I’ve been watching you.. a lalala long – Reverse Engineering IP cameras (Part 1)

The Foscam FI9816P is a wireless Internet Protocol (IP) camera commonly employed for surveillance and it can send and receive data via a computer network and the Internet. This particular model costs around $70 USD and can help you, according to Foscam, keep an eye on what matters most (a lalalala long).

There are numerous Foscam models out there with critical security vulnerabilities; so, Tasos had the idea to order the new FI19816P model and check if this is the case. The goals of this side project is to undestand how IP cameras work, find bugs and exploit them to get internal access, and dump and backdoor the firmware. In order to achieve all these, the first step is to teardown the camera and look for a serial port. Serial ports are typically used by the embedded system developers for debugging and various other technical support purposes. Access to the serial port interface can allow us to observe the booting process, access the bootloader, check debug messages, and ultimately interact via a shell with the system.

Identifying the serial headers

Most serial port headers have between 4-6 pins (typically 4):

  • Vcc (3.3 V)
  • Ground (GND)
  • Transmit (TXD)
  • Receive (RXD)

Since the UART port is not designed to be utilized by the end users it almost never has pins or connectors attached. After taking a quick look at the board of FI9816P, 3 sets of unused pads call our attention.



Time to get out the multimeter.

Pad 2 (J6) is unlikely to be the UART console. All 4 pins indicate 0 V (metal shielding is a convenient ground point to use for testing). Pad 3 has half of its pins to ground, and half to 5 V. It is also unlikely to be the serial port: the 5 V pins are not steady to 5 V indicating that none of them is Vcc (also, most Foscam models have 3.3 V as the Vcc pin). On the other hand, pad 1 (J5) has a grounded pin and the other pins around 3.3 V (time for a short celebration).

In order to verify that pad 1 is the UART port, JTAGulator  can help us identify the pinout.  JTAGulator is a hardware tool  that can assist in identifying on-chip debug interfaces like JTAG and UART. A logic analyzer, an oscilloscope, or even the variations of the multimeter can also help identify the pins.

Once we have connect the JTAGulator to pad 1 (GND to GND, and the other 3 pins to channels 8-10 of JTAGulator), we set the target system voltage to 3.3 V and issue the :u command to identify the UART pinout.


The JTAgulator permutation results reveal that channel 9 of JTAGulator is connected to TXD and channel 8 to RXD. Among these results, only the 115200 bits per second baudrate returns the 0D hexadecimal ASCII representation of Carriage Return (CR).



The 115200 b/s baudrate is also verified with baudrate.py, a python script that attempts to auto detect the baud rate of an actively transmitting serial port.

Connecting to serial port


Once we have both the pinout and baudrate, we are ready to start communicating with the device. In contrast with pad 2 and 3, we cannot attach headers to the serial port – pad 1 (J5). Therefore, we need to solder the J5 pinout connection.


To verify the correctness of the soldering we use JTAGulator one more time.



Now that we’ve got the hardware setup ready, it’s time to talk to the device. To achieve that, any UART to USB bridge would do the job. We used the 3.3 V C232HD USB – UART cable. In this part, it is important to connect the TXD and RXD pins of the device to RXD and TXD of the UART – USB bridge respectively.


Serial terminal

We are ready to open a serial terminal in our computer and communicate with the IP camera (any serial communication program would do, e.g. screen, minicom, putty, etc.). The video below presents how UART spits out information during the booting of the device.

Hitting any key during the booting process it allows to interrupt the bootloading and get (presumably) a shell after typing the correct password.


Getting the password

A way to get the password is to disassemble the firmware of the FI9816P camera and check if it resides over there. Unfortunately, the firmware of this particular camera model is openssl-encrypted.


Next steps

In order to decrypt the file, both the cipher and the password must be known. So, it seems that the firmware path is a dead end.

If anybody has any ideas how to get the password and thus shell access on the device, it would be greatly appreciated. If not, I am sure we will find a way with Tasos.



Shell Script for Building a Complete GCC Cross-Compiler

This article illustrates how to install on a Debian-based distribution the complete toolchain to cross compile in a shell-script automated way. A short intro In several cases it happens that the platform you’re developing on and the computer you’re developing for don’t match. For instance, you may want to develop an application for ARM or PowerPC on your x86 computer. In order to do that, it is necessary to build a cross-compiler that will enable you to build applications for other targets on your machine i.e. a compiler that knows how to write machine code for your target platform.  The required process to install the compiler is provided in the following bash script: a script to download packages for, configure, build and install a GCC cross-compiler from scratch.


# Author: Charalambos Konstantinou 
# W: http://harryskon.com/
# Github: https://github.com/harryskon/cross_compilers
# This script will download packages for, configure, build and install a GCC cross-compiler.
# Published also @ http://w3-tutorials.com/item/29-shell-script-for-building-a-complete-gcc-cross-compiler

