http协议的waf绕过

admin 2021年12月8日07:43:56评论240 views字数 4439阅读14分47秒阅读模式

一、    请求方法

也就是GET/POST,waf可能以此为依据对流量检测,列举一些少数不用GET/POST的请求情况。

比如IIS和tomcat存在老掉牙的PUT漏洞,WebDAV PUT/CVE-2017-12615。
比如存在直接PUT的oos。
比如springboot部分接口会写成PUT或者DELETE。
比如shiro-550在错误的请求方法中依旧能反序列化成功。

http协议的waf绕过



二、    传参

GET/POST/Cookie/Header,通常来说,waf对这四种传参方式的检测力度会不断削弱。
此外,在传输多个同一参数时,不同的中间件有不同的处理方案,apache/php

<?php  var_dump("id: ".$_REQUEST['id']);var_dump("token: ".$_COOKIE['token']);var_dump("test: ".$_SERVER['HTTP_TEST']);

http协议的waf绕过


tomcat/java


<%out.println("id: "+request.getParameter("id"));Cookie[]cookie = request.getCookies();for(Cookie c:cookie){    out.println("token:"+c.getValue());  }out.println("test: "+request.getHeader("test"));%>

http协议的waf绕过


IIS/asp

<%Response.Write("id:" & Request("id"))Response.Write("<br>id:" &Request.Form("id"))Response.Write("<br>token:" &Request.Cookies("token"))Response.Write("<br>test:" &Request.ServerVariables("HTTP_TEST"))%>

http协议的waf绕过

可以看到,IIS和apache均出现了以逗号合并多个参数的情况。因此在传输恶意payload时,可以用双参数进行,如下。
/test?id=1+and/*&id=*/1=1
IIS还允许传参unicode编码,或者在英文字母间插入%字符。
/1.asp?id=%u0031&id=a%b%c

http协议的waf绕过

GET传一个id,POST再传一个效果更好,虽然测试的几个中间件只有IIS可以,但实际情况中还是比较常见的。



三、    Content-Type

常见Content-Type如下
Content-Type: application/x-www-form-urlencoded
Content-Type: application/json
Content-Type: text/xml
Content-Type: multipart/form-data

有时候会加个编码
Content-Type: text/html; charset=utf-8

这个header允许大小写,还允许分号分割后增加脏数据干扰waf识别。一般来说Content-Type声明和POST传输的数据格式需要对应,不过也有的时候不对应或者没有Content-Type也可以被后端识别。
apache/php

http协议的waf绕过

tomcat/java

http协议的waf绕过

IIS/asp

http协议的waf绕过




四、    multipart/form-data

Content-Type: multipart/form-data通常用于文件上传,也可以用于传参,除了上面的干扰方法之外,在boundary段,Content-Disposition段也存在很多方法。

apache/php,最宽松。

http协议的waf绕过



tomcat/java,较为宽松。需要Context.xml

<?xml version="1.0" encoding="UTF-8"?><Context allowCasualMultipartParsing="true"></Context>

http协议的waf绕过


IIS/aspx,较为严格。

<%@ Page Language="C#" Debug="true"%><script runat="server">protected void Page_load(object sender,EventArgs e){  string id = Request.Params["id"];  string cid= Request.Params["cid"];  Response.Write("id: " + id);  Response.Write("rncid: " + cid);}</script>

http协议的waf绕过



flask/python,较为宽松

from flask import Flask, request
app=Flask(__name__)@app.route('/test', methods=["GET", "POST"])def test(): id = request.form.get("id") return "id: "+str(id)
if __name__ == '__main__': app.run()

http协议的waf绕过

以如下格式为标准

Content-Type: multipart/form-data; boundary=---69
-----69Content-Disposition: form-data; name="id"
3-----69--

复数显示

Content-Type: multipart/form-data; boundary=---69; boundary=---69Content-Type: multipart/form-data; boundary=---69
-----69Content-Disposition: form-data; name="id";name="id";
3-----69Content-Disposition: form-data; name="id"
4-----69--

分割成段并编号

http协议的waf绕过

这些位置基本都可以增加一些变化以逃脱waf识别,有兴趣的可以自己根据我标识的位置进行测试。



