WIP: Fun with the Foscam FI9853EP

From OISecWiki

A few months ago I acquired a Foscam FI9853EP v2 IP Camera. It's a low budget cheap outdoor cam, which seems to do it's job marginally well. There are some quirks, but at EUR 66 it's not that bad. After the latest firmware upgrade to 2.84.2.35 (system firmware 1.12.5.4) it seems the cam started to show problems providing a RTSP stream towards my Shinobi setup. After some tinkering it started working again.

The Foscam firmware update images are well-known encrypted with OpenSSL. There is a list of keys available that work for most Foscam Firmware images. The list is embedded in a python script to decrypt the firmware images. The firmware images it self are gzipped tarballs containing all update files. The keys it self to decrypt the images can be found in the binaries that run the firmware upgrade. Unfortunately Foscam tried to obfuscate the openssl cmd and the key by using a function called 'ReformString'. Fortunately there is also a python script to deobfuscate the strings.

Trying to run the FI9853EP firmware images through the original decrypt foscam script yielded no results. I've made minor changes to the script which are reflected in the link I posted above. After the change it worked just fine.

To investigate the cam further I bought a second FI9853EP to take it apart and do some analytics on it.

The opened camera with the POE module on top

The camera contains of 2 boards, a seperate POE board which sits on top of the Main board including the camera module and processor. The POE board accepts 2 wires from the ethernet connector.

The processor board of the Foscam FI9853EP is actually the processor board of a FI9803PV4 (it is clearly stated on the silkscreen). It contains the following components:

  • HiSilicon Hi3518E - EVC200 - Main Processor
  • Macronix MX25L12805D - 128Mbit SPI NOR Flash
  • Realtek RTL8201E - Ethernet 10/100 PHY

The FI9803PV4 is a Wifi Enabled camera, but the FI9853EP lacks the WIFI components, presumably it is connected using USB and is probably a RT2870AP based model.

Camera main board

It seems there is no UART available on the board. The 4 pads in the top right corner don't seem to be serial (after probing it with my Rigol Oscilloscope in RS232 decode mode at 115200 baud). It seems the traces go directly to the SPI flash module. So with no direct access to the system I decided to dump the flash contents for analysis.

After desoldering the flash module and hooking it up to my buspirate v3 it was easy to acquire the SPI flash contents using flashrom.

cliff@pell:~/Projects/foscam$ flashrom -V -p buspirate_spi:dev=/dev/ttyUSB0,spispeed=1M -c MX25L12805D --read foscam.bin
flashrom v0.9.9-r1954 on Linux 4.18.0-16-generic (x86_64)
flashrom is free software, get the source code at https://flashrom.org

flashrom was built with libpci 3.3.1, GCC 5.3.1 20160424, little endian
Command line (7 args): flashrom -V -p buspirate_spi:dev=/dev/ttyUSB0,spispeed=1M -c MX25L12805D --read foscam.bin
Initializing buspirate_spi programmer
Detected Bus Pirate hardware v3b
Detected Bus Pirate firmware 5.10
Using SPI command set v2.
SPI speed is 1MHz
Raw bitbang mode version 1
Raw SPI mode version 1
The following protocols are supported: SPI.
Probing for Macronix MX25L12805D, 16384 kB: probe_spi_rdid_generic: id1 0xc2, id2 0x2018
Found Macronix flash chip "MX25L12805D" (16384 kB, SPI) on buspirate_spi.
Chip status register is 0x00.
Chip status register: Status Register Write Disable (SRWD, SRP, ...) is not set
Chip status register: Bit 6 is not set
Chip status register: Block Protect 3 (BP3) is not set
Chip status register: Block Protect 2 (BP2) is not set
Chip status register: Block Protect 1 (BP1) is not set
Chip status register: Block Protect 0 (BP0) is not set
Chip status register: Write Enable Latch (WEL) is not set
Chip status register: Write In Progress (WIP/BUSY) is not set
This chip may contain one-time programmable memory. flashrom cannot read
and may never be able to write it, hence it may not be able to completely
clone the contents of this chip (see man page for details).
Reading flash... 

