On Thursday, 16 February 2023, Fortinet released a PSIRT that details CVE-2022-39952, a critical vulnerability affecting its FortiNAC product. This vulnerability, discovered by Gwendal Guégniaud of Fortinet, allows an unauthenticated attacker to write arbitrary files on the system and as a result obtain remote code execution in the context of the root user.
Extracting the System
Extracting the filesystems from the appliances is straightforward, first the mountable filesystem paths are listed from the vmdk:
sudo virt-filesystems --filesystems -a fortinac-9.4.1.0726.vmdk
Next, we mount the filesystem to a directory we make:
sudo guestmount -a fortinac-9.4.1.0726.vmdk -m /dev/centos/root --ro /tmp/fnac941
After extracting both filesystems from both the vulnerable and patched vmdk’s, it’s apparent that the file
/bsc/campusMgr/ui/ROOT/configWizard/keyUpload.jsp was removed in the patch, and also matches the name of the servlet mentioned in the advisory.
Examining the contents of keyUpload.jsp, we see that the unauthenticated endpoint will parse requests that supply a file in the
key parameter, and if found, write it to
After successfully writing the file, a call to
Runtime().Exec() executes a bash script located at
The bash script calls unzip on the file that was just written. Immediately, seeing this call on the attacker controlled file gave us flashbacks to a few recent vulnerabilities we’ve looked at that have abused archive unpacking. While our initial thoughts were around a directory traversal issue, unzip helpfully strips relative paths and protects against traversals.
The issue is actually much more simple and no traversal is needed. Just before the call to unzip, the bash script calls
cd /. Unzip will allow placing files in any paths as long as they do not traverse above the current working directory. Because the working directory is
/, the call
unzip inside the bash script allows any arbitrary file to be written.
Weaponization of the Issue
Similar to the weaponization of previous archive vulnerability issues that allow arbitrary file write, we use this vulnerability to write a cron job to
/etc/cron.d/payload. This cron job gets triggered every minute and initiates a reverse shell to the attacker.
We first create a zip that contains a file and specify the path we want it extracted. Then, we send the malicious zip file to the vulnerable endpoint in the
key field. Within a minute, we get a reverse shell as the root user. Our proof of concept exploit automating this can this can be found on our GitHub.
Indicators of Compromise
Unfortunately, the FortiNAC appliance does not allow access to the GUI unless a license key has been added, so no native GUI logs were available to check for indicators. However, exploitation of the issue was observable in filesystem logs located at
/bsc/logs/output.master. Specifically, you could check for the line
Running configApplianceXml as long as the attacker has not cleared out this log file.
Arbitrary file write vulnerabilities can be abused in several ways to obtain remote code execution. In this case, we write a cron job to
/etc/cron.d/, but attackers could also overwrite and binary on the system that is regularly executed or SSH keys to a user profile.