Smartbi 远程代码执行漏洞复现(QVD-2025-31926)

1、 漏洞描述

近日,奇安信CERT监测到官方修复Smartbi 远程代码执行漏洞(QVD-2025-31926),该漏洞源于攻击者可通过默认资源ID绕过身份验证获取权限,配合后台接口实现远程代码执行,可能导致服务器被完全控制、数据泄露或业务系统沦陷。鉴于该漏洞影响范围较大,建议客户尽快做好自查及防护。

2、影响范围

影响版本

Smartbi <= 11.0.99471.25193

3、补丁分析

官网发布了新的补丁,我们可以从补丁入手,看他修复了什么

https://www.smartbi.com.cn/patchinfo

下载到的补丁是经过加密的

具体解密方法可参考:

Smartbi 最新认证绕过导致RCE漏洞分析

解密

下载为 jar 包:

7-31 的补丁内容:

java
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
{
	"version": "1.0",
	"date": "2025-07-31 09:00:00",
	"patches": {
	    "PATCH_20250731": {
	    	"desc": "强化系统安全性,防范特定条件下的非授权访问5 (Patch.20250731  @2025-07-31)",
	    	"desc_zh_TW": "強化系統安全性,防範特定條件下的非授權訪問5 (Patch.20250731  @2025-07-31)",
	    	"desc_en": "Strengthen system security against unauthorized access under certain conditions 5 (Patch.20250731  @2025-07-31)",
	    	"urls": [
	    		{
					"url": "/vision/share.jsp",
					"rules": [
						{
							"type": "ShareRecordPatchRule",
						}
					]
				},
				{
	    			"url": "/smartbix/api/agentEngineMonitor/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/customextension/customsqlnode/nodedefine",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/datamining/config/infos",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/datamining/config/service/infos",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},{
	    			"url": "/smartbix/api/datamining/config/system/infos",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/datamining/customExtensionNode/java/upload",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/datamining/customExtensionNode/python/upload",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/datamining/customtree/type/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/datamining/customnodehelp/update/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/datamining/bind/mining/secret",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/engineMonitor/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/engineMonitor/engineLog/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/engineMonitor/engineMethod/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/engineMonitor/restartComputeNode/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/engineMonitor/agentsystem/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/engineMonitor/agentLog/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/serveMonitor/serviceMethod/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/serveMonitor/serviceServers/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/serveMonitor/serviceLog/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/checkStart",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/jobs",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/jobs/job",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/jobs/job/kill",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/stages",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},{
	    			"url": "/smartbix/api/sparkUiMonitor/stages/stage",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/stages/pool",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/storage",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/storage/rdd",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/environment",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/executors",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/executors/threadDump",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/SQL",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/SQL/execution",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/logPage",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/applications",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/api/v1/applications/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/executorspage",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/log",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/sparkUiMonitor/backMaster",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/dataprepare/sparkfunctions/import",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/dataprepare/sparkfunctions/delete/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/dataprepare/sparkfunctions/reset",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/dataprepare/sparkfunctions/update",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_MINING,MANAGE_ETL,AUGMENTED_DATASET_ETL"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/jobflow/config",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_JOBFLOW,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/jobflow/jobFlowLog/*",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_JOBFLOW,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/jobflow/jobFlowLog",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_JOBFLOW,MANAGE_TOOLKIT_SYSMONITOR"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/user/scheduleIsPasswordValidate",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_USERMANAGEMENT"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/user/isPasswordValidate",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_USERMANAGEMENT"
	    			}]
	    		},
	    		{
	    			"url": "/smartbix/api/admin/clearCache",
	    			"rules": [{
	    				"type": "AssertFunctionUrlPatchRule",
	    				"funcList": "MANAGE_TOOLKIT_EXPORTSYSTEMLOG"
	    			}]
	    		}, {
						"url": "/smartbix/api/login",
	    			"rules": [{
	    				"type": "RejectPatchRule"
	    			}]
					}, {
						"url": "/smartbix/*",
	    			"rules": [{
	    				"type": "RejectInvalidUrlPatchRule"
	    			}]
					}
	    	]
	    },

找到漏洞路径/vision/share.jsp以及对应补丁代码

4、漏洞源码分析

这里获取一个资源ID resid,如果这个资源ID符合isPublicShareResourceByShareType ,不管当前会话是否已登录,都将当前用户切换为public用户

也就是说未登录的用户,访问资源时,会获得 public的权限。

注:

如果没有添加库,就会如下图所示,找不到对应的方法、类

如果要看到完整的代码,需要把 lib 库添加到项目结构中:

具体要添加的库:

E:\Smartbi\Tomcat\lib

E:\Smartbi\Tomcat\webapps\smartbi\WEB-INF\lib

这样就可以看到完整的源码了

接着上文,跟进 autoLoginByPublicUser

该方法的作用: 如果系统允许匿名访问,则使用内部 SERVICE 账户临时授权,把当前用户切换为 public 用户。

java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//表示该方法不可通过远程 RMI 调用,只能内部调用
@NotRMI
public boolean autoLoginByPublicUser() {
    //必须有一个 public 用户,否则登录失败
    String userName = "public";
    if (this.getUserByName(userName) == null) {
        return false;
    } else {
        //若本次会话没有,系统 ID,则设置为默认值
        if (this.stateModule.getSystemId() == null) {
            this.stateModule.setSystemId("DEFAULT_SYS");
        }

        // SERVICE 是内部保留的系统用户
        IUser serviceUser = this.getUserById("SERVICE");
        if (serviceUser == null) {
            throw (new SmartbiException(UserManagerErrorCode.NOT_EXIST_USER)).setDetail("SERVICE");
        } else {
            //如果当前用户已经是 public ,不再进行切换操作
            IUser currentUser = this.safeGetCurrentUser();
            if (currentUser != null && "PUBLIC".equals(currentUser.getId())) {
                return true;
            } else {
                //将当前用户强制设置为 SERVICE
                this.stateModule.setCurrentUser(serviceUser);
                this.stateModule.removeSessionAttribute("SMARTBIX_STATE");
                boolean ret = false;

                boolean var5;
                try {
                    //switchUser 执行真正的用户切换
                    ret = this.switchUser(userName);
                    var5 = ret;
                } finally {
                    if (!ret) {
                        this.stateModule.setCurrentUser(currentUser);
                    }

                }

                return var5;
            }
        }
    }
}

跟进 setCurrentUser

java
1
2
3
4
5
6
7
8
9
    @NotRMI
    public void setCurrentUser(IUser user) {
        //state 是 Smartbi 的一个独立 Session 状态对象,通常封装:登录用户、本地语言、当前 SystemId、用户权限缓存(role/resource)、登录 token、登录方式
        this.getState().setUser(user);
        //在 HTTP Session 中记录用户名
        this.setSessionAttribute("user", user == null ? null : user.getName());
        //更新 Session 的语言环境
        this.updateSessionLocale(user);
    }

跟进 switchUser

java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
public boolean switchUser(String username) {
//当前会话必须有用户,在上一步的 autoLoginByPublicUser() 把当前用户设置为 SERVICE
boolean result = false;
String loginFailReason = null;
User currUser = (User)this.userManagerModule.getStateModule().getCurrentUser();
if (currUser == null) {
    return false;
} else {
    //获取当前用户信息
    String currUserName = currUser.getName();
    UserBO userBO = new UserBO(currUser);

    try {
        //跳过登录的校验
        String code = null;
        Collection<LoginCheckItem> skipChecks = new HashSet(Arrays.asList(LoginCheckItem.TWO_FACTOR_AUTH_CHECK));
        //如果是 public ,还要跳过校验  LoginCheckItem.ROLE_ASSIGNMENT_CHECK
        if ("public".equals(username)) {
            skipChecks.add(LoginCheckItem.ROLE_ASSIGNMENT_CHECK);
        }

        //verifyPassword 只有当前用户是 Admin 才允许 switchUser,普通用户不能随意切换
        //而在 autoLoginByPublicUser 在切换 public 时,强制把当前用户变成 SERVICE(管理员),就可以通过 verifyPassword,进行切换
        Supplier<Boolean> verifyPassword = () -> {
            if (userBO.isAdmin()) {
                return true;
            } else {
                throw new SmartbiException(UserManagerErrorCode.NO_PERMISSION);
            }
        };
        //performLoginCheck 会执行用户是否存在、过期等等逻辑
        result = this.performLoginCheck(username, (String)null, code, skipChecks, verifyPassword);
    } catch (SmartbiException e) {
        loginFailReason = e.getDetail() == null ? e.getMsg() : e.getDetail();
    } finally {
        //写日志
        JSONObject obj = new JSONObject();
        Object attr = this.userManagerModule.getStateModule().getRequestAttribute("loginByToken");
        if (attr != null) {
            obj.put("loginByToken", attr.toString());
        }

        obj.put("switchUserBy", currUserName);
        if (result) {
            this.performLoginSucceeded(username, (String)null, () -> obj);
        } else {
            this.performLoginFailed(username, loginFailReason, () -> obj);
        }

    }

    return result;
}
}

所以总结一下:我们需要找到一个资源 ID 符合 isPublicShareResourceByShareType,不管登录与否,都可以获得public用户的 session

跟进 isPublicShareResourceByShareType

java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public boolean isPublicShareResourceByShareType(String relateid, String shareType) {
        if (StringUtil.isNullOrEmpty(relateid)) {
            return false;
        } else {
            try {
                ShareRecord shareRecord = null;
                //根据 shareType 决定查询方式
                if (StringUtil.isNotNullAndEmpty(shareType)) {
                    shareRecord = SocialContactShareDAOFactory.getShareRecordDAO().loadWeChatByRelateid(relateid);
                } else {
                    shareRecord = SocialContactShareDAOFactory.getShareRecordDAO().loadByRelateid(relateid);
                }

                //检查分享记录是否“公开分享且已启用”
                if (shareRecord != null 
                    && shareRecord.getPublicshared() == 1 
                    && shareRecord.getEnabled()) {
                    return true;
                }
            } catch (ParseException e) {
                LOG.error(e);
            }

            return false;
        }
    }

跟进 shareRecord

shareRecord.getPublicshared()

shareRecord.getEnabled()

总结满足 isPublicShareResourceByShareType 的条件:

  1. relateid不为空
  2. shareType不为空
  3. shareRecord.getPublicshared() == 1表示公开分享
  4. shareRecord.getEnavled() == true
    1. deleted != 1分享不能被删除
    2. cancelled != 1分享不能被取消
    3. enddate == null为 null 就是永不过期

具体的构造需要找到对应的参数:

c_deleted!=1 and c_cancelled!=1 and c_publicshared=1

继续跟入loadByRelateid

根据 relateid 字段查询一条 ShareRecord 记录

去查找:“ShareRecord.getShareRecordByRelateid”

表名 :t_share_record

列名 : c_relateid

构造查询语句:

select c_relateid from t_share_record where c_deleted != 1 and c_cancelled != 1 and c_publicshared = 1

可能由于我没有安装演示库,导致什么都查不到

看其他师傅的文章里是可以查询到结果的

通过以上方法获取到有效 session 就可以在后台调用任意 js 代码达到远程代码执行的目的

由于我没有获得有效的 session,后续就不复现了,,

借用 @漫漫安全路 师傅的文章:

参考:

【已复现】Smartbi 远程代码执行漏洞(QVD-2025-31926)安全风险通告

Smartbi 最新认证绕过导致RCE漏洞分析

smartbi远程代码执行漏洞复现(QVD-2025-31926) - Zephyr07 - 博客园