The extracted SPI flash can be found here.

The flash exists of 5 regions:

Name Size Description
boot 512K U-Boot
kernel 3M Linux Kernel 3.4.35
app 11M SquashFS Filesystem
app_ext 1M JFFS2 Filesystem
para 512K Multiple JFFS2 Filesystems, contains rom images + data + configuration files


Using  binwalk to extract recognized files gave me all the contents of the flash split out per file. Analyzing the firmwareupgrade binary resulted in the knowledge that the decrypt and deobfuscate python scripts worked just fine and contained the correct OpenSSL key for the camera. However OpenSSL defaulted to a different hash and for some reason the stated md5 didn't work. Running a manual decrypt on the firmware upgrade binaries resulted in a decrypted binary ready to unpack. Foscam binaries and configuration files are encrypted using aes-128-cbc with md5 as its message digest.

Kernel Region

When extracting the cpio archive that resides inside the kernel image we find there are 2 passwd files (/etc/passwd and /etc/passwd-).

cliff@pell:~/Projects/foscam/cpio-root/etc$ cat passwd 
root:$1$uYfJBoag$N8ofdlVBVcfzOY7utbTfo0:0:0::/root:/bin/sh 
cliff@pell:~/Projects/foscam/cpio-root/etc$ cat passwd- 
root:ab8nBoH3mb8.g:0:0::/root:/bin/sh

/etc/passwd- is DES encrypted and contains 1 entry for root. A quick round through john reveals that the password is 'helpme'. Unfortunately the real passwd file is using md5 crypt and the password helpme is not used there.

App Region

Running deobfuscate-foscam.py on the webService daemon reveiled the passwords used for encrypting and decrypting the configuration backup files (mind the default openssl message digest used by foscam is md5 as they are using an older OpenSSL version):

File: FI9853EP-flash/_foscam.bin.extracted/webService 
Deobfuscated: openssl enc -d -aes-128-cbc -k BpP+2R9*Q -in %s > % 

The same goes for the firmwareUpgrade binary:

File: FI9853EP-flash/_foscam.bin.extracted/FirmwareUpgrade
Deobfuscated: openssl enc -d -aes-128-cbc -k WWeift*v2 -in %s > %

Para Region

The para partition contains the configuration files encapsulated in JFFS2 filesystems. Here also resides the rom.dat file which contains the MAC address to be used. Furthermore there is a set of configuration files that are binary while most others are XML files. Checking the webService daemon makes it obvious that these files are encrypted (aes-128-cbc) binary equivalents of their XML variants (which are not in the para region).

The files are not encrypted with the openssl binary as the other files are, but are internally encrypted inside webService using libEncrypt.so. The AES key used is 'M0i*P2jK_' which we acquired using the following basic program. The values entered are derived from using IDA Pro on the LibEncrypt.so binary and some reverse engineering of the ReformString function:

#include <stdio.h>

int main () {
    char decryptString[96] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@#$%^&*()_+|`-+={}[]:;'<>?,./\" ";

    printf ("%c",decryptString[38]);
    printf ("%c",decryptString[52]);
    printf ("%c",decryptString[8]);
    printf ("%c",decryptString[70]);
    printf ("%c",decryptString[41]);
    printf ("%c",decryptString[54]);
    printf ("%c",decryptString[9]);
    printf ("%c",decryptString[36]);
    printf ("%c",decryptString[73]);
}

I am still figuring out the IV used to encrypt the XML files.

-- work in progress --

After resoldering the flash module back in place and reassembling the camera it worked fine again, so no brick on my desk ;)

Frank Spierings contacted me because he did his own research. His research can be found here: https://gist.github.com/FrankSpierings/9ad86cd77a62b0b6b67f94157908be61

References used:

  1. https://herrfeder.github.io/embeddedsec/2017/10/19/Hacking-A-IP-Camera-Part1.html
  2. https://github.com/mcw0/PoC
  3. http://www.macronix.com/Lists/Datasheet/Attachments/7447/MX25L12833F,%203V,%20128Mb,%20v1.0.pdf