HTTP请求走私

0x00 前言

请求走私的的环境需要有,1台cdn缓存服务器,一台真正处理的业务的web服务器,用户访问网站表面上看着是直接访问该web服务器,其实是从cdn上获取缓存的数据,并没有去请求真正web服务器

0x01 预备知识

cdn的作用是为了缓存静态页面,这样可以让真正的web服务器的压力不要太大。另一个作用是为了隐藏web服务器的真实ip地址。(随手用QQ截图画了个图

cdn与web服务器之间相当于代理的关系

用户去请求部署了cdn的web站点,其实请求的资源cdn上有,直接从cdn上发送给用户,而不会再走到后面的web服务器,这样就节省了真正服务器的开销。如果没有再去请求web服务器,

0x02 HTTP走私原理

HTTP 请求的请求体有2种判定方式

  1. 利用Content-Length字段来判定请求体的内容长度
  2. 利用Transfer-Encoding字段来判定请求体的结束位置

Content-Length

​ 正常post请求,会带上请求体(body),请求体有多长,Content-Length的值就是多少

Transfer-Encoding

Transfer-Encoding就是分块传输的标志,它不靠Content-Length来告诉web服务器请求体有多长,而是靠0这个字符来代表分块结束,之后还要换行2次(重点!!!)

至于分块传输的格式

3
aaa
5
aa
a
0


上面这行代表着分了3段,第一段是3个a,第二段是2个a和一个\r和一个\n再1个a,第三段是空

aaa上面的3是长度,表示第一段有3个字节,同理第二段加上换号就是5个字节,最后一段为空就0个字节,但最后有2个换行表示结束

再注意,长度是以16进制表示,即如下下面字节长度为27,则长度为1b

请求走私的原理是因为,假如cdn对请求有限制,而web服务器对请求没有限制,此时cdn和web服务器的对body的处理方式不一致,就会导致绕过cdn的限制,直接去请求web服务器的资源。

说到这里有点抽象,举个下面要用到的lab环境的例子

cdn不准请求/admin目录,web服务器可以请求/admin 目录,而我们访问肯定是先请求cdn的,因此就被拦截了。

我们要做的是去请求真正web服务器的/admin目录,就不会被拦截。如果cdn和web服务器对body检测机制不同,HTTP请求走私就可以派上用场了。

0x03请求走私的类型

  1. GET请求web服务器不处理请求体,cdn处理请求体(body)
  2. 设置2个 Content-Length, cdn解析第一个,web服务器解析第二个
  3. cdn使用Content-Length,web服务器使用Transfer-Encoding(默认情况下,存在Transfer-Encoding字段时,会优先按分块传输来解析请求体)
  4. cdn使用Transfer-Encoding,web服务器使用Content-Length

0x04例子

环境链接:

https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-cl-te

随便注册下就可以开始了

实验要求,访问 /admin目录,并以admin的身份去删除carlos用户

该实验室是前面的cdn使用的是Content-Length来检测body,后面的web服务器使用的是Transfer-Encoding来进行检测body

直接请求admin,可以看到被403了

接下来使用分块传输,最前面请求的不是/admin,而是去请求可以请求到的/根目录

利用GET协议发现不被允许,因此改成POST协议

可以看到已经返回的值和只请求/是不同的,提示到需要是本地访问,或者登陆administrator账号,登陆administrator账号不太现实,本地访问的话只有加上Host: localhost即可

这里处理的流程大致是这样的

  • cdn看Content-Length字段来判定请求体信息,它会把下面所以给当成请求体,于是请求合法,发送给后面的web服务器
  • web服务器因为有Transfer-Encoding字段存在,并且下面是以分块传输的格式,因此以分块传输来划分body内容
  • 遇到了0,因此此时web服务器认为该HTTP请求已经结束了,再次往下GET /admin HTTP/1.1,就当成新的HTTP请求,于是返回了/admin目录的信息

继续添加Host: localhost的请求头(有时候请求多次才灵光,可能是缓存问题?

可以看到已经有admin的权限了,并且有删除carlos账号的url请求

这里有个问题为什么加localhost得到的结果不是用户的localhost地址,而是web服务器的地址。我理解的是,该请求发送给后面真正的web服务器时,web服务器是拿到这些HTTP请求,从web服务器端把这些HTTP请求进行发送,最后将结果返回给用户。

也就是这HTTP的request是web服务器发出的,于是localhost就是web服务器了

最后删除carlos账号,就完成了本次实验

相对的来,下面这个实验是,cdn使用分块传输,后面web服务器使用的Content-Length进行检验

https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-te-cl

要求是一样的,也是删除carlos账号

那么利用上面的包依然可以访问到/admin目录,这里注意Content-Length长度为4,因为后面的web服务器是检测Content-Length的,因此它读了4个字节后就结束了,这里的4个字符是22加上\n\r,共4个

之后后面的web服务器会把内容当成下一个请求包了

这里有个坑,burpsuit它会自动检测body长度,然后自动更新Content-Length字段,这里可以关闭这个功能,取消勾勾即可

接下来就和上面一样了,添加Host: localhost请求体,之后删除carlos账号

完结撒花

0xff参考链接

https://xz.aliyun.com/t/6631

https://www.freebuf.com/articles/web/213360.html

https://blog.csdn.net/weixin_44058342/article/details/102503140

https://portswigger.net/web-security/request-smuggling/exploiting/lab-bypass-front-end-controls-cl-te

posted @ 2020-06-13 18:28  sijidou  阅读(3122)  评论(1编辑  收藏  举报