前日看到运维在工作群中发布对发布项目进行 fastjson 的低版本拦截,缘由是发现了一个高危漏洞,提醒我们尽快升级版本。但运维并未表明是哪个漏洞,我便只好自己探索了一下。参考了一下两篇博主的文章,稍作整理。有兴趣的同学可以深入了解下。
Fastjson 1.2.24反序列化漏洞分析www.freebuf.com那么这个攻击,目前来看,需要被攻击的服务器使用了fastjson的低版本库,并且开启Feature.SupportNonPublicField否则不支持私有属性的传入。
在fastjson版本低于1.2.51会存在这个问题,fastjson允许我们在json字符串中通过“@type” 来指定序列化的对象。因此,根据这个我们来跟踪代码。
在parseObject方法往下断点调试。
会看到方法中调用了parseObject这个方法,继续往下。
T
在这个过程中,会根据type来判断对象,并通过调用deserializer.deserialize(this, clazz, fieldName)方法进行反序列化。
在往下代码会进行一个创建对象实例的动作,然后代码进入到字段属性的匹配阶段,会根据对象的属性和json的字段进行一个匹配。
匹配字段会调用 parseField(parser, key, object, type, fieldValues)这个方法,这个方法也是触发漏洞的关键方法,在最后有一个setValue(object,value)的方法。
在setValue中,可以看到有个代理方法会去触发对象的get方法,这样getOutputProperties()方法就会被调用。在_bytecodes中构造恶意代码就会被执行。
整个调用链路如下:
到这流程基本就结束了, com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl这个类的getOutputProperties()方法我就不具体展开了,有兴趣的同学再自行跟踪一下。通过getTransletInstance()可以执行_bytecodes中的攻击命令。
那么这个攻击,目前来看,需要被攻击的服务器使用了fastjson的低版本库,并且开启Feature.SupportNonPublicField,否则不支持私有属性的传入,存在局限性。
我这里摘录了参考博文中的一段方式,如下,链接在文章最上方。
Fastjson 1.2.24反序列化漏洞分析:
至此,其实整个流程已经走完了,但是还有一点令我们非常难受,就是我们的demo中,在接收JSON的时候设置了Feature.SupportNonPublicField。默认情况下fastjson只会反序列化public的方法和属性,而我们构造的PoC中有private的成员变量_bytecodes和_name,为了给这些变量赋值,则必须要假设服务端开启了SupportNonPublicField功能。
而现实情况下,大部分都是parse(json)和parseObject(json)一把梭,使用这个功能的情况不是很多,这样一来就导致我们的PoC没有了良好的通用性,那么有没有解决方案呢?答案当然是有的,那就是不使用TemplatesImpl,换一种RCE的触发方式即可。在网上经过一番搜索,发现了一些可以利用的方法
主要是利用JNDI+RMI方法,这个可以参考之前的spring-tx.jar的反序列化问题,当时就是采用这种方式来触发的。但是调用链不太好找, 这个PPT中给出了多个利用链,这里的调用链后续再进行分析,这里暂且不做验证。
这样一来,只要是开发同学在编写代码时,直接反序列化了用户传入的JSON,就有可能造成RCE,而攻击者也无需关心SupportNonPublicField是否开启了,危害提高了许多。
有兴趣的同学可以再深入研究一下。