愛伊米

實用的 HTTP 標頭走私:透過反向代理攻擊 AWS

現代 Web 應用程式通常依賴於多臺伺服器鏈,它們相互轉發HTTP請求。這種轉發建立的攻擊面越來越受到關注,包括最近流行的快取攻擊和請求走私漏洞。最近的請求走私研究,已經開發出新的方法來隱藏鏈中某些伺服器的 HTTP 請求標頭,同時讓其他伺服器看到它們——這種技術被稱為“標頭走私”。本文提出了一種新的識別標題走私的技術,並演示了標題走私如何導致快取攻擊、IP限制繞過和請求走私。

Web 應用程式使用的 HTTP 伺服器鏈通常可以建模為由兩個元件組成:

◼直接處理來自使用者請求的“前端”伺服器,這些伺服器通常會處理快取和載荷平衡,或充當 Web 應用程式防火牆 (WAF);

◼前端伺服器將請求轉發到的“後端”伺服器,這是應用程式的伺服器端程式碼執行的地方;

實用的 HTTP 標頭走私:透過反向代理攻擊 AWS

上述模型僅是一個簡化,可能有多個前後端伺服器,現實中可能有多個前端和後端伺服器,而前端和後端伺服器本身通常是多個伺服器鏈。

後端伺服器通常依賴前端伺服器在 HTTP 請求標頭中提供的準確資訊,例如“X-Forwarded-For”標頭中的客戶端 IP 地址或“Content-Length”標頭中的請求正文長度。為了準確地提供這些資訊,前端伺服器必須過濾掉客戶端提供的這些標頭的值,這些值是不可信的。

使用標頭走私,可以繞過此過濾並將資訊傳送到它視為受信任的後端伺服器。我將展示這如何導致繞過 AWS API Gateway 中的 IP 限制,以及一個易於利用的快取攻擊問題。然後,我將討論如何調整用於發現這些漏洞的方法,以基於多個“Content-Length”標頭(CL)安全地檢測請求走私。

本研究開發的用於識別標頭走私漏洞的方法決定了是否可以對標頭應用“突變”,使其能夠在不被前端伺服器識別或處理的情況下潛入後端伺服器。突變只是對標頭的混淆。以下示例是“Content-Length”標頭的變體版本:

這個方法依賴於這樣一個事實:當傳送一個帶有無效的“Content-Length”標頭的請求時,大多數web伺服器都會返回一個漏洞:

請求

響應

該方法還依賴於在“Content-Length”標頭的常規形式和變異形式傳送有效值和無效值時對響應的比較。我們首先將常規“Content-Length”標頭中的有效和無效值傳送到目標:

請求

響應

請求

響應

由於在“Content-Length”標頭中包含垃圾值會導致響應不同,我們可以推斷鏈中至少有一個伺服器正在解析這個標頭。

此伺服器鏈允許透過在標頭名稱中的空格後附加字元將標頭走私到後端。因此,當我們將請求中的“Content-Length”替換為“Content-Length abcd”並再次傳送請求時,我們得到以下結果:

請求

響應

請求

響應

在比較來自常規和變異的“Content-Length”標頭的響應時,有三件重要的事情需要注意。第一個是每個標頭中的無效值與有效值引起的響應不同。這表明鏈中至少有一個伺服器將這些標頭中的每一個解析為“Content-Length”標頭。

其次,當每個標標頭檔案中包含一個有效值時,會返回相同的響應:

請求

響應

請求

響應

這表明變異標頭的存在並沒有阻止任一伺服器正常解析請求,這種檢查對於確保突變不會使請求完全無效非常重要。

最後要注意的重要一點是,與常規標頭相比,每個標頭中的無效值會導致變異標頭中的不同響應:

請求

響應

請求

響應

這表明,這些漏洞很可能源自鏈中的不同伺服器。換句話說,前端伺服器不會像解析常規的“Content-Length” 標頭一樣解析變體後的“Content-Length”標頭,而後端伺服器由於存在標頭走私,則可以。

示例

繞過限制

◼AWS API 閘道器 IP 限制

在跨漏洞賞金計劃掃描時,我注意到使用 AWS API Gateway 建立的 API 允許透過在空格後將字元附加到標頭名稱來進行標頭走私,例如,將“X-My-Header: test”變異為“X-My-Header abcd: test”。我還注意到前端伺服器正在重寫“X-Forwarded-For”標頭。

