In November of 2023, preparing for a call for papers, I attempted to investigate the FortiSIEM patch for CVE-2023-34992. I kindly inquired with the PSIRT if I could have access to the most recent versions to some of their appliances to validate the patches, to which they declined. Acquiring access a different way, I eventually was able to analyze the patch.
While the patches for the original PSIRT issue, FG-IR-23-130, attempted to escape user-controlled inputs at this layer by adding the wrapShellToken()
utility, there exists a second order command injection when certain parameters to datastore.py
are sent. There exist two distinct vulnerabilities which were assigned CVE-2024-23108 and CVE-2024-23109, both with a CVSS3 score of 10.0, which allows remote, unauthenticated command execution as root. This blog will only cover the first, CVE-2024-23108, given they’re both patched in the same release.
CVE-2023-34992 Patch and Code Flow Analysis
In CVE-2023-34992, the phMonitor service on tcp/7900 was abused by sending it a handleStorageRequest message with a malicious server_ip
value. When phMonitor received this message the specific command to be executed would be:
/usr/bin/python3.9 /opt/phoenix/deployment/jumpbox/datastore.py nfs test ‘<server_ip>’ ‘<mount_point>’ online
. Inspecting the control flow of datastore.py
for this type of request, we see that the server_ip
field is validated by attempting to connect to the IP address.
Figure 1. datastore.py validating server_ip
After this, control is eventually passed to /opt/phoenix/deployment/jumpbox/datastore/nfs/test.py
. Here, a call to __testMount()
formats a call to os.system()
on line 23, which derives the nfs_string
value from our user-controlled mount_point
payload value.
Figure 2. __testMount() calls os.system()
By formatting a request to the phMonitor client with a command type of 81, and the following payload, an unauthenticated attacker can achieve remote code execution as root.
Figure 3. Exploiting for reverse shell
The astute reader will notice that there is very little difference in the exploitation of the previous command injection, CVE-2023-34992, to this one, CVE-2024-23108, reported 6 months later.
Figure 4. CVE-2023-34992 vs CVE-2024-23108
Our proof of concept exploit can be found on our GitHub.
Indicators of Compromise
The logs for the phMonitor service will verbosely log many details of messages it receives and can be found at /opt/phoenix/logs/phoenix.log
. Attempts to exploit CVE-2024-23108 will leave a log message containing a failed command with datastore.py nfs test
. These lines should be inspected for malicious looking input.
Figure 5. Malicious commands logged
Timeline
29 November 2023 – Reported CVE-2024-23108
30 November 2023 – Reported CVE-2024-23109
3 January 2024 – PSIRT reproduces issues
16 January 2024 – Fortinet silently fixes the issues in v7.1.2 build 0160 with no mention of the vulnerabilities, PSIRT releases, or CVEs published
31 January 2024 – Fortinet publicly “discloses” the issues by adding unpublished CVE IDs to the PSIRT released for CVE-2023-34992 6 months prior without adding a changelog entry
7 February 2024 – Fortinet publicly publishes the CVE IDs, but states they were duplicates published in error, and then states they were real
Sometime later in 2024 – Fortinet eventually adds a changelog entry to the PSIRT and adds CVE IDs to the release documents
28 May 2024 – This blog
NodeZero
Horizon3.ai clients and free-trial users alike can run a NodeZero operation to determine the exposure and exploitability of this issue.
Sign up for a free trial and quickly verify you’re not exploitable.