For the past several months, VDOO’s security research teams have been undertaking broad-scale security research of leading IoT products, from the fields of safety and security. In most cases, the research was carried out together with the device vendors for the sake of efficiency and transparency.
As part of this research, VDOO researchers found zero-day vulnerabilities in devices of several vendors. These vulnerabilities were disclosed to the vendors, in accordance with responsible disclosure best practices, and will be shared gradually after the disclosure periods are concluded.
One of the vendors for which we found vulnerable devices was Foscam. Our team discovered a critical chain of vulnerabilities in Foscam security cameras. Combining the discovered vulnerabilities, an adversary who successfully obtains the address of the camera, can remotely gain root access to the cameras (via LAN or internet). VDOO has responsibly disclosed these vulnerabilities (CVE-2018-6830, CVE-2018-6831 and CVE-2018-6832) and engaged with Foscam’s security team to solve the matter.
VDOO’s security research team enjoyed full collaboration and transparency with Foscam and are appreciative of their openness in sharing the information discovered with the security community. This constitutes a meaningful contribution to the IoT industry as a whole and specifically to the privacy and security of Foscam’s customers.
To the best of our knowledge, these vulnerabilities were not exploited in the field, and therefore, did not lead to any concrete privacy violation or security threat to Foscam customers. The Foscam team acted promptly to patch these vulnerabilities and push them to the vulnerable products.
We strongly recommend that Foscam customers who did not update their cameras do so immediately or mitigate the risk in alternative ways. See instructions in FAQ section below.
We also recommend that other camera vendors follow our recommendations at the end of this report to avoid and mitigate similar threats.
VDOO is a technology driven company that strives to change the reality of unprotected connected devices. VDOO is building a line of products to support device manufacturers in embedding security into their connected devices at the development stage and enable post-development security.
In addition to developing products and services, VDOO invests significant efforts in wide scope research of connected devices. Safety and security products are two of the focus groups of this research.
VDOO’s research goal is to contribute knowledge and tools to mitigate risks, as well as encourage device vendors to implement the right security for their products. We at VDOO believe that an appropriate implementation of the security essentials will dramatically decrease the chances of exploiting vulnerabilities on the device.
This is a first of a series of blogs that will cover technical deep dives as part of our wide scope research. Stay tuned.
The camera is running a Linux operating system and all processes run with root privileges. The web server is a lighttpd with additional vendor code, and it forwards API requests to its internal CGIProxy.fcgi process, by using the FastCGI protocol. The CGIProxy.fcgi executable forwards requests (by using a proprietary IPC mechanism) to the webService process – that verifies the user’s credentials (if needed) and runs the handler for the desired API command. Depending on the command, the handler may call additional code from the devMng process, that in turn usually runs shell commands by using the system() or popen() library calls, to configure system services. A watchdog daemon restarts important processes after they are terminated.
The attack scenario on a network-accessible camera is as follows:
This section provides the details of each vulnerability and explains the full attack sequence.
This vulnerability allows an attacker to delete arbitrary files from the camera’s filesystem, by crafting a special GET request to the camera’s Web management interface; no user credentials are required.
This vulnerability is related to custom vendor code added to the open source lighttpd web server code. The function of this code is to delete temporary snapshot pictures taken using the snapPicture API command immediately after they are uploaded from the camera to the user (the same functionality is assigned to the exportConfig API command).
When a GET request is sent to the web server (over port 88), after processing the request, the request’s URI path component (con->request.uri->ptr) is searched for either the string /configs/export/ or /snapPic/. If the request contains one of these strings, the server uses the strncat function to combine the the document-root path /tmp/www with the URI’s path component to form a full path. It then verifies the existence of the file (by calling access(path, F_OK)) and proceeds to delete the file by calling remove(path).
This code suffers from a path-traversal vulnerability, by which an attacker can use dot-dot-slash (‘…/’) sequences in the GET request that will end in the con->request.uri->ptr component. Since the /snapPic/ directory already exists in the server’s document-root, the attacker can use the /snapPic/ URI as a valid path that will also trigger execution of this code branch. The attacker then continues adding dot-dot-slash sequences to travel up the directory tree until reaching the root directory (‘/’), and then add the path for the file to be deleted. For example, the URI /snapPic/…/…/…/tmp/abc indicates that the file /tmp/abc, if exists, will be deleted.
This PoC shows how we use the vulnerability to delete an arbitrary file from the device. The _FILE_TO_DELETE shell variable holds a file’s absolute path.
This vulnerability allows an attacker to crash the device’s webService process. It is triggered by sending a specially crafted GET request to the camera’s Web management interface, without the need for any user credentials.
The camera’s web-server offers a FastCGI API with many commands. Among the possible commands is the getSWFlag command, which is invoked by sending an unauthenticated HTTP GET request to /CGIProxy.fcgi?cmd=getSWFlag. The GET request parameters are forwarded from the CGIProxy.fcgi process to webService‘s getSWFlag function code (let’s call it getSWFlag_func). getSWFlag_func can optionally receive a query-string parameter named callbackJson.
getSWFlag_func first reads the value of the callbackJson parameter to a local variable, callbackJson_var, of size 0x400 bytes on the stack. This is done by invoking the get_param function with a reference to callbackJson_var, with a size limit of up to 0x400 characters.
After that, getSWFlag invokes the prepare_reply_func function with a reference to callbackJson_var. This function prepares some of the HTTP response that will be sent back to the user.
If callbackJson_var isn’t an empty string – prepare_reply_func appends various string data to the callbackJson_var string in place (at its original location on the stack of getSWFlag_func) using strcat. In total approximately 0x48 characters are added. (the appended string is:'({“key”:”<CGI_Result><result>0</result><flag>0011</flag></CGI_Result>”})’).
Thus, if an attacker sets the value of the query string’s parameter, callbackJson to hold enough characters (above a certain threshold), the resulting concatenation generated by prepare_reply_func will cause an overflow of callbackJson_var in the stack for getSWFlag_func. Writing a large number of bytes will cause an overwriting of saved stack registers (including the PC register) and cause a crash. Thus, the attacker can crash the webService process, which leads to a restart of this process a few seconds later by the /usr/bin/watchdog process.
This vulnerability requires administrator credentials, which were achieved in the previous stages. It allows an attacker to execute commands as the root user, for escalating privileges. It bypasses a patch of an older vulnerability, CVE-2017-2879, disclosed by Cisco Talos, in June 2017.
The camera’s web-server FastCGI API includes a command for setting a custom NTP server (/CGIProxy.fcgi?cmd=setSystemTime). This command requires administrator credentials. The parameter ntpServer, required by this command, holds the string value to be used to set the NTP_Server_URL. This parameter is not sanitized of special characters and can even contain spaces and semicolons.
When the API command setSystemTime is called, CGIProxy.fcgi forwards the request to the webService process, which reads its parameters and sends an IPC message that invokes the devMng function OnDevMngMsgSetSystemTime (command 0x6034).
Among other things, OnDevMngMsgSetSystemTime sets the new NTP_Server_URL in a global structure.
A separate thread, NTP update thread, within devMng, runs the setSystemTimeNTP function once every second in an infinite loop.
setSystemTimeNTP takes the NTP_Server_URL value from the global structure (set earlier) and calls gethostbyname(NTP_Server_URL) using this value. If the hostname is successfully resolved, it proceeds to call the following vulnerable code: sprintf(buf, “ntpclient -h %s -c 3 -s”, NTP_Server_URL); and popen(buf, “r”); (see IDA screenshot below).
The popen function runs a shell command by running sh -c with the provided string argument. If we set NTP_Server_URL to be ;SOME_COMMAND;, and could bypass the gethostbyname(NTP_Server_URL) call – popen would then call sh -c “ntpclient -h ;SOME_COMMAND; -c 3 -s”. The semicolon facilitates breaking the shell command and causing a command injection. As the devMng process runs as root, we will be able to run any command as the root user.
As noted earlier, it is our understanding that the code that proceeds only upon a successful gethostbyname() call was added in order to patch the CVE-2017-2879 vulnerability. Our speculation is that the patch authors assumed that using the gethostbyname() call would be a sufficient solution to sanitize the input of NTP_Server_URL. We refuted this assumption, as we observed that uclibc’s (the camera’s C standard library) gethostbyname() implementation does not fail to resolve hostnames that include semi-colons or spaces.
In order to bypass the gethostbyname call, we perform the following steps (see corresponding step numbers in the ‘CVE-2018-6831 Steps’ diagram below):
Preparations for the vulnerability – Setting up a Bind9 DNS server with the following configuration:
Setting the camera’s DNS Server to point to our DNS server: (using the administrator’s username and password)
Triggering the vulnerability (we chose to execute a telnet server and then connect to it):
Below is also a screenshot from Wireshark – showing the DNS traffic emitted throughout the attack.
We would like to relate to some bad architectural practices that were found in the cameras analyzed in this research, that make it easier for an attacker to discover and exploit vulnerabilities. We encourage device makers to take the below recommendations into consideration.
We would like to thank Foscam’s security team for efficiently and promptly handling this security issue.
Or Peles (@peles_o), VDOO
You need to check that your camera’s firmware is at least the version appearing in ‘Table I’ below with the associated security patch. To check which firmware version your camera uses, you can do the following:
Method 1
Method 2
If you have multiple devices, it may be worthwhile to retrieve the firmware programmatically by issuing the following command:
curl “<Camera IP Address>:88/cgi-bin/CGIProxy.fcgi?cmd=getDevInfo&usr=admin&pwd=<Password>
For example:
curl “192.168.0.200:88/cgi-bin/CGIProxy.fcgi?cmd=getDevInfo&usr=admin&pwd=abc1234
The reply should look like this:
<CGI_Result>
<result>0</result>
<productName>FI9816P+V3</productName>
<serialNo>0000000000000001</serialNo>
<devName>Acme</devName>
<mac>00626E860232</mac>
<year>2018</year>
<mon>5</mon>
<day>25</day>
<hour>19</hour>
<min>40</min>
<sec>19</sec>
<timeZone>0</timeZone>
<firmwareVer>2.81.2.29</firmwareVer>
<hardwareVer>1.12.5.2</hardwareVer>
<pkgTime>2017-06-15_17%3A21%3A35</pkgTime>
</CGI_Result>
Look for the line with “firmwareVer”.
These are the latest vulnerable firmware versions. The addition of a corresponding patch mitigates the vulnerabilities.
Camera models Application firmware version
C1 Lite V3 2.82.2.33
C1 V3 2.82.2.33
FI9800P V3 2.84.2.33
FI9803P V4 2.84.2.33
FI9816P V3 2.81.2.33
FI9821EP V2 2.81.2.33
FI9821P V3 2.81.2.33
FI9826P V3 2.81.2.33
FI9831P V3 2.81.2.33
FI9851P V3 2.84.2.33
FI9853EP V2 2.84.2.33
C1 2.52.2.47
C1 V2 2.52.2.47
C1 Lite 2.52.2.47
C1 Lite V2 2.52.2.47
FI9800P 2.54.2.47
FI9800P V2 2.54.2.47
FI9803P V2 2.54.2.47
FI9803P V3 2.54.2.47
FI9815P 2.51.2.47
FI9815P V2 2.51.2.47
FI9816P 2.51.2.47
FI9816P V2 2.51.2.47
FI9851P V2 2.54.2.47
R2 2.71.1.59
C2 2.72.1.59
R4 2.71.1.59
FI9900EP 2.74.1.59
FI9900P 2.74.1.59
FI9901EP 2.74.1.59
FI9961EP 2.72.1.59
FI9928P 2.74.1.58
FI9803EP 2.22.2.31
FI9803P 2.24.2.31
FI9853EP 2.22.2.31
FI9851P 2.24.2.31
FI9821P V2 2.21.2.31
FI9826P V2 2.21.2.31
FI9831P V2 2.21.2.31
FI9821EP 2.21.2.31
FI9821W V2 2.11.1.120
FI9818W V2 2.13.2.120
FI9831W 2.11.1.120
FI9826W 2.11.1.120
FI9821P 2.11.1.120
FI9831P 2.11.1.120
FI9826P 2.11.1.120
FI9805W 2.14.1.120
FI9804W 2.14.1.120
FI9804P 2.14.1.120
FI9805E 2.14.1.120
FI9805P 2.14.1.120
FI9828P 2.13.1.120
FI9828W 2.13.1.120
FI9828P V2 2.11.1.133
As botnet malware is normally crafted to go undetected, there’s no easy way to know for sure. Any suspicious change to the device may indicate the existence of a botnet malware on your device.
A few ways to check:
At the time of publication, we are not aware of any malware abusing this issue. If you suspect your device is breached, restore the camera to its factory settings. Doing so will restore the configuration to default settings, allowing you to connect and upgrade the firmware. Keep in mind that if you’re using a firmware susceptible to the vulnerabilities detected by VDOO, the device might be targeted and can become infected again shortly. So, after resetting the device, make sure to immediately perform the firmware upgrade, prior to connecting the camera directly to the internet.
In order to reduce the camera’s exposure and the ability to manage it remotely, it is recommended to place the device behind a firewall blocking port 88 and 443 (or the ports specified in the camera’s configuration) and consider not allowing the camera to initiate any outbound connections (please keep in mind, this could affect the Foscam cloud service). Another option is to put the device behind a reverse proxy that blocks the URLs we are using for the exploit (see above for additional details). Please contact [email protected] if additional help is necessary.
Click here to find the vendor’s instructions for firmware update.