Smartbi 远程代码执行漏洞

环境搭建:

搭建参考:https://wiki.smartbi.com.cn/pages/viewpage.action?pageId=114987452

访问 http://ip:18080/smartbi/vision/index.jsp

漏洞分析:

下载漏洞补丁:

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

使用如下脚本解密,得到压缩文件后解压

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import argparse
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
from base64 import b64decode

def decrypt_aes_file(input_file, output_file, key=b'1234567812345678', iv=b'1234567812345678'):
cipher = AES.new(key, AES.MODE_CBC, iv)
with open(input_file, 'rb') as f_in:
encrypted_data = f_in.read()
decoded_data = b64decode(encrypted_data)
decrypted_data = unpad(cipher.decrypt(decoded_data), AES.block_size)
with open(output_file, 'wb') as f_out:
f_out.write(decrypted_data)

parser = argparse.ArgumentParser()
parser.add_argument('-f', '--file', type=str, default="patch.patches", help="Path to file name.")
args = parser.parse_args()

filename = "decrypted-"+args.file+".zip"

decrypt_aes_file(args.file, filename)
print("[+] OutPut: " + filename)

查看 patch.patchs 补丁文件,根据漏洞描述猜测权限绕过发生在 /vision/share.jsp 文件中

继续跟进,只需要满足条件 shareService.isPublicShareResourceByShareType(resid, sharetype),并且让 JSONObject result = shareService.getShareRestrictByShareType(resid, sharetype) 的结果为 false 就可以直接调用 UserManagerModule.getInstance().autoLoginByPublicUser() 来获取合法Session。

/smartbi/vision/share.jsp

继续跟进 shareService.isPublicShareResourceByShareType(resid, sharetype),满足根据 relateid (也就是resid) 查询到的 shareRecord 不为空且 Publicshared 为1就会返回 true

smartbi.module.socialcontactshare.SocialContactShareService#isPublicShareResourceByShareType

在 smartbi 数据库 t_share_record 表中查询两个满足条件的 relateid 值:96a0a9d0b86f90d5416d013f4cfe2f23 和 b904ab9f5a84712a672523a7b4881ee4

继续跟进 shareService.getShareRestrictByShareType(resid, sharetype),当 shareType 为空就调用 this.shareRestrict(relateid, (String)null, (String)null, (String)null)

smartbi.module.socialcontactshare.SocialContactShareService#getShareRestrictByShareType

在 shareRestrict() 方法的条件判断中 shareRecord.getCode() 获取数据库 t_share_record 表中的值为空,所以最终返回false。

smartbi.module.socialcontactshare.SocialContactShareService#shareRestrict

最终使用以下http请求获得合法 public 用户 Session

1
2
3
GET /smartbi/vision/share.jsp?resid=b904ab9f5a84712a672523a7b4881ee4 HTTP/1.1
Host: 192.168.211.252:18080
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.6478.57 Safari/537.36

在 patch.patchs 6月份的补丁中搜索到了一个明显的关键字

搜索相关方法,可以看到不需要admin权限,并直接调用js引擎执行了传入的表达式。

而 Smartbi 的smartbi.framework.rmi.RMIServlet 可以通过 smartbi.framework.rmi.ClientService#executeInternal 反射调用任何方法,不再赘述。

漏洞复现: