Jackson系列二——CVE-2017-7525(基于TemplatesImpl利用链)
/本次Jackson反序列化漏洞对于Jackson来说是首例,因此针对这些版本范围的漏洞利用类有很多,这章节只用TemplatesImpl这条在Fastjson也盛行的利用类进行演示,其他利用链在后面的文章中会补充分析。
0x01 影响版本
Jackson 2.6系列 < 2.6.7.1
Jackson 2.7系列 < 2.7.9.1
Jackson 2.8系列 < 2.8.8.1
0x02 限制
JDK使用1.7版本的,不能使用1.8版本,具体原因后面章节会分析到。
注意,小版本搞的1.7版本的也会有些不能成功利用,具体要自己测试才知道哪些版本是可用的。
我本地用的JDK版本为1.7.0_21,之前用的1.7.0_80没成功。
0x03 复现利用
我本地用的jar包:jackson-annotations-2.7.9,jackson-core-2.7.9,jackson-databind-2.7.9,commons-codec-1.12,commons-io-2.5,spring-core-4.3.13.RELEASE。
PoC.java,这里选择以开启DefaultTyping的方式进行反序列化:
1 | public class PoC { |
Mi1k7ea.java,要进行反序列化的类:
1 | package com.mi1k7ea; |
Exploit.java,恶意类,至于为何要继承AbstractTranslet类可以参考《Fastjson系列二——1.2.22-1.2.24反序列化漏洞》中的调试分析:
1 | public class Exploit extends AbstractTranslet { |
运行即可成功触发弹计算器:
Exploit类中换成其他命令的话运行结果保存在result.txt中:
这里我们看下PoC:
1 | { |
这里解释下设置的几个JSON键值对:
- transletBytecodes——Base64编码的Exploit恶意类的字节流,编码原因可参考之前的《Fastjson系列二——1.2.22-1.2.24反序列化漏洞》;
- transletName——TemplatesImpl类对象的_name属性值;
- outputProperties——为的是能够成功调用setOutputProperties()函数,该函数是outputProperties属性的setter方法,在Jackson反序列化时会被自动调用;
0x04 调试分析
在mi1k7ea = mapper.readValue(jsonInput, Mi1k7ea.class);
中打下断点;同时,我们由之前Fastjson中的分析也知道,TemplatesImpl利用链的其中一步是调用了getOutputProperties()函数,我们也在这里打下断点。
下面开始调试,其中反序列化的处理过程和之前调试的一样,我们直接跟到关键的地方看看就好。
我们知道在BeanDeserializer.vanillaDeserialize()函数中会先新建Bean实例,然后调用deserializeAndSet()函数来解析属性值并设置到该Bean中;而在deserializeAndSet()函数中,会反射调用属性的setter方法来设置属性值。
前两个属性transletBytecodes和transletName都是通过反射机制调用setter方法设置的,但是outputProperties属性在deserializeAndSet()函数中是通过反射机制调用它的getter方法,这就是该利用链能被成功触发的原因,虽然Jackson的反序列化机制只是调用setter方法,但是是调用SetterlessProperty.deserializeAndSet()来解析outputProperties属性而前面两个属性是调用的MethodProperty.deserializeAndSet()解析的,其中SetterlessProperty.deserializeAndSet()函数中是调用属性的getter方法而非setter方法:
再往下就是反射调用到了getOutputProperties():
再后面就和Fastjson中分析的一样了,这里不再赘述。
利用链:getOutputProperties()->newTransformer()->getTransletInstance()->defineTransletClasses()->恶意类构造函数
到getOutputProperties()时的函数调用栈如下:
1 | getOutputProperties:431, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax) |
0x05 为什么要设置transletName属性值
PoC不写该属性值的话会报错,我们调试分析下原因。
跟踪到getOutputProperties()->newTransformer()->getTransletInstance()这条调用链时发现,问题出在TemplatesImpl.getTransletInstance()函数中:
由于此处_name为null,导致程序提前return了,并未进入后面生成Java了以及新建该Java类实例的代码中,从而也无法成功触发漏洞。
由前面调试分析可知,transletBytecodes和transletName属性值都是通过调用MethodProperty.deserializeAndSet()函数来反射调用其setter方法来设置的。
这里我们重新transletName属性带上,再次调试,跟进设置transletName属性值时的MethodProperty.deserializeAndSet()函数中,发现其调用的setter方法就是TemplatesImpl.setTransletName()函数:
因此这个属性值是必须的,不能为null。
0x06 高版本JDK不能触发的原因——_tfactory
在大版本下,JDK1.7和1.8中,com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl类是有所不同的。
当然,在小版本较高的1.7和某些1.8的还是能够成功触发的,具体的可自行测试。
在我本地的JDK 1.8.0_73 版本中,看到在TemplatesImpl.getTransletInstance()方法中调用了defineTransletClasses()函数来定义Java类,跟进看看:
区别在于新建TransletClassLoader类实例的代码,其中调用了_factory
属性,但是该属性值我们没有在PoC中设置,默认为null,于是就会抛出异常了。
那么如何设置这个_factory
属性呢?我们在PoC中随便填入如'_factory':{},
,会看到如下错误信息:
1 | com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "_factory" (class com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl), not marked as ignorable (5 known properties: "uriresolver", "transletBytecodes", "outputProperties", "transletName", "stylesheetDOM"]) |
可以看到,这个错误是Jackson.databind报的,说的是TemplatesImpl类已知的只有5个配置项,即”uriresolver”, “transletBytecodes”, “outputProperties”, “transletName”, “stylesheetDOM”。
在里面没有看到tfactory相关字样,也就是说,Jackson压根就不支持我们在序列化的TemplatesImpl类的内容上添加并解析_tfactory属性。
0x07 补丁分析
这里将jackson-databind-2.7.9换成jackson-databind-2.7.9.1。
尝试运行会报错如下,显示因为某些安全原因禁止了该类的加载:
1 | com.fasterxml.jackson.databind.JsonMappingException: Illegal type (com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl) to deserialize: prevented for security reasons |
调试分析,在调用BeanDeserializerFactory.createBeanDeserializer()函数创建Bean反序列化器的时候,其中会调用checkIllegalTypes()函数提取当前类名,然后使用黑名单进行过滤:
注意:实际调试的时候回调用两次BeanDeserializerFactory.createBeanDeserializer()->checkIllegalTypes(),第一次由于是Mi1k7ea类,因此不会被过滤;第二次是TemplatesImpl类,由于其在黑名单中,因此被过滤了。
在jackson-databind-2.7.9.1-sources.jar!/com/fasterxml/jackson/databind/deser/BeanDeserializerFactory.java中,存在默认的黑名单DEFAULT_NO_DESER_CLASS_NAMES,将TemplatesImpl类以及早期其他常用反序列化利用类都过滤了:
1 | static { |
OK,17年经典的Jackson反序列化漏洞就说到这,利用链是和Fastjson一样的com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl,两者的利用链很多都是可以共用的,但是会有些细微的区别。下一篇文章看看Jackson其他反序列化利用链及CVE漏洞。