题目1:平台搭建

你需要搭建一个名为 php_xxe 的本地 Web 环境,并演示如何利用 XXE(XML 外部实体注入)漏洞读取服务器上的文件。

1. 环境准备

你需要一个集成了 PHP 环境的 Web 服务器软件,推荐使用 phpStudyWampServer 或 XAMPP。这里以最常用的 phpStudy 为例。

2. 部署步骤

  1. 启动服务:打开 phpStudy,确保 Apache 和 MySQL 服务处于“开启”状态(通常显示为绿色)。
  2. 放置源码:
    • 找到 phpStudy 的网站根目录,通常是 WWW 文件夹(例如 C:\phpstudy_pro\WWW)。
    • 将你下载好的 php_xxe 文件夹(即你截图中显示的包含 index.html、doLogin.php 等文件的文件夹)复制粘贴到这个 WWW 目录下。
  3. 访问测试:
    • 打开浏览器。
    • 在地址栏输入: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开发者工具)来拦截登录请求。

  1. 打开 Burp Suite,开启代理拦截(Intercept is on)。
  2. 在浏览器登录页面随意输入用户名(如 admin)和密码(如 1234)。
  3. 点击绿色的 LOGIN 按钮。
  4. 此时 Burp Suite 会拦截到一个 POST 请求。

第二步:构造 Payload(攻击载荷)

在拦截到的数据包中,找到请求体(Request Body),你会看到原始的 XML 数据。你需要将其修改为包含恶意实体的代码。

(1)修改 XML 数据(构造 Payload)

你需要删除原本的 <user>...</user> 部分,替换成包含恶意定义的 XML 代码。

操作方法:

  1. 在 Burp Suite 的拦截界面中,选中第 14 行到最后一行的所有 XML 内容(即 <user> 标签及其内部内容)。
  2. 删除这些旧内容。
  3. 复制并粘贴以下代码进去(注意缩进和格式要保持整洁):
    <?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)发送请求
  1. 确认修改后的数据包看起来像这样(重点看下半部分):
    ![示意图]
    • 头部保持原样。
    • 底部变成了我们刚才写的带有 <!DOCTYPE 的代码。
  2. 点击 Burp Suite 右上角的 「Forward」(转发)按钮。

(3)查看结果
  1. 点击 Forward 后,浏览器页面会刷新或显示响应结果。
  2. 如果攻击成功:
    • 页面可能会报错,或者在原本显示“登录失败/用户名错误”的地方,直接打印出了 win.ini 文件的内容(通常是以 ; for 16-bit app support 开头的一大段文字)。
    • 这说明服务器已经把 win.ini 的内容读出来并返回给你了。

(4)截图保存

题目要求截图,你需要截取以下两个画面之一作为证据:

  1. Burp 中的修改画面:就像你现在发的这张图,但是下半部分已经改成了上面的恶意代码。
  2. 浏览器的回显画面:页面上显示出 win.ini 文件内容的瞬间。

题目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>:依然是在用户名处触发实体引用。

第三步:发送并查看结果

  1. 点击 Burp Suite 的 Forward 发送数据包。
  2. 观察浏览器返回的响应(Response)。
    • 如果成功:你会看到一大段文本,那是 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

  1. 查看响应:在浏览器的返回页面或者 Burp 的 Response 面板中,你看到的不再是乱码或空白,而是一串长长的 Base64 字符串(例如 PD9waHAgJGZsYWcgPSAiZmxhZ3t4eHh4fSI7ID8+)。
  2. 进行解码:
    • 复制这串 Base64 字符。
    • 使用在线工具(搜索“Base64 解码”)或者 HackBar 的解码功能进行解码。
  3. 得到结果:解码后,你就会看到 flag.php 的源代码,里面通常包含类似 flag{xxxxxx} 的答案。

总结

这一题的核心在于 编码绕过”。如果不加 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 攻击。
Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