API Gateway 允許你使用以下資源策略來限制 API 訪問某些 IP 地址:

實用的 HTTP 標頭走私:透過反向代理攻擊 AWS

此策略將訪問限制為僅接受來自 IP 地址 1。2。3。4和私有範圍 10。0。0。0/8 的請求。來自其他 IP 地址的請求遇到漏洞:

請求

響應

不出所料,簡單地向請求新增“X-Forwarded-For”標頭與 AWS 的安全控制不匹配:

要求

回覆

然而,當應用一個允許標頭資訊走私到這個標頭資訊的突變時,就會授予訪問許可權:

請求

響應

這允許繞過 IP 限制,但在實際情況下可能很難實現。來自私有範圍的地址是顯而易見的猜測,但如果這些不被允許,那麼就很難猜測一個已被授予訪問許可權的IP地址。

請求

響應

事實證明,在請求中新增標頭“x - forward - for abcd: z”可以在API閘道器中繞過AWS資源策略的IP限制。

AWS Cognito速率限制

在滲透測試期間,我在 AWS Cognito 中發現了一個類似但非常小的漏洞。Cognito 是一個身份驗證提供程式,你可以將其整合到你的應用程式中以幫助處理身份驗證。

在短時間內向“ConfirmForgotPassword”或“ForgotPassword”目標發出五次請求後,我的IP地址被暫時封鎖。但是,在請求中新增“X-Forwarded-For:[0x0b]z”允許再發出 5 個請求。不幸的是,不可能在此標頭中迴圈不同的值或有效的 IP 地址繼續獲得五次嘗試,這意味著此漏洞的影響很小。然而,它仍然是一個很好的例子,說明如何使用頭部走私來繞過速率限制。

快取攻擊

在我向AWS報告後,他們立即修復了IP限制繞過。當重新測試時,我注意到我仍然可以使用相同的變體將標頭走私到後端伺服器,這讓我想知道是否還有其他有趣的標頭值得嘗試。

API 閘道器可能在內部使用了一些很有趣的標頭,但我無法識別其中的任何一個。真正引人注目的是”Host”標頭,如果我試圖將這個標頭偷偷傳遞到後端伺服器會發生什麼。

我使用 API Gateway 設定了兩個 API:一個“受害者”API 和一個“攻擊者”API:

請求

響應

請求

響應

實用的 HTTP 標頭走私:透過反向代理攻擊 AWS

當在常規“Host”標頭旁邊包含一個變異的“Host”標頭時,就會出現有趣的行為:

請求

響應

API 閘道器正在從變異的“Host”標頭中指定的 API 返回響應。這與大多數 Web 伺服器的行為形成對比,後者不會將變異的“Host”標頭視為“Host”標頭,而是從常規“Host”標頭中獲取主機。當這樣的伺服器充當 API 閘道器前的快取時,這會變得很有趣,因為它會快取上述請求的結果,就好像它是對“victim。i。long。lat”的請求一樣,即使響應是來自“attacker。i。long。lat”API。

實用的 HTTP 標頭走私:透過反向代理攻擊 AWS

為了演示這一點,我使用“AllViewer”請求策略在 API 閘道器前面設定了 CloudFront,這會導致所有標頭都被轉發。傳送上述請求,然後請求“https://victim。i。long。lat/a”,顯示攻擊者API的響應已經儲存在受害者API的快取中:

請求

響應

請求

響應

這種快取攻擊很容易被利用,因為攻擊者可以設定自己的API並返回任意路徑的任意內容。這允許他們完全覆蓋受害者快取中的任何條目,有效地允許他們完全控制受害者API的內容。

請求走私

在 Black Hat USA 2020 上,Amit Klein 提出了一個基於 2 個“Content-Length”標頭的請求走私(“CL。CL”請求走私)。當使用在同一連線中傳送的以下請求將 Squid 用作 Abyss Web 伺服器前的反向代理時,可能會觸發該漏洞:

實用的 HTTP 標頭走私:透過反向代理攻擊 AWS

第一個請求以綠色顯示,包含兩個“Content-Length”標頭,一個是變異的,另一個是未變異的。Squid 只會解析未變異的標標頭檔案,並將第一個請求的主體長度取為 33 位元組,以藍色顯示。Squid 然後將第二個請求作為紅色顯示的請求——對“/doesntexist”的“GET”請求。

