by Alex Drozdov, Wallarm Research

XXE或XML外部实体是2017 OWASP Top10漏洞列表中的新问题。这是基于来自安全问题数据库的直接数据证据而引入的唯一的一个新问题。XML通常用于从电影到Docker容器的各种元数据,是REST、WSDL、SOAP、WEB-RPC等API协议的基础,而且,单个应用程序可能包含几个链接的XML解释器,用于处理来自不同应用程序层的数据。这种通过XML解释器在应用程序堆栈的不同位置注入外部实体的潜在能力使得XXE非常危险。

许多Web应用程序防火墙能够保护Web服务器免受XXE攻击。

Wallarm CEO,Ivan Novikov 在article in Security Boulevard上发表的一篇文章中写道:

实际上,XXE并不是一个BUG,而是任何XML解析器的一个显而易见的特点。是的,XML数据格式允许您在XML文档中包含任何外部文本文件的内容。

一段含有恶意代码的XML文档示例:

image.png

这里的$attack;指的是前面写的实体链接, 链接中指向的文件内容会在文档主体中替换掉它。

上述文件分为3个重要部分:

1.可选标头<?xml?>用于定义文档的基本特征,例如版本和编码。

2.XML文档模式的可选声明—<!DOCTYPE>,此声明可用于设置外部链接。

3.文档主体。它有一个层次结构,由<! DOCTYPE>定义根部的指定标签。

正确配置的XML解释器要么不接受带有XML链接的文档进行处理,要么验证链接及其来源,如果缺少验证,可以通过链接加载任意文件并集成到文档主体中,如上面的示例所示。

在本文中,我们将根据它们处理XML验证的方式来研究两种类型的WAF:

1.预处理的。使用自己的解析器对XML文档进行预处理的WAF。

2.基于正则表达式的。仅搜索数据中的特定子字符串或符合正则表达式的WAF。

不幸的是,这两种类别的WAF都可以被Bypass。

下面我们展示几种黑客能够绕过WAF并且可以进行XXE的方法。

方法1:文档中额外的空格符

由于XXE通常位于XML文档的开头,一个惰性匹配的WAF会忽略掉整个文档,并只会处理其开头部分。然而,XML格式允许在格式化标记属性时,使用任意数量的空格。因此攻击者可以在<?xml?> 或者 <!DOCTYPE>中插入额外的空格符来Bypass这类WAF。

image.png

 

方法2:无效的数据格式

为了绕过攻击者可能会发送特殊格式的XML文档,这样WAF就会认为他们是无效的。

链接到未知实体

会进行预处理的WAF的设置通常会阻止从链接中读取文件的内容。这种策略通常是有意义的,否则WAF本身也可能成为攻击的目标。问题是外部资源链接不但可以存在于文档的第三部分(文档主体),而且可以存在于声明中— <! DOCTYPE>。这意味着没有读取文件内容的WAF将不会读取文档中存在的实体声明。反过来,指向未知实体的链接将阻止XML解析器导致错误。

Example:

image.png

幸运的是,防止这种绕过非常简单 – 只需命令WAF中的XML解析器在遇到未知实体后不要关闭。

 

方法3:罕见编码

除了前面提到的XML文档的三个部分之外,还有第四部分位于它们之上,它还控制文档的编码(例如<?xml?>) — 文档的第一个字节带有可选的BOM(字节顺序标记)。

More information: https://www.w3.org/TR/xml/#sec-guessing

XML文档不仅可以用UTF-8编码,还可以用UTF-16(两种变体 – BE和LE),UTF-32(四种变体 – BE,LE,2143,3412)和EBCDIC编码。

在这种编码的帮助下,使用正则表达式很容易绕过WAF,因为在这种类型的WAF中,正则表达式通常仅配置为单字符集。

罕见编码也可用于绕过会预处理的WAF,因为它们并不总是能够处理上面列出的所有编码。例如,libxml2解析器仅支持一种类型的UTF-32 – UTF-32BE,特别是没有BOM。

 

方法4:在一个文档中进行两种类型的编码

在上一节中,我们演示了文档的编码通常由其第一个字节指定。但是当<?xml?>标签包含与文档开头第一个字节不同的编码属性时会发生什么?在这种情况下,一些解析器会更改编码,以便文档的开头具有同一字符集,其余部分采用另一种编码。也就是说,不同的解析器可以在不同的时间切换编码。Java解析器(javax.xml.parsers)在<?xml?>结束后严格更改字符集,而libxml2解析器会在”encoding”属性的值执行之后或者更迟— 在<?xml?>处理完成前后切换编码。

会预处理的WAF只有在根本不处理这些文档时,才能可靠地保护这些文档不受攻击。我们还必须要记住有一些同义编码,例如UTF-32BE 和 UCS-4BE。此外,有些编码虽然不同,但从编码文档的初始部分<?xml?>的角度来看是兼容的。例如,一个看似是UTF-8编码的文档可能包含字符串<?xml version="1.0" encoding=”windows-1251”?>

下面是一些例子。为了简洁起见,我们不会将XXE放在文档中。

libxml2解析器将文档视为有效的,然而javax.xml.parsers中的JAVA引擎认为它是无效的。

image.png

反之亦然,javax.xml.parser中的JAVA引擎认为该文档是有效的,但在libxml2解析器中是它无效的:

image.png

libxml2的文档,编码由utf-16le改为位于标签中间的utf-16be:

image.png

libxml2的文档,编码从utf-8改为ebcdic-us:

image.png

 

后记

如你所见,有很多Bypass方法来绕过这些没有受到较好保护的文档。防止XXE的最佳方法是配置我们的应用程序本身以安全的方式初始化XML解析器。主要有两种不同的选项应该禁用:

我们将继续研究XXE WAF bypasses,并期望尽快发布。敬请关注。

源链接

Hacking more

...