XXE或XML外部实体是2017年OWASP Top 10漏洞列表中的新问题。这是基于来自安全问题数据库的直接数据证据而引入的唯一一个新问题。XML通常用于从movies到Docker容器的所有内容的元数据,并且是API协议(如REST、WSDL、SOAP、Web-RPC和其他协议)的基础,而且,一个应用程序可能包含多个链接的XML解释器,这些解释器处理来自不同应用程序层的数据。这种通过XML解释器在应用程序堆栈中的不同位置注入外部实体的潜在隐患使XXE变得很危险。
许多Web应用程序防火墙能够保护Web服务器免受XXE攻击。
在Wallarm CEO, Ivan Novikov的文章Security Boulevard中这样写道:
实际上,XXE不是一个bug,而是XML解析器的well-documented特性。XML数据格式允许您在XML文档中包含任何外部文本文件的内容。
包含攻击代码的XML文档示例:
这里的文本$attack;
指的是前面注册的实体的链接。链接中指定的文件内容将其替换为文档正文中的内容。
上述文档分为三个重要部分:
1.可选标头,<?xml?>
用于定义基本文档特征,例如版本和编码。
2.XML文档模式的可选声明——<!DOCTYPE>
。此声明可用于设置外部链接。
3.文档正文。它有一个层次结构,其根部是指定的标签<! DOCTYPE>
正确配置的XML解释器要么不接受包含XML链接的文档进行处理,要么将验证链接及其来源,如果缺少验证,则可以通过链接加载任意文件并将其集成到文档体中,如上面的示例所示。
在本文中,我们将根据WAF处理XML验证的方式来研究两种类型的WAF:
1.成熟的waf——使用自己的解析器预处理XML文档的WAFs。
2.基于正则表达式。仅搜索数据中的特定子字符串或正则表达式的WAFS。
不幸的是,这两种类型的WAF都可以绕过。
下面我们展示了攻击者可以用来骗过WAF并获得XXE的几种方法。
由于XXE通常在XML文档的开头,所以比较省事儿的WAF可以避免处理整个文档,而只解析它的开头。但是,XML格式允许在格式化标记属性时使用任意数量的空格,因此攻击者可以在<?xml?>
或<!DOCTYPE>
中插入额外的空格,从而绕过此类WAF。
为了绕过WAF,攻击者可能会发送特殊格式的XML文档,以便WAF认为它们无效。
比较成熟的WAF设置通常不会读取链接文件的内容。这种策略通常是有意义的,否则,WAF本身也可能成为攻击的目标。问题是,外部资源的链接不仅可以存在于文档的第三部分(正文),还可以存在于声明<! DOCTYPE>中 。
这意味着未读取文件内容的WAF将不会读取文档中实体的声明。而指向未知实体的链接又会阻止XML解析器导致错误。
幸运的是,防止这样的绕过非常简单——命令WAF中的XML解析器在遇到未知实体后不要关闭。
除了前面提到的xml文档的三个部分之外,还有位于它们之上的第四个部分,它们控制文档的编码(例如<?xml?>)——文档的第一个字节带有可选的BOM(字节顺序标记)。
更多信息: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。
在上一节中,我们演示了文档的编码通常由其第一个字节指定。但是当包含编码属性的<?xml?>标记引用文档开头的不同字符集时会发生什么?在这种情况下,一些解析器更改编码,使文件的开头有一组字符,其余的是另一组编码。。也就是说,不同的解析器可能在不同的时间转换编码。Java解析器(javax.xml.parsers)在<?xml?>结束后严格地更改字符集,而libxml2解析器可以在执行“编码”属性的值之后或在处理<?xml?>之前或之后切换编码。
只有在根本不处理这些文件时,比较成熟的WAF才能可靠地防止这些文件中的攻击。我们还必须记住,有许多同义词编码,例如UTF-32BE和UCS-4BE。此外,有些编码可能不同,但从编码文档初始部分 <?xml?>
的角度来看,它们是兼容的。例如,看似UTF-8的文档可能包含字符串<?xml version=”1.0” encoding=”windows-1251”?>
。
这里有一些例子。为了简明扼要,我们不把XXE放在文档里。
libxml2解析器将文档视为有效,但是,javax.xml.parsers set中的Java引擎认为它无效:
反之亦然,文档对于javax.xml.parser是有效的,但对于libxml2解析器是无效的:
libxml2的文档,在标记中间将编码从utf-16le更改为utf-16be:
libxml2的文档,编码从utf-8改为ebcdic-us:
正如你所看到的,有许多绕过方法。防止XXE的最好方法是配置应用程序本身,以安全的方式初始化XML解析器。为此,应该禁用两个选项:
外部实体
外部DTD架构
我们将继续我们的研究XXE WAF绕过。敬请关注。
翻译:https://lab.wallarm.com/xxe-that-can-bypass-waf-protection-98f679452ce0