另一方面,Abyss 將解析變異和未變異的“Content-Length”標頭,並從變異標頭中獲取 0 位元組的值。因此,它認為第二個請求是以藍色開頭的請求——對“/a。html”的“GET”請求。

實用的 HTTP 標頭走私:透過反向代理攻擊 AWS

這樣做的總結果是,Abyss 以“/a。html”的內容響應,而 Squid 將此響應快取到路徑“/doesntexist”,從而導致快取攻擊。

Klein 的研究特別有趣,因為它表明 CL。CL 請求走私存在於現代系統中,他提出了一種使用超時安全檢測請求走私的簡單方法,該方法基於“內容長度”和“傳輸編碼”標頭(“CL。TE”和“TE。CL”請求走私)。此方法試圖使後端期待比前端轉發更多的內容,從而觸發後端超時。透過首先掃描 CL。TE 請求走私,可以在測試易受攻擊的系統時將影響其他使用者請求的風險降至最低。

對 CL。CL 請求走私執行相同操作的嘗試可能類似於以下情況:

對於前端讀取未變異的“Content-Length”標頭而後端讀取變異版本的易受攻擊的系統,這通常會導致超時。儘管在 Squid 和 Abyss 設定的情況下,不會導致超時,因為 Abyss 不會在回覆“POST”請求之前等待正文傳送。

當這個請求被髮送到一個易受攻擊的系統時,危險就來了,其中前端讀取變異的標頭,後端讀取未變異的版本。前端伺服器將轉發“z”正文,後端伺服器將其視為下一個請求的開始。然後套接字就被攻擊了,並且由於後端伺服器將請求方法視為例如“zGET”,因此另一個使用者的請求失敗的可能性很高。

如果我們不知道前端伺服器將解析哪個“Content-Length”標頭,我們既有可能會在易受攻擊的系統中導致超時,也有可能發生套接字攻擊,可能導致另一個使用者的請求失敗。

可以稍微修改用於檢測標頭走私的方法,以建立安全的 CL。CL 請求走私檢測方法。以下示例展示瞭如何使用這種修改後的方法來檢測 Squid 和 Abyss 中的 Klein 漏洞。

首先,使用正在測試的“Content-Length”標頭對向目標系統傳送 “baseline” 請求:

請求

響應

下一步是再發送兩次相同的請求,在每個“Content-Length”標頭中都有一個垃圾值:

請求

實用的 HTTP 標頭走私:透過反向代理攻擊 AWS

響應

請求

響應

比較 3 個響應,我們注意到:

包含垃圾值的請求都觸發了與“baseline”響應不同的響應,這表明至少有 1 個伺服器正在解析每個標頭的值。

對包含垃圾值的請求的響應是不同的。這表明漏洞來自不同的伺服器,因此鏈中的不同伺服器正在解析不同版本的“Content-Length”標頭。

這些情況表明潛在的 CL。CL 請求走私,當調查超出這一點時,重要的是要知道前端伺服器正在解析哪個標頭,以最大限度地減少使套接字攻擊和影響其他使用者的機會。

這可以透過傳送帶有單個未變異的“Content-Length”標頭的請求並觀察產生的漏洞來實現:

請求

響應

由於前端伺服器幾乎肯定會解析此請求中的“Content-Length”標頭,因此產生的漏洞很可能是由前端伺服器生成的。透過將此漏洞與該過程中早期生成的漏洞進行比較,我們看到它與在同一請求中傳送標頭“Content-Length: z”和“Content-Length abcd: 0”時生成的漏洞相同。因此,前端伺服器解析未變異的“Content-Length”標頭,後端伺服器解析變異的1。

這些請求僅表明存在潛在的請求走私漏洞,儘管還遠未確定。例如,許多伺服器會處理兩種形式的“Content-Length”標頭,但是當它們具有不同的值時就會出現漏洞,從而無法進行請求走私。

緩解措施

防禦這些型別的漏洞可能有些複雜,因為它們依賴於 Web 伺服器之間實現的差異,而不是 1 個 Web 伺服器中的特定漏洞。

前端伺服器應避免轉發格式奇怪的標頭,這是 AWS 透過 API 閘道器採用的方法,包括編寫測試來驗證這種行為。這也阻止了 Cloudflare 在快取攻擊示例中使用,因為它們不會轉發名稱中帶有空格的任何標頭。

參考及來源:https://www。intruder。io/research/practical-http-header-smuggling