中新网安安全实验室|HTTP请求走私漏洞及靶场复现
2019年8月,hackerone提交了关于PayPal HTTP请求走私+存储性XSS (链接:https://hackerone.com/reports/510152) 攻击可以直接对PayPal登陆页面进行控制,并且能获取所有用户密码,危害极大。这是什么漏洞,我们今天来揭开它的面纱:HTTP请求走私(HTTP Request Smuggling)
图片来源: https://portswigger.net/research/http-desync-attacks-request-smuggling-reborn 我们先了解下今年black hat上共享的Paypal漏洞实例(引用:https://i.blackhat.com/eu-19/Wednesday/eu-19-Kettle-HTTP-Desync-Attacks-Request-Smuggling-Reborn.pdf )代码如下:由于PayPal登录页面有一个CSP规则脚本-SRC,阻止了这个重定向后来,作者登录页面在动态生成的iframe中将c.payal.com上的子页面加载了。此子页面未使用CSP,还使用了由作者的JS文件!可以控制iframe页面,但是由于同源策略,无法读取父页面的数据。然后,在paypal.com/us/gifts上发现了一个不使用CSP的页面,并且还导入了污染JS文件。通过使用自己的JS将c.paypal.com iframe重定向到该URL(并第三次触发自己的JS导入),他终于可以访问父级并从使用Safari或IE PayPal登录的每个人那里窃取纯文本的PayPal密码。看着是挺绕的,但是慢慢想一下很简单,PayPal主站是有同源策略,旁站存在HTTP请求走私直接加载自己的JS,PayPal.com/us/gifts可以绕过主站可以加载自己的JS,然后成功窃取每个登陆PayPal账号密码。好,我们来了解下什么是HTTP走私。首先我们要了解下HTTP简介和概念。
HTTP请求走私是一种干扰网站处理从一个或多个用户接收的HTTP请求序列的方式的技术,它可以绕过安全控制,未经授权访问敏感数据并且直接危害其他应用程序用户。
我们知道HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web)服务器传输超文本到本地浏览器的传送协议,HTTP是一个基于TCP/IP通信协议来传递数据。
自HTTP/1.1开始,支持通过单个基础TCP或者SSL/TLS套接字发送多个HTTP请求,该协议将HTTP请求背靠背放置,服务器解析标头以计算出每个结束的位置及下个开始位置。1. Persistent Connection(持久连接)HTTP运行在TCP连接之上,存在TCP三次握手,慢启动等特点,为了尽可能提高HTTP的性能,引用了长连接的概念,目的解决HTTP传输,多次建立连接信息的情况,通过Connection: keep-alive 头部来实现,服务器和客户端使用它告诉对方在发送完数据之后不断开TCP连接,那么问题来了,我们该如何判断信息是否传输完成呢。为了解决这个问题,于是引入下面的请求头Content-length。2. Content-length(实体长度)Content-Length实体标头字段发送给接收方的实体的大小(以OCTET的十进制数为单位)通过判断Content-lenget长度相等,服务器便知道这个时候可以断开连接,如果Content-length和实体的实际长度短会造成内容截断,如果比实际内容长,会为缺少的内容进行自动填充,看似完美了,但是服务器为了计算信息内容,将所有内容缓存下载,并没有解决web应用优化。3. Transfer-Encoding: chunked(分块编码)为了解决Web优化,引入一个新的请求头Transfer-Encoding: chunked 也就是分块编码,加入请求头后,报文会使用分块的形式进行传输,不在需要缓存所有实例内容,只需要缓存分块即可,分块要求,每块必须包含16进制的长度和数据,长度值独立占据一行,不包括CRLF(\r\n),也不包括结尾的CRLF,当分块的长度为0,且没有数据,连接结束大多数网站为了提高浏览速度,用户体验,减少服务器负担,使用CDN加速服务,原理就是在源站前面加入具有缓存功能的反向代理,当用户请求静态资源,可以直接到代理服务器中获取,不在从源站服务器获取,反向代理与后端源站服务器之间,会重用TCP链接,因为不同的用户请求将通过代理服务器与源站服务器连接,代理服务器与后端的源站服务器的IP是相对固定。但是由于两者服务器的实现方法不同,如果用户提供模糊的请求可能代理服务器认为是一个HTTP请求,然后转发给后端源站服务器,源站服务器经过解析处理后,只认为其中一部分请求,剩下的另外一部分就是走私请求,形成这个原因,是由于HTTP规范提供了两种不同方式来指定请求的结束位置,它们是Content-Length标头和Transfer-Encoding标头。
我这里用的是https://portswigger.net演示环境,工具:burp suite,首先关闭Update content-length。
(1) CL.TE漏洞CT-TE: 前端使用Content-length,后端使用Transfer-Encoding前端服务器使用Content-Length头,而后端服务器使用Transfer-Encoding头。https://portswigger.net/web-security/request-smuggling/lab-basic-cl-te前端服务器处理Content-Length标头,并确定请求正文的长度为9个字节,直到的结尾test该请求被转发到后端服务器。后端服务器处理Transfer-Encoding标头,因此将消息正文视为使用分块编码。它处理第一个块,该块被声明为零长度,因此被视为终止请求。接下来的字节test保留未处理,后端服务器会将其视为序列中下一个请求的开始。(2) TE.CL漏洞前端服务器使用Transfer-Encoding头,而后端服务器使用Content-Length头。https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-te-cl,当我们直接访问/admin直接显示403,无法访问。该怎么办呢,如果我们使用下面请求是不是就绕过了呢? 是的,但是提示必须host是localhost才能访问,那我们直接加入HOST: localhost 可见加入HOST:localhost 发送请求,直接进入管理页面。
因为前端服务器处理Transfer-Encoding标头,使用分块编码。一直读到为0,认为读取完毕,此时这个请求对代理服务器来说是一个完整的请求,然后转发给后端服务器,后端服务器对Content-Length标头进行处理,当它读完71后认为请求结束,后面的数据就认为另一个请求,也就是成功执行。文件字节数为十六进制数:113转换为十进制数:71 TE-TE行为很容易理解,当前端服务器和后端服务器都支持Transfer-Encoding标头,我们可以通过某种方式混淆标头来诱导其中一台服务器不对其进行处理。可以说还是CL-TE TE-CL。 https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-te-cl使用下面数据包进行发送:1.不要重复使用后端连接,HTTP走私依赖多个后端多路复用,后端服务器将走私数据包与合法数据包一起处理,产生危害行为。如果每个请求单独联系发送,恶意的走私请求不在有效。
2.使用HTTP / 2进行后端连接,因为此协议禁止使用分块传输编码。3.前端服务器和后端服务器确保使用完全相同的Web服务器软件,以便它们就请求之间的界限达成一致。https://portswigger.net/research/http-desync-attacks-request-smuggling-rebornhttps://portswigger.net/web-security/request-smuggling
|