I have a Foscam FI9853EP, which was introduced in 2014 and has long since been obsoleted. One of the things that stands out, is that all firmware is encrypted:
$ file FosIPC_B_patch_ver2.x.2.31_3_20190718_150013.bin FosIPC_B_patch_ver2.x.2.31_3_20190718_150013.bin: openssl enc'd data with salted password
I was curious: what could be in the firmware that needs this amount of protection? Usually, firmwares are plaintext but signed so that you can’t installed any unauthorized software in your device.
My end goal is to be able to decrypt the most recent (2019) firmware. But I’m not there yet.
Finding an UART
There is a lot of information available on how to locate a serial port on the device so you can interact with it. You tend to be looking for a 3-pin or 4-pin header. On the Foscam, there is a 4-pin header close to the ESD warning symbol on the board.
The picture below shows where the header is located. I soldered the second wire using the other side of the board:
Counting pins from left to right, we have:
- Pin 1 = TX
- Pin 2 = GND
- Pin 3 = RX
- Pin 4 = ?
Using a FTDI I had lying around and the standard 115200/8N1 settings, we have a console!
U-Boot, or not yet
It turns out the system uses standard U-Boot. However, there is a catch:
System startup U-Boot 2010.06 (Nov 16 2017 - 11:43:05) Check Flash Memory Controller v100 ... Found SPI Nor(cs 0) ID: 0xc2 0x20 0x18 ##uboot 020sdk patch!## Block:64KB Chip:16MB Name:"MX25L128XX" SPI Nor total size: 16MB MMC: EMMC/MMC/SD controller initialization. Card did not respond to voltage select! No EMMC/MMC/SD device found ! *** Warning - bad CRC, using default environment In: serial Out: serial Err: serial Hisilicon ETH net controler init rmii phy led completed Hit any key to stop autoboot: 1 1st input Passwd:
There is a password protection mechanism in place: whenever you interrupt the boot process, it asks for a password that we don’t have.
Where is the firmware stored and how do we get to it?
If you take a closer look at the picture above, you’ll spot a 8-pin SOIC chip to the right. This chip is a MX25L12835F, which is a 128MBit SPI NOR flash memory IC. This is also what the boot log mentions right before we stop it. This chip will likely contain the firmware.
It would be possible to desolder the IC, dump its content and solder it back. This felt like a lot of work, and I like to avoid soldering if I can help it, since we already have a device that can interact with the IC: the device itself. But to dump the contents of the IC, we either need access from Linux or from U-Boot. The latter is easiest, but we still have that pesky password prompt…
Getting U-Boot shell, the easy way
I had an idea: if I could somehow stop the boot process, it will likely just error out and give me a prompt. To this end, I tried shorting pins 5 (
SI) and 6 (
SCLK) of the flash memory chip with a screwdriver while I powered the device on. Sometimes I was too quick and U-Boot wouldn’t start at all, and usually I was too late and the kernel was already loaded. However, after a few tries, success!
Wrong Image Format for bootm command ERROR: can't get kernel image! hisilicon #
Since I stopped shorting the pins, I can interact with the flash IC now and inspect its contents:
hisilicon # sf probe 0 16384 KiB hi_fmc at 0:0 is now current device hisilicon # sf read Usage: sf read addr offset len hisilicon # sf read 0x82000000 0 0x10000 hisilicon # md.b 0x82000000 0x10000 82000000: 17 04 00 ea 14 f0 9f e5 14 f0 9f e5 14 f0 9f e5 ................ ...
Dumping the flash
The approach above with the
md.b command works, but it’s very slow. I really did not fancy dumping 16MB this way. There is an ethernet port on the device. Let’s see if we can use it:
hisilicon # setenv serverip 192.168.1.1 hisilicon # setenv ipaddr 192.168.1.2 hisilicon # ping 192.168.1.1 MAC: 00-00-23-34-45-66 eth0 : phy status change : LINK=DOWN : DUPLEX=FULL : SPEED=100M eth0 : phy status change : LINK=UP : DUPLEX=FULL : SPEED=100M host 192.168.1.1 is alive
Hooray! The U-Boot is also built with TFTP upload and download capabilities. I decided to dump the flash in 4 parts, as I was getting TFTP errors if I tried to do it in one go and I could easily retransfer the problematic pieces this way.
hisilicon # sf read 82000000 0 400000 hisilicon # tftp 82000000 flash0 400000 hisilicon # sf read 82000000 400000 400000 hisilicon # tftp 82000000 flash400000 400000 hisilicon # sf read 82000000 800000 400000 hisilicon # tftp 82000000 flash800000 400000 hisilicon # sf read 82000000 c00000 400000 hisilicon # tftp 82000000 flashc00000 400000
I can re-combine the flash by just concatenating the flash files together:
$ cat flash0 flash400000 flash800000 flashc00000 > flash.bin
Making sense of the flash
I wanted to split the 16MB flash image up, as it isn’t used as a single blob. Allowing the device to boot and looking at the bootlog revealed the flash layout:
Creating 5 MTD partitions on "hi_sfc": 0x000000000000-0x000000080000 : "boot" 0x000000080000-0x000000380000 : "kernel" 0x000000380000-0x000000e80000 : "app" 0x000000e80000-0x000000f80000 : "app_ext" 0x000000f80000-0x000001000000 : "para"
So we can split it using the following commands:
$ dd if=flash.bin of=boot.mtd ibs=1 skip=0 count=524288 $ dd if=flash.bin of=kernel.mtd ibs=1 skip=524288 count=3145728 $ dd if=flash.bin of=app.mtd ibs=1 skip=3670016 count=11534336 $ dd if=flash.bin of=app_ext.mtd ibs=1 skip=15204352 count=1048576 $ dd if=flash.bin of=para.mtd ibs=1 skip=16252928 count=524288
Let’s see if the resulting images make any sense:
$ file *.mtd app_ext.mtd: Linux jffs2 filesystem data little endian app.mtd: Squashfs filesystem, little endian, version 4.0, xz compressed, 11298912 bytes, 462 inodes, blocksize: 131072 bytes, created: Thu Nov 16 07:51:11 2017 boot.mtd: data kernel.mtd: u-boot legacy uImage, Linux-3.4.35, Linux/ARM, OS Kernel Image (Not compressed), 2976536 bytes, Tue Nov 7 02:41:11 2017, Load Address: 0X80008000, Entry Point: 0X80008000, Header CRC: 0XAF395D8A, Data CRC: 0X36BDB2E2 para.mtd: Linux jffs2 filesystem data little endian
Learning the U-Boot password
The boot.mtd is just a binary data blog, which means it likely contains the bootloader as-is. I decided to look at the strings within to see if there is anything worthwhile, and indeed:
$ strings boot.mtd [...] Hit any key to stop autoboot: %2d %dst input Passwd: ipc.fos~ %2d [...]
1st input Passwd: we find the string
ipc.fos~ ! I decided to try it, and this is indeed the U-Boot password. I no longer have to mess with the pins to get a prompt, and I have the current (factory) firmware of the device.
Next step: extracting data from the images
This post is already long enough, so I’ll leave it at that. However, I plan om extract the images to figure out how the device boots, updates and hopefully learn a thing or two on how to proceed. Stay tuned!