freeBuf
主站

分类

漏洞 工具 极客 Web安全 系统安全 网络安全 无线安全 设备/客户端安全 数据安全 安全管理 企业安全 工控安全

特色

头条 人物志 活动 视频 观点 招聘 报告 资讯 区块链安全 标准与合规 容器安全 公开课

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

渗透测试 | HTTP请求走私
2024-04-23 17:13:55

前言

在一次测试过程中扫描器扫出了这个漏洞,以前只知道一个大概,今天来具体的看一下该漏洞的原理,利用方式以及检测方式。

由于本人水平有限,文章中可能会出现一些错误,欢迎各位大佬指正,感激不尽。如果有什么好的想法也欢迎交流~~

漏洞原理

在复杂的网络环境下,不同的服务器对RFC标准实现的方式不同,程度不同。这样一来,对同一个HTTP请求,不同的服务器可能会产生不同的处理结果,这样就产生安全风险。

为了缓解服务器的压力,一般在服务器前面会用代理服务器进行缓存,因此就可能造成代理服务器与真实的服务器之间处理请求不同,导致非法的请求到达真实服务器。

如果在代理服务器上做权限控制,则还可能绕过权限限制。

实际就是绕过第一个服务器,让它以为发送的是一个请求,而真实的服务器认为是两个不同的请求。

一般来说,反向代理服务器与后端的源站服务器之间,会重用TCP链接。这也很容易理解,用户的分布范围是十分广泛,建立连接的时间也是不确定的,这样TCP链接就很难重用,而代理服务器与后端的源站服务器的IP地址是相对固定,不同用户的请求通过代理服务器与源站服务器建立链接,这两者之间的TCP链接进行重用,也就顺理成章了。

当我们向代理服务器发送一个比较模糊的HTTP请求时,由于两者服务器的实现方式不同,可能代理服务器认为这是一个HTTP请求,然后将其转发给了后端的源站服务器,但源站服务器经过解析处理后,只认为其中的一部分为正常请求,剩下的那一部分,就算是走私的请求,当该部分对正常用户的请求造成了影响之后,就实现了HTTP走私攻击。

1713862538_6627778a137804adf796c.png!small?1713862538760


RFC标准:Request For Comments

检测工具:https://github.com/anshumanpattnaik/http-request-smuggling

基础知识

漏洞的主要原因是在http1.x中引入了长连接keep-alive与pipline的概念。长连接允许多个请求复用同一个tcp连接,不必每个请求重新建立连接,大大节约了服务器资源,pipline使得http的请求不必等到响应之后在发起,而可以流式得发起请求,请求到达服务端后仍然通过排队的方式进行处理。正是这两个概念导致了我们今天要讲的问题,当然还有另外重要的一点就是,关于服务器在处理te(Transfer-Encoding)与cl(Content-Length)时存在的差异导致了这个问题。

Keep-Alive

HTTP/1.0 的持久连接机制是后来才引入的,通过 Connection: keep-alive 这个头部来实现,服务端和客户端都可以使用它告诉对方在发送完数据之后不需要断开 TCP 连接,以备后用。HTTP/1.1 则规定所有连接都必须是持久的,除非显式地在头部加上 Connection: close。所以实际上,HTTP/1.1 中 Connection 这个头部字段已经没有 keep-alive 这个取值了,但由于历史原因,很多 Web Server 和浏览器,还是保留着给 HTTP/1.1 长连接发送 Connection: keep-alive 的习惯。

Pipeline

客户端可以像流水线一样发送自己的HTTP请求,而不需要等待服务器的响应,服务器那边接收到请求后,需要遵循先入先出机制,将请求和响应严格对应起来,再将响应发送给客户端。现如今,浏览器默认是不启用Pipeline的,但是一般的服务器都提供了对Pipleline的支持。

Content-Length

表示传输内容的长度。告诉服务端传输内容的长度。

Transfer-Encoding

是一个 HTTP 头部字段,字面意思是「传输编码」。实际上,HTTP 协议中还有另外一个头部与编码有关:Content-Encoding(内容编码)。通过特殊的格式来表示一个http请求是否传输完成。

