http走私攻击介绍
![http走私攻击([RoarCTF 2019]Easy Calc) - 图1](/uploads/projects/u390550@fftlfh/a6e77d8804117605ab60f81cbe8fda2a.png)
前端服务器(CDN)和后端服务器接收数据不同步,引起对客户端传入的数据理解不一致,从而导致漏洞的产生。
大多数HTTP请求走私漏洞的出现是因为HTTP规范提供了两种不同的方法来指定请求的结束为止:
Content-Length标头和Transfer-Encoding标头
同时使用两种不同的方法时,Content-Length的无效。当多个服务器时,对客户端传入的数据理解不一致时,就会出现有些服务器认为Content-Length的长度有效,有些Transfer-Encoding有效。
而一般情况下,反向代理服务器和后端源站服务器之间,会重用TCP链接(因为TCP会切割报文)。这样超出的长度就会拼接到下一次请求进行,从而导致HTTP请求走私漏洞。
HTTP协议解析漏洞 :WAF进行模式匹配的时候都是对HTTP协议变量进行匹配,攻击者构造异常的HTTP数据包导致不能正常提取变量,都不能进入到模式匹配阶段,自然而然就绕过了。
HTTP请求走私攻击的5种方式
1.CL不为0
所有不携带请求体的http请求都有可能收到此影响。这里用GET举例。
前端代理服务器允许GET请求携带请求体;后端服务器不允许GET请求携带请求体,它就会直接忽略掉GET请求中的Content-Length头,不进行处理。这里就有可能导致请求走私。
构造请求示例:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图2](/uploads/projects/u390550@fftlfh/4b21a1d2f0bac2aa3835f3730f7642df.png)
\r\n是换行的意思,windows的换行是\r\n,unix的是\n,mac的是\r
攻击流程:
前端服务器收到该请求,读取Content-Length,判断这是一个完整的请求。
然后转发给后端服务器,后端服务器收到后,因为它不对Content-Length进行处理,由于Pipeline的存在,后端服务器就任务这是收到了两个请求,分别是:
第一个:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图3](/uploads/projects/u390550@fftlfh/0cd21d98429afc4c5267f1cae1412267.png)
第二个:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图4](/uploads/projects/u390550@fftlfh/12c5bf81712af8ecd60ccb1f1335020c.png)
所有造成了请求走私。
2.CL-CL
有些服务器不会严格的实现该规范,假设中间的代理服务器和后端的源站服务器在收到类似的请求时,都不会返回400错误。
但是中间代理服务器按照第一个Content-Length的值对请求进行处理,而后端源站按照第二个Cont-Length的值进行处理。
构造请求示例:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图5](/uploads/projects/u390550@fftlfh/e01a6f422cc7a76bef584d926e1b4d64.png)
攻击流程:
中间代理服务器获取到的数据包的长度为8,将上述整个数据包原封不动的转发给后端源站服务器。
而后端服务器获取到的数据包长度为7。当读取完7个字符后,后端服务器认为已经读取完毕,然后生成对应的响应发送出去。而此时的缓冲区还剩余一个字母a,对于后端服务器来说,这个a是下一个请求的一部分,但是还没有传输完毕。
如果此时有一个其他的正常用户对服务器进行了请求:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图6](/uploads/projects/u390550@fftlfh/175eaef9a171b37a9d5222c3617ea7ee.png)
因为代理服务器和源站服务器之间一般会重用TCP连接。所以正常用户的请求就拼接到字母a后面,当后端服务器接收完毕后,它实际处理的请求其实是:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图7](/uploads/projects/u390550@fftlfh/2fe674537702784659c7ebdc1d9c6477.png)
这时,用户就会收到一个类似于aGET request method not found的报错。这样就实现了一次HTTP走私攻击,而且还对正常用户的行为造成了影响,而且还可以扩展成类似于CSRF的攻击方式。
但是一般的服务器都不会接受这种存在两个请求头的请求包。该怎么办?
所有想到前面所说的
RFC2616规范
如果收到同时存在Content-Length和Transfer-Encoding这两个请求头的请求包时,,在处理的时候必须忽略Content-Length。
所以请求包中同时包含这两个请求头并不算违规,服务器也不需要返回400错误。导致服务器在这里的实现更容易出问题。
3.CL-TE
CL-TE,就是当收到存在两个请求头的请求包时,前端代理服务器只处理Content-Length请求头,而后端服务器会遵守RFC2616的规定,忽略掉Content-Length,处理Transfer-Encoding请求头。
构造请求示例:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图8](/uploads/projects/u390550@fftlfh/13d02e92944f8e6325afde9f6b4ab992.png)
连续发送几次请求就可以获取响应。
攻击流程:
由于前端服务器处理Content-Length,所以这个请求对于它来说是一个完整的请求,请求体的长度为6,也就是
![http走私攻击([RoarCTF 2019]Easy Calc) - 图9](/uploads/projects/u390550@fftlfh/a04a5b5ac692d16b49836537efabb6e8.png)
当请求包经过代理服务器转发给后端服务器时,后端服务器处理Transfer-Encoding,当它读取到
![http走私攻击([RoarCTF 2019]Easy Calc) - 图10](/uploads/projects/u390550@fftlfh/c6144563c8fe18cbc68038a452d709a0.png)
认为已经读取到结尾了。
但剩下的字母a就被留在了缓冲区中,等待下一次请求。当我们重复发送请求后,发送的请求在后端服务器拼接成了类似下面这种请求:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图11](/uploads/projects/u390550@fftlfh/603eaacbdd0d8eb0c3b5d14673c3588d.png)
服务器在解析时就会产生报错了,从而造成HTTP请求走私。
4.TE-CL
TE-CL,就是当收到存在两个请求头的请求包时,前端代理服务器处理Transfer-Encoding请求头,后端服务器处理Content-Length请求头。
构造请求示例:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图12](/uploads/projects/u390550@fftlfh/3fd46dcc4ae70e9cc12a35cd8ea55e98.png)
攻击流程:
前端服务器处理Transfer-Encoding,当其读取到
![http走私攻击([RoarCTF 2019]Easy Calc) - 图13](/uploads/projects/u390550@fftlfh/6f90f354fb0b2a18856f82a55a9d3ed3.png)
认为是读取完毕了。
此时这个请求对代理服务器来说是一个完整的请求,然后转发给后端服务器,后端服务器处理Content-Length请求头,因为请求体的长度为4.也就是当它读取完
![http走私攻击([RoarCTF 2019]Easy Calc) - 图14](/uploads/projects/u390550@fftlfh/607931ab91ea080c5ea3f4e8f95f779d.png)
就认为这个请求已经结束了。后面的数据就认为是另一个请求:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图15](/uploads/projects/u390550@fftlfh/7ae61075c5182884bd194e97d8e04f7c.png)
成功报错,造成HTTP请求走私。
5.TE-TE
TE-TE,当收到存在两个请求头的请求包时,前后端服务器都处理Transfer-Encoding请求头,确实是实现了RFC的标准。不过前后端服务器不是同一种。这就有了一种方法,我们可以对发送的请求包中的Transfer-Encoding进行某种混淆操作(如某个字符改变大小写),从而使其中一个服务器不处理Transfer-Encoding请求头。在某种意义上这还是CL-TE或者TE-CL。
构造请求示例:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图16](/uploads/projects/u390550@fftlfh/6a7435cb0c5d5ad382c93bd5e308c062.png)
攻击流程:
前端服务器处理Transfer-Encoding,当其读取到
![http走私攻击([RoarCTF 2019]Easy Calc) - 图17](/uploads/projects/u390550@fftlfh/130ffffb31aef93938b74889ffd87672.png)
认为是读取结束。
此时这个请求对代理服务器来说是一个完整的请求,然后转发给后端服务器处理Transfer-encoding请求头,将Transfer-Encoding隐藏在服务端的一个chain中时,它将会回退到使用Content-Length去发送请求。读取到
![http走私攻击([RoarCTF 2019]Easy Calc) - 图18](/uploads/projects/u390550@fftlfh/5222ee5505d6e0fd6af555108dc56f04.png)
认为是读取完毕了。后面的数据就认为是另一个请求:
![http走私攻击([RoarCTF 2019]Easy Calc) - 图19](/uploads/projects/u390550@fftlfh/0b9a17fad5a0617b4648dd74fb070b49.png)
成功报错,造成HTTP请求走私。
实战攻击
![http走私攻击([RoarCTF 2019]Easy Calc) - 图20](/uploads/projects/u390550@fftlfh/a12ed480b2d15c0377224f942052b8e6.png)
![http走私攻击([RoarCTF 2019]Easy Calc) - 图21](/uploads/projects/u390550@fftlfh/1a1d9660ba789655373c5977780876cd.png)
其它几种请求走私依旧可以,就不测试了。
可能用得到的几个函数
scandir() 函数 返回指定目录中的文件和目录的数组。
base_convert() 函数 在任意进制之间转换数字,返回一个字符串
dechex() 函数:把十进制转换为十六进制。
hex2bin() 函数:把十六进制值的字符串转换为 ASCII 字符。
readfile() 函数
输出一个文件。
该函数读入一个文件并写入到输出缓冲。若成功,则返回从文件中读入的字节数。若失败,则返回 false。您可以通过 @readfile() 形式调用该函数,来隐藏错误信息。
输入时发现num只能输入数字,输入字符无法解析。
这里可以利用php的字符串解析特性绕过bypass:利用PHP的字符串解析特性Bypass
PHP需要将所有参数转换为有效的变量名,因此在解析查询字符串时,它会做两件事:
1.删除空白符
2.将某些字符转换为下划线(包括空格)
我们首先要构造列目录的payload,肯定要使用scandir函数,尝试构造列举根目录下的文件。scandir可以用base_convert函数构造,但是利用base_convert只能解决a~z的利用,因为根目录需要/符号,且不在a~z,所以需要hex2bin(dechex(47))这种构造方式,dechex() 函数把十进制数转换为十六进制数。hex2bin() 函数把十六进制值的字符串转换为 ASCII 字符。
![http走私攻击([RoarCTF 2019]Easy Calc) - 图22](/uploads/projects/u390550@fftlfh/41b766686d0e846381fc9f5efb7c2398.png)
构造读取flag,使用readfile函数,paload:base_convert(2146934604002,10,36)(hex2bin(dechex(47)).base_convert(25254448,10,36)),方法类似
![http走私攻击([RoarCTF 2019]Easy Calc) - 图23](/uploads/projects/u390550@fftlfh/0546801f8129bf279a3e386b2483d68c.png)
