Vulnerabilities > CVE-2017-2877 - Improper Handling of Exceptional Conditions vulnerability in Foscam C1 Firmware 2.52.2.43

047910
CVSS 7.5 - HIGH
Attack vector
NETWORK
Attack complexity
LOW
Privileges required
NONE
Confidentiality impact
PARTIAL
Integrity impact
PARTIAL
Availability impact
PARTIAL
network
low complexity
foscam
CWE-755

Summary

A missing error check exists in the Multi-Camera interface used by the Foscam C1 Indoor HD Camera running application firmware 2.52.2.43. A specially crafted request on port 10001 could allow an attacker to reset the user accounts to factory defaults, without authentication.

Vulnerable Configurations

Part Description Count
OS
Foscam
1
Hardware
Foscam
1

Seebug

bulletinFamilyexploit
description### Summary A missing error check exists in the Multi-Camera interface used by the Foscam C1 Indoor HD Camera running application firmware 2.52.2.43. A specially crafted request on port 10001 could allow an attacker to reset the user accounts to factory defaults, without authentication. ### Tested Versions * Foscam Indoor IP Camera C1 Series * System Firmware Version: 1.9.3.18 * Application Firmware Version: 2.52.2.43 * Plug-In Version: 3.3.0.26 ### Product URLs http://www.foscam.com/downloads/index.html ### CVSSv3 Score 9.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H ### CWE CWE-392: Missing Report of Error Condition ### 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. The device has a Multi-Camera feature that allows cameras to communicate with each other, in order to display multiple streams on a unique web interface. Communication between cameras happen on UDP ports 10000 and 10001 and is handled by the binary "devMng". `sub_29A98` is the threaded function that manages incoming messages on both ports using `select` [1]. If a message is sent to port 10001, the function `multicamera_p10001` is called [2]. ``` .text:00029A98 sub_29A98 .text:00029A98 .text:00029A98 F0 45 2D E9 STMFD SP!, {R4-R8,R10,LR} .text:00029A9C 10 30 A0 E3 MOV R3, #0x10 .text:00029AA0 71 DF 4D E2 SUB SP, SP, #0x1C4 .text:00029AA4 BC 31 8D E5 STR R3, [SP,#0x1E0+var_24] .text:00029AA8 5C 33 9F E5 LDR R3, =0x3DE .text:00029AAC 00 30 8D E5 STR R3, [SP,#0x1E0+timeout] .text:00029AB0 58 33 9F E5 LDR R3, =aStartListenDis ; "Start listen discovery port" .text:00029AB4 00 40 A0 E1 MOV R4, R0 .text:00029AB8 04 30 8D E5 STR R3, [SP,#0x1E0+addr_len] .text:00029ABC 06 00 A0 E3 MOV R0, #6 .text:00029AC0 4C 33 9F E5 LDR R3, =aIpcamdiscovery ; "IPCamDiscovery/CIPCamDiscovery.cpp" .text:00029AC4 03 10 A0 E3 MOV R1, #3 .text:00029AC8 48 23 9F E5 LDR R2, =(aMayNotBeAvaila+0x19) .text:00029ACC 06 A4 FF EB BL _Z8wirteLogiiPKcS0_iS0_z ... .text:00029BC0 01 0B A0 E3 MOV R0, #0x400 .text:00029BC4 05 20 A0 E1 MOV R2, R5 .text:00029BC8 05 30 A0 E1 MOV R3, R5 .text:00029BCC B0 51 8D E5 STR R5, [SP,#0x1E0+var_30] .text:00029BD0 C6 A2 FF EB BL select ; [1] .text:00029BD4 05 00 50 E1 CMP R0, R5 .text:00029BD8 78 00 00 0A BEQ loc_29DC0 .text:00029BDC 0B 00 00 AA BGE loc_29C10 ... .text:00029C10 loc_29C10 ... .text:00029C30 28 00 00 0A BEQ loc_29CD8 ... .text:00029C50 04 30 8D E5 STR R3, [SP,#0x1E0+addr_len] .text:00029C54 0C 00 94 E5 LDR R0, [R4,#0xC] .text:00029C58 08 10 A0 E1 MOV R1, R8 ; buffer .text:00029C5C 01 2C A0 E3 MOV R2, #0x100 .text:00029C60 05 30 A0 E1 MOV R3, R5 .text:00029C64 00 70 8D E5 STR R7, [SP,#0x1E0+timeout] .text:00029C68 20 A4 FF EB BL recvfrom ... .text:00029CB8 E5 FE FF EB BL multicamera_p10000 ... .text:00029CD8 loc_29CD8 ... .text:00029D18 04 30 8D E5 STR R3, [SP,#0x1E0+addr_len] .text:00029D1C 54 00 94 E5 LDR R0, [R4,#0x54] .text:00029D20 08 10 A0 E1 MOV R1, R8 ; buffer .text:00029D24 01 2C A0 E3 MOV R2, #0x100 .text:00029D28 07 30 A0 E1 MOV R3, R7 .text:00029D2C 00 50 8D E5 STR R5, [SP,#0x1E0+timeout] .text:00029D30 EE A3 FF EB BL recvfrom ... .text:00029D80 35 FE FF EB BL multicamera_p10001 ; [2] ``` `multicamera_p10001` receives the "CIPCamDiscovery" object [3], the message [4] and its length [5] as parameters. The message header "MO_I" is checked [6] and the 16bit command identifier is extracted [7]. If the "discovery" command ("0x0064") is used [8], the 32bit payload size is extracted and verified against the length of the whole message minus 0x17 (the header length) [9]. If all checks are passed, the function `sub_281FC` is called [10] passing the message payload as second parameter [11]. ``` .text:0002965C multicamera_p10001 .text:0002965C .text:0002965C F0 45 2D E9 STMFD SP!, {R4-R8,R10,LR} .text:00029660 00 A0 53 E2 SUBS R10, R3, #0 .text:00029664 4C D0 4D E2 SUB SP, SP, #0x4C .text:00029668 00 60 A0 E1 MOV R6, R0 ; [3] .text:0002966C 01 40 A0 E1 MOV R4, R1 ; [4] .text:00029670 02 50 A0 E1 MOV R5, R2 ; [5] .text:00029674 68 70 9D E5 LDR R7, [SP,#0x68+arg_0] .text:00029678 60 00 00 0A BEQ loc_29800 .text:0002967C 00 00 51 E3 CMP R1, #0 .text:00029680 00 00 52 13 CMPNE R2, #0 .text:00029684 00 30 A0 13 MOVNE R3, #0 .text:00029688 01 30 A0 03 MOVEQ R3, #1 .text:0002968C 09 00 00 1A BNE loc_296B8 ... .text:000296B8 loc_296B8 .text:000296B8 40 80 8D E2 ADD R8, SP, #0x68+dest ... .text:000296D0 08 00 A0 E1 MOV R0, R8 .text:000296D4 64 11 9F E5 LDR R1, =aMo_i ; "MO_I" .text:000296D8 E1 A5 FF EB BL strcmp ; [6] .text:000296DC 00 80 50 E2 SUBS R8, R0, #0 .text:000296E0 46 00 00 1A BNE loc_29800 .text:000296E4 04 30 D4 E5 LDRB R3, [R4,#4] .text:000296E8 05 20 D4 E5 LDRB R2, [R4,#5] .text:000296EC 02 34 83 E1 ORR R3, R3, R2,LSL#8 .text:000296F0 03 38 A0 E1 MOV R3, R3,LSL#16 .text:000296F4 43 38 B0 E1 MOVS R3, R3,ASR#16 ; [7] .text:000296F8 02 00 00 0A BEQ loc_29708 .text:000296FC 64 00 53 E3 CMP R3, #0x64 .text:00029700 47 00 00 1A BNE loc_29824 .text:00029704 28 00 00 EA B loc_297AC ; [8] ... .text:000297AC loc_297AC .text:000297AC 0F 30 D4 E5 LDRB R3, [R4,#0xF] .text:000297B0 10 20 D4 E5 LDRB R2, [R4,#0x10] .text:000297B4 02 24 83 E1 ORR R2, R3, R2,LSL#8 .text:000297B8 11 30 D4 E5 LDRB R3, [R4,#0x11] .text:000297BC 03 28 82 E1 ORR R2, R2, R3,LSL#16 .text:000297C0 12 30 D4 E5 LDRB R3, [R4,#0x12] .text:000297C4 03 2C 82 E1 ORR R2, R2, R3,LSL#24 .text:000297C8 17 30 82 E2 ADD R3, R2, #0x17 .text:000297CC 03 00 55 E1 CMP R5, R3 ; [9] .text:000297D0 0C 00 00 0A BEQ loc_29808 ... .text:00029808 loc_29808 .text:00029808 06 00 A0 E1 MOV R0, R6 .text:0002980C 17 10 84 E2 ADD R1, R4, #0x17 ; [11] .text:00029810 0A 30 A0 E1 MOV R3, R10 .text:00029814 00 70 8D E5 STR R7, [SP,#0x68+var_68] .text:00029818 77 FA FF EB BL sub_281FC ; [10] ``` `sub_281FC` allows for resetting the user accounts in the device, given a valid "authResetKey" is supplied. Usually this key can be retrieved with the CGI command "getAuthResetKey", which is in charge of generating a random key and to send it to the "devMng" process, which stores it in a global variable. To invoke this CGI command, administrator privileges are required. At [12] the key, passed as second parameter, is stored in `%r5`. At [13] the expected key buffer is stored in `%r4` and is cleared [14]. The function `sub_2C878` is then called passing a global structure [15] and the expected key buffer as arguments. ``` .text:000281FC sub_281FC .text:000281FC .text:000281FC 30 40 2D E9 STMFD SP!, {R4,R5,LR} .text:00028200 00 50 51 E2 SUBS R5, R1, #0 ; [12] .text:00028204 24 D0 4D E2 SUB SP, SP, #0x24 .text:00028208 06 00 00 1A BNE loc_28228 ... .text:00028228 loc_28228 .text:00028228 00 00 53 E3 CMP R3, #0 .text:0002822C 0A 00 00 1A BNE loc_2825C ... .text:0002825C loc_2825C .text:0002825C 10 40 8D E2 ADD R4, SP, #0x30+s ; [13] .text:00028260 0F 20 A0 E3 MOV R2, #0xF .text:00028264 04 00 A0 E1 MOV R0, R4 .text:00028268 00 10 A0 E3 MOV R1, #0 .text:0002826C 57 AA FF EB BL memset ; [14] .text:00028270 04 10 A0 E1 MOV R1, R4 .text:00028274 B0 00 9F E5 LDR R0, =dword_8F6F8 ; [15] .text:00028278 7E 11 00 EB BL sub_2C878 ``` `sub_2C878` copies the expected key from the global structure to the buffer if the "authResetKey" is set [16]. If not, the function prints an error, but the return value is 0 in both cases. ``` .text:0002C878 sub_2C878 .text:0002C878 00 30 A0 E1 MOV R3, R0 .text:0002C87C 00 00 51 E2 SUBS R0, R1, #0 .text:0002C880 10 40 2D E9 STMFD SP!, {R4,LR} .text:0002C884 00 00 E0 03 MOVEQ R0, #0xFFFFFFFF .text:0002C888 10 80 BD 08 LDMEQFD SP!, {R4,PC} .text:0002C88C 08 10 93 E5 LDR R1, [R3,#8] .text:0002C890 00 40 D1 E5 LDRB R4, [R1] .text:0002C894 00 00 54 E3 CMP R4, #0 .text:0002C898 03 00 00 1A BNE loc_2C8AC .text:0002C89C 14 00 9F E5 LDR R0, =aGetdevauthrese ; "getDevAuthResetKey error, authResetKey have not set !" .text:0002C8A0 B7 99 FF EB BL printf .text:0002C8A4 04 00 A0 E1 MOV R0, R4 .text:0002C8A8 10 80 BD E8 LDMFD SP!, {R4,PC} .text:0002C8AC .text:0002C8AC loc_2C8AC .text:0002C8AC FF 99 FF EB BL strcpy ; [16] .text:0002C8B0 00 00 A0 E3 MOV R0, #0 .text:0002C8B4 10 80 BD E8 LDMFD SP!, {R4,PC} ``` Back in the parent function, there's no way to check whether the previous call was successful or not: the execution continues and the key and expected key buffers are compared [17]. If equal, the password reset request is sent via an IPC call with code 0x4028 [18]: this invokes the function "OnWebServiceMsgRestoreUserAccount" in the "webService" binary, which resets the user accounts to factory defaults. ``` .text:0002827C AC 30 9F E5 LDR R3, =0x2DB .text:00028280 00 30 8D E5 STR R3, [SP,#0x30+var_30] .text:00028284 A8 30 9F E5 LDR R3, =aHandleresetu_1 ; "handleResetUsrPwdReq pResetCmdInfo->key is %s. config Auth key is %s." ... .text:000282A8 04 10 A0 E1 MOV R1, R4 .text:000282AC 05 00 A0 E1 MOV R0, R5 .text:000282B0 EB AA FF EB BL strcmp ; [17] .text:000282B4 00 40 50 E2 SUBS R4, R0, #0 .text:000282B8 0A 00 00 1A BNE loc_282E8 .text:000282BC 74 00 9F E5 LDR R0, =unk_8A480 .text:000282C0 74 10 9F E5 LDR R1, =0x4028 ; [18] .text:000282C4 04 20 A0 E1 MOV R2, R4 .text:000282C8 04 30 A0 E1 MOV R3, R4 .text:000282CC 00 40 8D E5 STR R4, [SP,#0x30+var_30] .text:000282D0 04 40 8D E5 STR R4, [SP,#0x30+var_2C] .text:000282D4 08 40 8D E5 STR R4, [SP,#0x30+var_28] .text:000282D8 0C 40 8D E5 STR R4, [SP,#0x30+var_24] .text:000282DC 36 A9 FF EB BL _ZN10CMsgClient7sendMsgEicPKciiiPc ; CMsgClient::sendMsg(int,char,char const*,int,int,int,char *) .text:000282E0 04 00 A0 E1 MOV R0, R4 .text:000282E4 09 00 00 EA B loc_28310 .text:000282E8 .text:000282E8 loc_282E8 .text:000282E8 50 30 9F E5 LDR R3, =0x2E3 .text:000282EC 00 30 8D E5 STR R3, [SP,#0x30+var_30] .text:000282F0 4C 30 9F E5 LDR R3, =aHandleresetu_2 ; "handleResetUsrPwdReq pResetCmdInfo->key is not match!" .text:000282F4 04 30 8D E5 STR R3, [SP,#0x30+var_2C] .text:000282F8 06 00 A0 E3 MOV R0, #6 .text:000282FC 02 10 A0 E3 MOV R1, #2 .text:00028300 1C 20 9F E5 LDR R2, ="" .text:00028304 1C 30 9F E5 LDR R3, =aIpcamdiscovery .text:00028308 F7 A9 FF EB BL _Z8wirteLogiiPKcS0_iS0_z ; wirteLog(int,int,char const*,char const*,int,char const*,...) .text:0002830C 00 00 A0 E3 MOV R0, #0 .text:00028310 .text:00028310 loc_28310 .text:00028310 24 D0 8D E2 ADD SP, SP, #0x24 .text:00028314 30 80 BD E8 LDMFD SP!, {R4,R5,PC} ``` Because function `sub_2C878` fails to return an error code, an attacker could reset the users' database by sending a request with a 1-byte null value as key. ### Timeline * 2017-07-13 - Vendor Disclosure * 2017-11-13 - Public Release
idSSV:96862
last seen2017-11-19
modified2017-11-14
published2017-11-14
reporterRoot
sourcehttps://www.seebug.org/vuldb/ssvid-96862
titleFoscam IP Video Camera devMng Multi-Camera Port 10001 Command 0x0064 Empty AuthResetKey Vulnerability(CVE-2017-2877)

Talos

idTALOS-2017-0384
last seen2019-05-29
published2017-11-13
reporterTalos Intelligence
sourcehttp://www.talosintelligence.com/vulnerability_reports/TALOS-2017-0384
titleFoscam IP Video Camera devMng Multi-Camera Port 10001 Command 0x0064 Empty AuthResetKey Vulnerability