Talos Vulnerability Report

TALOS-2017-0347

June 19, 2017

CVE Number

CVE-2017-2845

Summary

An exploitable command injection vulnerability exists in the web management interface used by the Foscam C1 Indoor HD Camera running application firmware 2.52.2.37. A specially crafted HTTP request can allow for a user to inject arbitrary shell characters during the SMTP configuration tests resulting in command execution. An attacker can simply send an HTTP request to the device to trigger this vulnerability.

Tested Versions

Product URLs

CVSSv3 Score

8.8 - CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

CWE

CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Details

Foscam produces a series of IP-capable surveillance devices, network video recorders, and baby monitors for the end-user. Foscam produces a range of cameras for both indoor and outdoor use and with wireless capability. One of these models is the C1 series which contains a web-based user interface for management and is based on the ARM architecture. Foscam is considered one of the most common security cameras out on the current market.

When various services are started, a service will first register a callback using the CMsgClient::registerMsgHandle function [1]. This will register a function to be called [2] when another service dispatches a message of the specified code [3]. An example of this registration process is handled inside the FCGI_Init function of the "CGIProxy.fcgi" service using the following code:

After the "CGIProxy.fcgi" service decodes an http request that's forwarded from the http daemon, the service will copy the decoded query into a buffer on the stack [4]. Once this is done, the buffer will then be used to pass the decoded query to CMsgClient::sendMsg. This will dispatch the query to the shared messaging subsystem using the code 0x4001 at [5]. At this point, the service that handles the specified code will be woken up to handle the specified request.

The handler for code 0x4001 is in the "webService" binary and is done by the function executeCGICmd at address 0x1e5a4. At the beginning of this function, the service will call a function [6] that's responsible for extracting the user name, password, and command that was specified within the user's query. Once the parameters have been extracted and copied into a local buffer on the stack, the command will be passed to the function call at [7] in order to determine the correct command function which is stored to funcptr. If authentication is not required for the command, then the branch at [8] will execute the function pointer returned by findJsonCallbackCommand at [7]. If authentication is required from the command, then the user name and password will be checked via strcmp and then the function call at [9] will execute the function pointer.

When handling the "CGIProxy.fcgi" command "smtpTest", the function smtpTest_239bc will be called. This function is responsible for testing the parameters to be used for sending e-mails. The function extracts the parameters for "smtpServer", "port", "isNeedAuth", "tls", "user", "password", "sender" and forwards them via IPC by calling CMsgClient::sendMsg, using the code 0x6069 at [10]. At this point, the service that handles the specified code will be woken up to handle the specified request.

The handler for code 0x6069 is in the "devMng" binary and is done by the function OnDevMngMsgSmtpMailTest_d9e4 at address 0x159e4. This function extracts the product model of the camera and replies to the message with this information. The reply is handled back in the "webService" binary by the function OnWebServiceMsgSmtpMailTestReply_e474 at address 0x16474. This function parses the numeric function arguments ([11] "port", "isNeedAuth", etc.) and calls testSmtpServer_52cf0.

The function testSmtpServer_52cf0 receives 9 parameters: "C1" (the product model), "smtpServer", "sender", "port", "isNeedAuth", "tls", "user", "password" and a pointer to a 128 bytes stack variable. First the function checks if the parameters are non-null, then parses the SMTP server [12], creates the subject of the mail using sprintf [13] and calls sendSmtpTestMail_51f6c [14].

This function takes care of checking again that the parameters are valid by comparing them with null. Then it proceeds to copying the SMTP username and password in local variables [15] [16], and extracting at most 4 recipients from the comma-separated list provided from the user using the "sender" parameter [17]. Note that extract_recipients also allows ";" and " " as separators. Parameters are then collected and passed to the function smtpTestConfigure [18].

smtpTestConfigure takes care of creating "msmtprc" configuration file and populates it with the user-supplied parameters. The execution continues with encoding the mail subject [19], preparing a "/tmp/.mail" file containing the mail contents [20], concatenating the previously extracted recipients and removing any old "/tmp/.msmtp.log" log file [21]. A command string is then built using sprintf [23], resulting in "cat /tmp/.mail | msmtp mailaddr &" where "mailaddr" is the user-supplied "sender" parameter [22], which was not previously sanitized. The resulting string is then passed as an argument to system at [24].