宝塔低版本登录绕过漏洞
宝塔在6.0版本修改了源代码换成了python的,使用flask框架搭建,其中登录的时候可以选择使用微信扫码登录,在扫描登录的过程存在一处逻辑漏洞可以绕过限制,免密登录,执行恶意代码
分析
BaoTa新版本是7.1,已经将漏洞修复了,先从github上下载6.9.5版本的BaoTa源代码
将项目导入pycharm进行分析
宝塔面板的入口在BT-Panel文件,先跟BT-Panel
从BTPanel模块导入app类,然后,在debug的时候,执行app.run函数,跟进app,发现BTPanel模块就只有一个文件__init__.py文件,跟进这个文件
app是Flask的实例,这里基本可以看出宝塔面板是使用flask框架编写的web程序,针对web程序的审计,一般都是先根据路由跟进业务代码,在宝塔中,所有的路由都在这个文件中定义好了,直接跟进这个文件就好
在我审计宝塔的过程中,我发现宝塔的路由可以分成3部分,第一部分是常规能访问的部分,最简单的就是提示你正确入口,如果有漏洞能在这部分被利用那就非常严重了
第二部分是真正的登录口,或者经过登录口认证后的页面,典型的就是登录入口,宝塔的登录入口是随机8位数,这个登录入口设置成随机8位数,并不是为了防止爆破这么简单,实际上,他是宝塔的第一层认证
这段代码中,login函数就是登录口对应的业务逻辑代码,可以看到这个函数对应的路由有3个,主要是/login和route_path,route_path就是8位随机数,如果我们传入的是/login,最终会返回autterr.html文件,如果传入的是route_path,session[‘admin_auth’]会等于True,这个sessions就是第一层的验证
1 | admin_path = '/' |
第三部分就是登录进入宝塔面板,一旦进入宝塔面板,这个服务器基本沦陷了,这一部分是主要常规的账号密码登录和扫码登录,常规的密码登录略过,这里主要研究扫码登录
跟进代码的逻辑,这里主要是wxapp这个类来处理登录请求,而从行为上来讲,我们登录需要先获取验证码,所以先跟进fun=login_qrcode时,wxapp类的处理
如果fun=login_qrcode,check函数会直接返回True,进入下个eval函数,执行的代码就是pluwx.login_qrcode(get),跟进login_qrcode函数
login_qrcode在ScanLogin这个类里,wxapp会继承这个类,从这段函数可以看出扫描登录的二维码来自宝塔官方,所以扫描登录会和官方有关系,有了二维码就要扫码登录
扫描登录时,宝塔官方回过来请求你的地址,url为fun=scan_login,这里也会经过check函数
这里逻辑会进入else代码块,这个代码块验证的很严格,没有啥绕过的可能,验证过后进入scan_login函数
主要是写了login.pl文件,这个文件非常好仿造,如果有漏洞能写文件,这里登陆就能绕过了(写shell不更香吗),官方到这里,他的工作就结束了,接下来就是宝塔面板自己的验证过程,宝塔面板需要知道扫描到底成功没有,他的前端会一直访问fun=is_scan_ok
扫描成功之后,他会读取login.pl的内容,返回给前端,前端带入这些参数,访问set_login函数,进行登录跳转
到这里,一个登录的流程就走完了,在这个流程中,is_scan_ok和set_login是公开的,他没有任何认证,这里就会出现一个条件竞争漏洞,如果攻击者能抢先访问到is_scan_ok和set_login函数,那他就能先登录宝塔面板
验证
宝塔面板在登录后有许多操作服务器的功能,这里选择计划任务作为验证漏洞的结果,漏洞利用成功后会使用计划任务反弹一个shell
编写验证的脚本上传另一台vps,这里需要注意cookie,一定要带入宝塔的特定cookie
开启另一台vps上的宝塔
开始验证
反弹成功
修复
宝塔在最新版中修复了这个漏洞,他将原本在第一部分就能访问的is_scan_ok这个路由放到了第二部分,这个漏洞的利用就变得很鸡肋
在宝塔的最新版可以看到不止修复了这个漏洞,在上面还有个修复补丁,可以追踪下上面的修复补丁