# See http://gcc.gnu.org/install/specific.html for more examples on host and target specifics
# For our case: HOST="x86_64-pc-linux-gnu"

# Choose your target: https://gcc.gnu.org/install/specific.html
# Tried parallel build with e.g. MAKEOPTS="-j 2" but didn't work thus leave it empty

abort() {
 echo "**************************************************************"
 echo error: $@
 echo "**************************************************************"
 exit 1
success() {
 echo "***************************************************************"
 echo success: $@
 echo "***************************************************************"
 echo "\a"
 sleep 3s

# GCC should not be build in the source directory: why? http://gcc.gnu.org/ml/gcc-bugs/2007-06/msg00234.html
prepare_clean_build() {
 rm -rf $BUILDDIR
 mkdir $BUILDDIR


export PATH="$INSTDIR/bin:$PATH"

test -d $CROSSDIR || mkdir $CROSSDIR
test -d $DOWNLOADS || mkdir $DOWNLOADS
test -d $SOURCEDIR || mkdir $SOURCEDIR
test -d $INSTDIR && rm -rf $INSTDIR; mkdir $INSTDIR

# 1. Install binutils (containing the assembler and the linker)
 test -f $BINUTILS.tar.gz || wget http://ftp.gnu.org/gnu/binutils/$BINUTILS.tar.gz
 test -d $BINUTILS || tar -xzf $DOWNLOADS/$BINUTILS.tar.gz
 $SOURCEDIR/$BINUTILS/configure --prefix=$INSTDIR --target=$TARGET --disable-nls --disable-werror
 make $MAKEOPTS all install || abort "building of $BINUTILS failed"
 success "$BINUTILS successfully installed to $INSTDIR"

# 2. Install GMP (GNU multiple precision arithmetic library)
 test -f $GMP.tar.bz2 || wget ftp://gcc.gnu.org/pub/gcc/infrastructure/$GMP.tar.bz2
 test -d $GMP || tar -xjf $DOWNLOADS/$GMP.tar.bz2
 $SOURCEDIR/$GMP/configure --disable-shared --enable-static --prefix=$INSTDIR
 make $MAKEOPTS all install || abort "building of $GMP failed"
 success "$GMP successfully installed to $INSTDIR"

# 3. Install MPFR (library for multiple-precision floating-point computations)
 test -f $MPFR.tar.bz2 || wget ftp://gcc.gnu.org/pub/gcc/infrastructure/$MPFR.tar.bz2
 test -d $MPFR || tar -xjf $DOWNLOADS/$MPFR.tar.bz2
 $SOURCEDIR/$MPFR/configure --disable-shared --enable-static --prefix=$INSTDIR --with-gmp=$INSTDIR
 make $MAKEOPTS all install || abort "building of $MPFR failed"
 success "$MPFR successfully installed to $INSTDIR"

# 4. Install MPC (library for the arithmetic of complex numbers with arbitrarily high precision)
 test -f $MPC.tar.gz || wget ftp://gcc.gnu.org/pub/gcc/infrastructure/$MPC.tar.gz
 test -d $MPC || tar -xzf $DOWNLOADS/$MPC.tar.gz
 $SOURCEDIR/$MPC/configure --disable-shared --enable-static --prefix=$INSTDIR --with-gmp=$INSTDIR --with-mpfr=$INSTDIR
 make $MAKEOPTS all install || abort "building of $MPC failed"
 success "$MPC successfully installed to $INSTDIR"

# 5. Install GCC (version 4 and above need GMP, MPFR and MPC development libraries to be installed)
 test -f $GCC.tar.bz2 || wget http://mirrors.kernel.org/gnu/gcc/$GCC/$GCC.tar.bz2
 test -d $GCC || tar -xjf $DOWNLOADS/$GCC.tar.bz2
 $SOURCEDIR/$GCC/configure --prefix=$INSTDIR --target=$TARGET --disable-nls --disable-libssp --enable-languages="c" --without-headers --with-newlib --with-gmp=$INSTDIR --with-mpfr=$INSTDIR --with-mpc=$INSTDIR
 make $MAKEOPTS all install || abort "building of $GCC failed"
 success "$GCC successfully installed to $INSTDIR"

# 6. Install newlib (library implementation intended for use on embedded systems)
 test -f $NEWLIB.tar.gz || wget ftp://sources.redhat.com/pub/newlib/$NEWLIB.tar.gz
 test -d $NEWLIB || tar -xzf $DOWNLOADS/$NEWLIB.tar.gz
 $SOURCEDIR/$NEWLIB/configure --prefix=$INSTDIR --target=$TARGET --disable-nls
 make $MAKEOPTS all install || abort "building of $NEWLIB failed"
 success "$NEWLIB successfully installed to $INSTDIR"

echo "Use cross-compiler by typing:"
echo "$INSTDIR/bin/$TARGET-gcc sourcefile.c"
echo "For more options type: $INSTDIR/bin/$TARGET-gcc --help"
echo "For example: include the -msim option to choose the specific (ppc) machine type"

How to Build Cross Compilers for Embedded Systems

The following steps explain how to build a cross compiler on your *nix machine:

Download the following sources

Set environment variables

Before setting the environment variables you have to choose your target: in this tutorial our target is powerpc-eabi (Embedded PowerPC system in big endian mode). Check here for other targets.

% export TARGET=powerpc-eabi
% export PREFIX=/usr/local/$TARGET #specify the PATH you want the cross-compiled binaries
% export PATH=$PATH:$PREFIX/bin

Compiling and installing binutils

% tar xzfv binutils-2.25.tar.gz
% mkdir build-binutils
% cd build-binutils
% ../binutils-2.25/configure --target=$TARGET --prefix=$PREFIX
% make all
% make install

Compiling and installing GCC

% tar xjfv gcc-4.8.4.tar.bz2
% mkdir build-gcc
% cd build-gcc
% ../gcc-4.8.4/configure --target=$TARGET --prefix=$PREFIX --without-headers --with-newlib --with-gnu-as --with-gnu-ld
% make all-gcc
% make install-gcc

Compiling and installing newlib

% tar xzfv newlib-2.2.0-1.tar.gz
% mkdir build-newlib
% cd build-newlib
% ../newlib-2.2.0-1/configure --target=$TARGET --prefix=$PREFIX
% make all
% make install

Reconfigure GCC with newlib

% cd build-gcc
% ../gcc-4.8.4/configure --target=$TARGET --prefix=$PREFIX --with-newlib --with-gnu-as --with-gnu-ld --disable-shared --disable-libssp
% make all
% make install

Compiling and installing GDB with PSIM (Emulator of the PowerPC Architecture)

% tar xjfv gdb-7.8.2.tar.bz2
% mkdir build-gdb
% cd build-gdb
% ../gdb-7.8.2/configure --target=$TARGET --prefix=$PREFIX –enable-sim-powerpc --enable-sim-stdio
% make all
% make install

Done! Let’s test our tool chain (-m options here)

% powerpc-eabi-gcc -mcpu=440 hw.c -o hw -msim
% powerpc-eabi-run hello

Disassemble firmware completely (rebuild functions in IDA)

The first steps after acquiring the firmware of an embedded system are mainly to:

  1. determine the processor of the device,
  2. disassemble the firmware image,
  3. reconstruct the firmware: rebuild functions, determine the base address, collect information from strings, rebuild symbols etc.

Regarding the processor identification, there is Skochinsky’s presentation which is actually amazing. For disassembling the binary image there is IDA. In order to proper reconstruct the firmware however, several techniques must be applied on the file. For example, one must determine the base address of the firmware i.e. the starting location of the firmware in order to have accurate interpretations of segments referenced by immediate addresses. The “load technique” is usually used for this step, given that there exist immediate address references in the disassembly. We will talk in future tutorials about this technique.

Today, we will present a simple trick how to rebuild functions and thus fix the disassemble code in IDA. The script below (kudos to Santamarta) simply instructs IDA to explore the remaining unexplored functions in the firmware. The example firmware in our case is based on ARM ISA. In addition, the prologue signature of the already IDA automatically identified functions is a STMFD instruction that pushes the current register values to the stack. The registers pushed to the stack are different between each STMFD instruction but the two most significant bytes of the instruction remain the same (“E9 2D”). This is verified also from the ARM instruction encoding standard. Hence, by editing Santamarta’s script to target this signature (+corrected for endianness), the script is applied to the loaded in IDA firmware. Consequently, a significant part of the firmware binary image is explored since more functions are identified.

/* Ruben Santamarta www.reversemode.com */
/* Fix functions - Schneider NOE 110 firmware */
/* Edited by Harrys Kon Feb. 2015*/
/* FixARMfunctions.idc*/
#include <idc.idc>
static main() {
 auto ae;
 auto funct;
 auto minea;
 auto prolog;
 auto j;
 auto fun_array;
 minea = MinEA();
 fun_array = CreateArray("ProGos");
 if (fun_array == -1) 
   fun_array = GetArrayId("ProGos");
 SetArrayString(fun_array,0,"2D E9"); 
 for (j=0;j<1;j++){
   ae = minea;
   prolog = GetArrayElement(AR_STR,fun_array,j);
   while (1) {
     funct = FindBinary ( ae, SEARCH_DOWN, prolog); 
     if (funct == BADADDR )
     funct = funct - 2;
     MakeCode (funct);
     MakeFunction (funct, BADADDR); 
     ae = funct + 4;