对于文件上传来说,多了filename和Content-Type,而filename和name的解析规律基本一致。

Content-Type在大概部分情况下可去除或者为其他任意值,因此waf不会检测,不过也有少数情况能影响到waf。

Content-Disposition: form-data; name="file"; filename="1.php"Content-Type: image/png

在Content-Type后面还可以设置charset,参考https://www.anquanke.com/post/id/242583的几种编码方法。

Content-Disposition: form-data; name="id"Content-Type: application/octet-stream; charset=CP037
cp037code

实际测试只有python/flask支持UTF-16be/UTF-16le/CP037/UTF-7等编码。

http协议的waf绕过


文章测试了java也有,同时werkzeug还支持Content-Transfer-Encoding: base64

可以看到,multipart/form-data可用变形非常多,而且不同中间件/语言规则都不同。很容易造成waf和后端解析的差异,导致waf无法识别被绕过。因此越来越多的waf选择自己实现严格的multipart/form-data,随便多个空格就拦截。比如宝塔。

五、    Transfer-Encoding: chunked

也就是分块传输,很多免费waf直接不识别分块传输。

Content-Type: application/x-www-form-urlencodedTransfer-Encoding: chunked
7;qweid=test002;qwest0;

Transfer-Encoding: chunked部分同样可以改变大小写和加空格。
标识长度的16进制数7,如上可以分号后增加各种脏数据填充,此处算A1填充处。
7本身可以在前面增加若干0来填充,此处算A0填充处。
这两处填充规则,不同的中间件也有着区别。

apache/php

A0+A1包括分号,也就是一行总长度最大为8188,如果有一行超出了长度限制,比如2;rty处填充9000脏数据,apache会报413,但前面正确的chunk也就是id=test依旧正确识别。

http协议的waf绕过

但如果整个body长度超过33180,id将无法获取包括GET上面的也一样,且这个数字是浮动的。
同理,如果有一个chunk和实际长度不符合,会报400错误但依旧能取得到对应的值。

http协议的waf绕过


这种情况曾用于ModSecurity的绕过。

Transfer-Encoding: chunked还可以和Content-Length: 8217共存,这种情况常见于找请求走私漏洞,但也有可能干扰waf识别。

tomcat/java

A0处仅允许8字节。A1处最大长度8191,并且所有chunk共享这一长度。超出长度后所有chunk将不再解析。

IIS/aspx

A0+A1,长度限制为16264,也是浮动的。
不使用Content-Length的情况下,在A0+A1处填充还很容易发包被拒绝。

flask/python

A0处无长度限制,但不支持A1和分号

nginx/php

A0和A1处均无长度限制。

分块传输还可以和Content-Type: multipart/form-data相结合,使其更加复杂。
分块传输也可以延迟发送,这也是分块传输被设计出来的意义,用如下burp插件可以很好的完成。
https://github.com/c0ny1/chunked-coding-converter

除了chunked之外,Transfer-Encoding还支持声明compress/deflate/gzip等压缩算法,可以让请求包的body压缩以免于被waf识别,但很早就被淘汰了,现在没有浏览器和服务端支持这个用法。

请求包能被压缩,与之对应的返回包压缩header如下
Accept-Encoding: gzip, deflate
支持compress/deflate/gzip/br,这个是客户端跟服务端声明自己的浏览器支持解压哪些返回包,服务端再响应Content-Encoding并返回压缩包,请求包并不会因为这个header被压缩。


六、    Expect: 100-continue

有的waf会检测返回包,这个header可以让返回包加个100状态码,所有中间件都支持。

http协议的waf绕过

七、    脏数据

通过上面介绍的可知,脏数据可以插在很多不影响传参的地方。根据payload的不同,也可以插在传参的注释处。比如sql注入的/*aaaaa*/。
脏数据用x00填充有奇效。

除了脏数据之外,针对免费云waf的打空流量,找真实ip,高并发等也是暴力手段之一。


原文始发于微信公众号(珂技知识分享):http协议的waf绕过

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2021年12月8日07:43:56
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   http协议的waf绕过http://cn-sec.com/archives/666336.html

发表评论

匿名网友 填写信息