接下來的主題跟 Requests Smuggling Attack (請求走私攻擊) [1] 有關,先花兩天介紹一下這種漏洞的底層原理,以及當中比較有名的一些研究吧!
它們是兩個不同的 HTTP Headers:
Content-Length: 是用來告訴 HTTP Server 這個請求接下來要 append 的內容有多大的
Transfer-Encoding: 用來告訴 HTTP Server 內文傳輸的方法是什麼(像是壓縮/分塊),常用有 chunked、gzip、deflate、compress,其中後三者強調的都是壓縮方法、chunked 則是分塊傳輸
一個由 Client Side 送出的標準 HTTP chunked 包會長這個樣子:
POST / HTTP/1.1
Host: vuln.whale-tw.com
User-Agent: curl/9.1.0
Accept: */*
Transfer-Encoding: chunked
Content-Type: text/plain
5
Hello
8
, World!
0
每次在內容的結構都是:
<接下來送出的資料大小>
<資料>
...
0 # 代表結束
分段將內容送給 Server Side。
終歸來說,畢竟 Headers 都是由 Client Side 送出,所以伺服器端要不要接受是看採用的 Server Config/設定等去決定的。
然而,現代有許多 Web Services 以 Load Balancing/Caching 等目的都會採取前後端分離的措施,那當前後端針對這兩個 Headers 信任產生不一致時就會發生漏洞:
這是當前端 Server 信任 Content-Length Header(但比較不信任 Transfer-Encoding 而後端 Server 信任 Transfer-Encoding Header(同樣地,比較不信任 Content-Length Header) 時的攻擊手法:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLED
特別注意到一個像這樣的請求,在前端 Server 看到 Content-Length 大小後會嘗試將接下來的 13 Bytes 全送給後端 Server (注意 HTTP 封包的換行是 2 bytes 的 \r\n)。
可是後端 Server 比起 Content-Length 更優先處理了 Transfer-Encoding Header,導致它在讀取到 0 後就自動把當前請求截斷,最後導致它要嘗試讀取下一個使用者的請求時會先從前端 Server 取到 SMUGGLED\r\n 這幾 bytes 的資料。
總地來說,就是攻擊者可以汙染下一個使用者的請求。
這次反過來,前端吃 Transfer-Encoding 而後端則是 Content-Length 擁護者。
聰明的讀者應該可以猜到接下來發生了什麼事情!
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 3
Transfer-Encoding: chunked
8
SMUGGLED
0
注意到這樣的請求在前端解析時會先把封包切成 chunked 的兩段 data SMUGGLED 和 0 (結尾 NULL)
可是後端在看到 Content-Length 為 3 以後,就會將這次請求視為 "收到 8\r\n" 後停止。
跟剛剛一樣,在這樣的例子中,攻擊者可以去破壞下一個使用者傳入的請求。
前面的兩個範例就是 Requests Smuggling Attack 最基本的形式!但它們光是玩轉於這兩個 Headers 間就不只如此了。
在有些情境中,是由前端 Server 拒絕並擋下了向後端發起的 /admin 等敏感路由之請求,那 Requests Smuggling Attack 就可以透過分塊/請求大小接收的不一致完成驗證繞過!
此外,有時也可以透過過大的 Content-Length 大小來讀取下一個使用者傳入的 HTTP 請求(E.g. 送出的 Data 是網站 Search 參數,而網站會顯示查詢關鍵字),甚至把一個只能攻擊自己的 Self-XSS 轉成可以無差別攻擊其他使用者的 XSS 呢!
關於這些利用以及偵測,更多可以去 Port Swigger [1] 上找到相關例子就先不贅述了!
另外還有 TE/TE 以及 CL/0 等解析上的攻擊呢,這些都值得閱讀!