Lab: Blind SQL injection with conditional responses
传送门:Lab: Blind SQL injection with conditional responses | Web Security Academy
关卡分析
先看描述,应用程序使用trackingcookie进行分析,说明这个trackingcookie可能可以利用,既不返回查询结果页不返回错误信息,但是查询正确会显示welcome back的信息,相当于一个只能回答是或不是的机器人,让我们来利用这个机器人来拿到账号密码进行登录即可过关,已知users表和username、password字段。
here we go
开始学习
url还是有控制参数,但是此时对我们已经没有别的反应了
参数随便输都没有报错信息
所以我们使用bp进行抓包,从trackingID入手
不确定抓没抓到,可以f12,点击Cookie-Editor插件查看一下session和trackingID,看看是否一致
send to repeat
第一步:测试cookie的位置是否有注入点
如果有,则会返回welcome back的信息
在trackingID后面使用' and 1=1--+
我们再试一下' and 1=2--+,是不是不返回,如果是则说明这里有注入点
判断成功cookie这里有注入点
第二步:判断是否有users这张表
使用' and (select 'x' from users limit 1)='x'--+
判断成功,users存在!
问题一:' and (select 'x' from users limit 1)='x'--+是什么意思?
答:
这句 (SELECT 'x' FROM users LIMIT 1) = 'x'
的关键在于它用子查询和逻辑比较来验证某些条件是否成立。我们逐步拆解这一句的含义:
结构解析
-
子查询部分:
(SELECT 'x' FROM users LIMIT 1)
-
目的:从
users
表中查询一行数据,但返回的结果不是表中的具体字段值,而是一个固定的字符串'x'
。 -
LIMIT 1:限制只查询一行,减少数据库负载。
子查询本质上是在测试:
users
表是否存在并有至少一条记录。- 如果
users
表存在且有数据,这个子查询会成功返回'x'
。 - 如果
users
表不存在,或者没有数据,子查询会失败,导致整个条件为假。
-
-
逻辑比较部分:
= 'x'
- 将子查询的结果与
'x'
进行比较:- 如果子查询成功返回
'x'
,条件为真。 - 如果子查询失败,或者返回的结果不等于
'x'
,条件为假。
- 如果子查询成功返回
- 将子查询的结果与
运行机制
-
成功的情况:
users
表存在且有数据。- 子查询
(SELECT 'x' FROM users LIMIT 1)
返回'x'
。 - 条件比较
'x' = 'x'
成立,整个语句返回成功。
-
失败的情况:
users
表不存在,或者表中没有数据。- 子查询无法返回任何结果。
- 条件比较失败,语句不会返回任何结果。
目的和作用
这段语句的核心作用是:
- 测试表是否存在: 如果
users
表不存在,子查询会失败,导致条件为假。 - 测试表是否有数据: 即使表存在,但如果没有记录,子查询也会失败。
通过这种方式,攻击者可以利用盲注来推断目标数据库中的表是否存在,以及是否包含有效数据。
示例说明
假设数据库中有一个 users
表,包含以下数据:
id | username | password |
---|---|---|
1 | admin | secret123 |
2 | user | password1 |
运行以下语句:
SELECT tracking-id FROM tracking-table WHERE trackingId = 'RvLfBU6S9EZRIVYN' AND (SELECT 'x' FROM users LIMIT 1) = 'x' --+
子查询执行:
SELECT 'x' FROM users LIMIT 1
:- 数据库从
users
表中查询第一行(LIMIT 1
),返回一个结果'x'
。
- 数据库从
逻辑比较:
'x' = 'x'
为真。
最终查询结果:
- 条件为真,主查询正常执行,返回结果。
总结
- 子查询
(SELECT 'x' FROM users LIMIT 1)
是用来验证users
表的存在性和数据的可用性。 = 'x'
是为了让条件返回布尔值,用于 SQL 注入中的盲注判断。- 这种方式非常常见于盲注场景,用于逐步推断目标数据库的结构和数据。
第三步:判断是否有username字段和administrator用户
使用' and (select username from users where username='administrator')='administrator'--+
第四步:判断密码的位数
使用' and (select username from users where username='administrator' and length(password)>1)='administrator'--+
这句sql语句的意思是:
-
(SELECT username FROM users WHERE username='administrator' AND length(password) > 1)
:- 这是一个子查询:
- 从
users
表中查询用户名为'administrator'
且密码长度大于 1 的用户。 - 如果条件满足,则返回
username
(即'administrator'
)。
- 从
- 这是一个子查询:
-
= 'administrator'
:- 验证子查询返回的值是否等于
'administrator'
。 - 如果子查询成功找到用户,并且条件(密码长度 > 1)成立,这个比较将返回
TRUE
。
- 验证子查询返回的值是否等于
-
--+
:- 注释掉原始查询的其余部分,使注入语句能够执行而不会出错。
问题二:在sql语句里and和等于号的优先级是怎么样的
答:在SQL中, AND 是逻辑运算符, = 是比较运算符。
逻辑运算符优先级高于比较运算符。但是你写的 1 AND 1 = 2 这个表达式,在SQL中会先计算 1 = 2 (结果为False),然后再计算 1 AND False ,最终结果为False。
例如在以下SQL查询中:
sql
SELECT
CASE
WHEN 1 AND 1 = 2
THEN 'True'
ELSE 'False'
END AS result;
查询结果会返回 False 。
我们这样一位一位的判断太慢了,所以使用bp里的intruder模块进行爆破
send to intruder,添加变量,使用sniper模块
payload type选用numbers,从1-50进行爆破
开始爆破,然后对爆破结果进行过滤,只要有welcome back的数据
只有19个
但是注意我们前面设置的是大于号' and (select username from users where username='administrator' and length(password)>1)='administrator'--+,所以密码有20位
第五步:爆破密码
使用:' and (select substring(password,1,1) from users where username='administrator')='a'--+
该语句的意思是通过比较单个字符的值来逐步猜测 administrator
用户的密码。具体解析如下:
语句解析
' and (select substring(password,1,1) FROM users WHERE username='administrator') = 'a'--+
-
' AND
:- 注入的起始点,将原始查询逻辑打断,并附加一个布尔条件。
-
(SELECT substring(password,1,1) FROM users WHERE username='administrator')
:-
子查询:
- 目标是从
users
表中提取username='administrator'
的用户密码。 substring(password, 1, 1)
:提取密码的第一个字符。password
是字段名称。1
是起始位置。1
是提取的字符数。
- 目标是从
-
如果
users
表中存在administrator
用户,这个子查询返回其密码的第一个字符。
-
-
= 'a'
:- 比较子查询返回的字符是否为
'a'
。 - 如果第一个字符确实是
'a'
,该条件为TRUE
。
- 比较子查询返回的字符是否为
-
--+
:- 注释掉后续的原始 SQL 查询内容,确保注入语句执行无误。
这里手动逐个拆解需要较长时间,所以使用intruder模块的Cluster bomb(集束炸弹)模块,添加两个变量,注意顺序不能乱
第一个变量添加在1那个位置表示从第一位开始到第20位逐位爆破,使用numbers字典
第二位添加在a那里表示爆破第一个变量时从abcdefghijklmnopqrstuvwxyz0123456789依个尝试,使用brute forcer字典
开始爆破,然后对爆破结果进行过滤,只要有welcome back的数据
最后登录账号密码即可
完成!