mongoose sql injection
注入看修复的commit就可以看出来在哪:
https://github.com/YMFE/yapi/pull/2628/commits/432cdfeb29667eea8b82d72a265022ac9515bdb7
这里对token增加了限制很容易想到token为其它类型的的情况,比如json,再结合注入就基本确定是mongoose的sql注入了
接着看下面的逻辑,注意两点
parseToken,看下代码的话会发现功能是解密token,获得原始的token,默认情况下salt是abcde和uid的拼接
这段逻辑是没什么问题,但是在下面parseToken失败了之后,代码又尝试把这个token当作原始的token进行查询和校验,这里就有点奇怪了。
一直跟踪getProjectIdByToken到最终调用mongoose的api都没有对token做任何过滤,所以这里存在注入。
mongoose的注入可以参考,https://blog.websecurify.com/2014/08/hacking-nodejs-and-mongodb
最终的效果就是可以通过注入真实的token,然而这里token并不是用户登录的token等等,而是项目的token
所以还要看看什么接口可用,来获取加密后的token以及RCE
可以通过 /api/open/plugin/export-full 这个接口uid然后推出加密后的token,然后就是分析怎么RCE了
mock sandbox
因为yapi之前有开放注册导致mock处可以RCE,所以我也先看了这个,相关接口是全部可以通过token访问的。不过因为之前的洞导致这里的沙箱增强了很多,所以之前的sandbox bypass也无法使用了
所以这里研究了下mock sandbox,发现之前的VM沙箱换成了safeify:
可以参考 https://juejin.cn/post/6844903607389814797 了解这个沙箱:
发现safeify直接调用了vm2 https://github.com/patriksimek/vm2 , 在安全上没有增加很多限制
那问题就是bypass vm2 了,vm2是一个相对安全的NodeJS沙箱,绕过这个难度就会大很多,只能寄希望于目标站点搭建时间比较早,用的vm2版本相对低一点,这样就可以用vm2的bypass方法来绕过
pre_script
再去看了一下漏洞预警,发现这次似乎RCE的点是pre_script, 所以又看了一下pre_script是怎么处理的:
在runAutoTest pre_script被处理,runAutoTest 是 /api/open/run_auto_test的处理函数,也是可用token调用的
然后是handleTest调用crossRequest,crossRequest通过sandbox运行preScript,
然后就发现pre_script处的沙箱居然是vm.., 那就可以直接用vm沙箱bypass的方法来命令执行了,
默认也是用sandboxByNode来执行script,不过还是可以看看else里面的sandboxByBrowser
发现沙箱都省了。。不过不会走到这就是了。
总结这个漏洞产生的根本原因是在处理token的时候parse失败了都不返回,多此一举,既然会有直接校验原始token这一步那么花这么多功夫加密解密token干什么呢?