在长连接的情况下,如果两个服务端对传输的长度处理不同,可能导致一个服务端认为是一个完整的请求,另一个服务端任务是两个。这就是请求走私。

利用场景

上面说了关于请求走私的一些基础知识,请求走私主要就是由于前后端服务器对于数据包的处理方式不同造成的,造成这种问题主要是由Content-Length与Transfer-Encoding两个参数控制的,这两个参数简称为CL与TE。下面就结合portswigger来看看该漏洞的一些具体应用场景。

https://portswigger.net/web-security/request-smuggling#what-is-http-request-smuggling

场景1:CL-TE:前端服务器使用Content-Length消息头,后端服务器使用Transfer-Encoding消息头

场景2:TE-CL:前段服务器使用Transfer-Encoding消息头,后端服务器使用Content-Length消息头

场景3:TE-TE:前端服务器和后端服务器都支持Transfer-Encoding标头,但是可以通过对标头进行某种方式的混淆来诱导其中一台服务器不对其进行处理

场景4:CL-CL:在RFC7230中,规定当服务器收到的请求中包含两个Content-Length,而且两者的值不同时,需要返回400错误。有些服务器不会严格的实现该规范,假设中间的代理服务器和后端的源站服务器在收到类似的请求时,都不会返回400错误。 但是中间代理服务器按照第一个Content-Length的值对请求进行处理,而后端源站服务器按照第二个Content-Length的值进行处理。

场景5:CL不为0的的Get请求:前端代理服务器允许GET请求携带请求体;后端服务器不允许GET请求携带请求体,它会直接忽略掉GET请求中的Content-Length头,不进行处理。这就有可能导致请求走私。

1713862701_6627782d384a72f3830a5.png!small?1713862702397

场景一:CL-TE

前端服务器使用Content-Length消息头,后端服务器使用Transfer-Encoding消息头。

RFC2616规范

如果收到同时存在Content-Length和Transfer-Encoding这两个请求头的请求包时,在处理的时候必须忽略Content-Length。

chunked

设置了 Transfer-Encoding: chunked 后,请求主体按一系列块的形式发送,并将省略 Content-Length。在每个块的开头需要用十六进制数指明当前块的长度,数值后接 \r\n(占 2 字节),然后是块的内容,再接 \r\n 表示此块结束。最后用长度为 0 的块表示终止块。终止块后是一个 trailer,由 0 或多个实体头组成,可以用来存放对数据的数字签名等。

[chunk size][\r\n][chunk data][\r\n][chunk size][\r\n][chunk data][\r\n][chunk size = 0][\r\n][\r\n]

代码实例

POST / HTTP/1.1
Host: xxxx.com
Content-Length: 6
Transfer-Encoding: chunked

0

a

分析

前端服务器:判断数据包以Content-Length的值,Content-Length: 6,判断完整,传给后端

后端服务器:判断数据包以Transfer-Encoding,遇到0\r\n\r\n后,以为请求体结束,留下了一个字母a在下一次请求时,会附着在下个请求中

此时再有用户请求

GET / HTTP/1.1
Host: localhost

就会返回错误内容造成服务器解析异常

aGET / HTTP/1.1
Host: localhost

portswigger实验

实验地址:https://portswigger.net/web-security/request-smuggling/lab-basic-cl-te

添加下面的内容,连续发送两次数据包,第二次的数据包会出现下面的报错

1713862833_662778b136e7601303034.png!small?1713862833809

成功解决

1713862837_662778b5b95af3bfd595b.png!small?1713862838192

场景二:TE-CL

前段服务器使用Transfer-Encoding消息头,后端服务器使用Content-Length消息头

代码实例

POST / HTTP/1.1
Host: cccccc.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked

12
GPOST / HTTP/1.1

0

注意上边有两个换行,为了让Transfer-Encoding成功解析

分析

前端: 读取到0\r\n\r\n后,Transfer-Encoding认为是一个完整请求, 传给后端

后端:Content-Length: 4,判断到12\r\n,不在解析,后边的内容会留给下个请求

此时再有用户发出请求

GET / HTTP/1.1
Host: localhost

拼接预留内

# web安全
本文为 独立观点,未经允许不得转载,授权请联系FreeBuf客服小蜜蜂,微信:freebee2022
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录