Jump to content
Aerosol

Reversing the Dropcam Part 2: Rooting your Dropcam

Recommended Posts

Posted

In the last Dropcam post, I wrote about reversing the USB setup procedure that the Dropcam uses to initially connect to your WiFi network. After exploring the USB tunneling protocol, the next step was to take it apart, or at least take off the back of the enclosure:

dropcamangle.jpg

The main controller is an Ambarella A5s system-on-chip, which contains an ARM processor, video processing hardware, USB device controller, and other peripherals. We had actually already guessed that the Dropcam used an Amborella chip based on the iManufacturer USB descriptor field value “Linux 2.6.38.8 with ambarella_udc”. Ambarella chips are also used in GoPro cameras. Quite a bit of work has been done reversing GoPro cameras by other researchers. One researcher, who goes by evilwombat, has done some particularly interesting work, including writing a firmware parser and tools that can be used to load custom code onto GoPro cameras over the USB port, which can be found at his Github page (https://github.com/evilwombat?tab=repositories).

Here's a picture of the Dropcam with some of the components identified:

components.png

The most useful thing to identify was the UART (serial) port (zoomed in the picture above, and labeled with TX, RX, 3.3v, and GND). Upon examining the board, that 4-pin footprint looked suspiciously like a serial port. One pad was connected to ground, and another was connected to a thick trace meaning it was likely a power connection, and it is in fact at 3.3v when the camera is powered on. The other two pads were connected to resistors via small traces and they were both at 3.3v with the camera powered on. This is consistent with an embedded system serial port – UARTs usually are at a “high” voltage level when they are idle; the TX line would be high because no data was being transmitted and the RX line would be pulled high when no input is connected. I tried connecting the RX line of a serial adapter to each of the two pads and found that when I configured the adapter for a baudrate of 115200 and powered the Dropcam, I could see Linux boot messages being transmitted:

[    0.000000] Linux version 2.6.38.8 (dropcambuild@ubuntu-dropcam-build) (gcc version 4.5.2 (Sourcery G++ Lite 2011.03-41) ) #15 PREEMPT Mon Oct 1 16:59:51 PDT 2012
[ 0.000000] CPU: ARMv6-compatible processor [4117b365] revision 5 (ARMv6TEJ), cr=00c5387f
[ 0.000000] CPU: VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
[ 0.000000] Machine: Coconut
[ 0.000000] Memory policy: ECC disabled, Data cache writeback
[ 0.000000] Ambarella: AHB = 0x60000000[0xf0000000],0x01000000 0
[ 0.000000] Ambarella: APB = 0x70000000[0xf1000000],0x01000000 0
[ 0.000000] Ambarella: PPM = 0xc0000000[0xe0000000],0x00200000 9
[ 0.000000] Ambarella: BSB = 0xc8c00000[0xe8c00000],0x00400000 9
[ 0.000000] Ambarella: DSP = 0xc9000000[0xe9000000],0x07000000 9
[ 0.000000] Ambarella: HAL = 0xc00a0000[0xfee00000],0x00009f34 9
[ 0.000000] bootmem_init: high_memory = 0xc8a00000
[ 0.000000] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 35052
[ 0.000000] Kernel command line: console=ttyS0 ubi.mtd=lnx root=ubi0:rootfs rw rootfstype=ubifs init=/linuxrc
[ 0.000000] PID hash table entries: 1024 (order: 0, 4096 bytes)
[ 0.000000] Dentry cache hash table entries: 32768 (order: 5, 131072 bytes)
[ 0.000000] Inode-cache hash table entries: 16384 (order: 4, 65536 bytes)
[ 0.000000] Memory: 138MB = 138MB total
[ 0.000000] Memory: 136244k/136244k available, 5068k reserved, 0K highmem
(etc.)

Once I had identified the TX and RX pads and successfully received some data, I soldered some wires to those pads and brought them out of the case so that I could access the serial port with the Dropcam assembled:

serialwires.jpg

After the boot messages, there is eventually a login prompt:

########  ########   #######  ########   ######     ###    ##     ##
## ## ## ## ## ## ## ## ## ## ## ## ### ###
## ## ## ## ## ## ## ## ## ## ## #### ####
## ## ######## ## ## ######## ## ## ## ## ### ##
## ## ## ## ## ## ## ## ######### ## ##
## ## ## ## ## ## ## ## ## ## ## ## ##
######## ## ## ####### ## ###### ## ## ## ##

Ambarella login:

Getting root via the Ambarella bootloader

Unfortunately, I didn't know the root password. I tried logging in as root with a few guessed passwords, but none of them worked. I was considering different ways to dump or modify the Flash chip contents when I happened upon a solution on a forum. After reading some posts on one of the GoPro forums I tried a trick mentioned there to get a bootloader prompt – transmitting a newline immediately upon powering the device on is the key. If you hold down the “Enter” key, repeatedly sending newlines to the serial connection while powering the Dropcam, you can access to the Ambarella bootloader:

             ___  ___  _________                _
/ _ \ | \/ || ___ \ | |
/ /_\ \| . . || |_/ / ___ ___ | |_
| _ || |\/| || ___ \ / _ \ / _ \ | __|
| | | || | | || |_/ /| (_) || (_) || |_
\_| |_/\_| |_/\____/ \___/ \___/ \__|
----------------------------------------------------------
Amboot(R) Ambarella(R) Copyright (C) 2004-2007
BST (137166), HAL (137166)
Arm freq: 480000000
iDSP freq: 120000000
Core freq: 120000000
Dram freq: 336000000
AHB freq: 120000000
APB freq: 60000000
amboot>
amboot>
amboot>
amboot>
amboot>
amboot>
amboot>
amboot>
amboot>
amboot>
amboot>
amboot>
amboot>
amboot> help
The following commands are supported:
help bios boot diag
dump erase nand_erase exec
hal hotboot netboot ping
r8 r16 r32 reboot
reset setenv setmem show
usbdl w8 w16 w32
xmdl bapi
Use 'help' to get help on a specific command
amboot>

Once you have access to the bootloader, rooting the Dropcam is just like getting root on any Linux computer where you have access to the bootloader. You can copy the kernel command line shown in the boot messages:

console=ttyS0 ubi.mtd=lnx root=ubi0:rootfs rw rootfstype=ubifs init=/linuxrc

And change the init parameter to start a shell:

amboot> boot console=ttyS0 ubi.mtd=lnx root=ubi0:rootfs rw rootfstype=ubifs init=/bin/sh

After doing this and watching the kernel boot again, I was left with a root shell:

[    3.130000] UBIFS: reserved for root:  0 bytes (0 KiB)
[ 3.130000] VFS: Mounted root (ubifs filesystem) on device 0:13.
[ 3.140000] Freeing init memory: 136K
/bin/sh: can't access tty; job control turned off
/ #

My goal was to edit the /etc/shadow file so that I could log in to the camera after a normal boot. Interestingly, the /etc/shadow file on the Dropcam is a link to /mnt/dropcam/shadow:

/ # ls -l /etc/shadow
lrwxrwxrwx 1 root root 21 Oct 1 2012 /etc/shadow -> ../mnt/dropcam/shadow

You therefore need to mount the /mnt/dropcam filesystem to access the shadow file:

/ # cat /etc/fstab
# /etc/fstab: static file system information.
#
# <file system> <mount pt> <type> <options> <dump> <pass>
#/dev/root / ext2 rw,noauto 0 1
#proc /proc proc defaults 0 0
devpts /dev/pts devpts defaults,gid=5,mode=620 0 0
#tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
debugfs /debug debugfs defaults 0 0

# extra mounts
/dev/mtdblock9 /mnt/dropcam jffs2 defaults 0 0
/ # mount -tjffs2 /dev/mtdblock9 /mnt/dropcam

And then remove the password hashes from it:

/ # cat /mnt/dropcam/shadow
root::10933:0:99999:7:::
bin:*:10933:0:99999:7:::
daemon:*:10933:0:99999:7:::
adm:*:10933:0:99999:7:::
lp:*:10933:0:99999:7:::
sync:*:10933:0:99999:7:::
shutdown:*:10933:0:99999:7:::
halt:*:10933:0:99999:7:::
uucp:*:10933:0:99999:7:::
operator:*:10933:0:99999:7:::
nobody:*:10933:0:99999:7:::
default::10933:0:99999:7:::

The /mnt/dropcam filesystem is interesting because it appears to be where camera-specific configuration files are stored:

/ # ls /mnt/dropcam/
bpcmap.bin keycert.pem softmac
fv.txt provisioned wpa_supplicant.conf
hwver shadow

This implies that different cameras might have different root passwords. The wpa_supplicant.conf file contains the configuration for the wireless network. Most interesting of these files, however, is the keycert.pem file, which contains a public/private RSA key pair and a client certificate. The certificate is issued by a “Dropcam Certificate Authority”, and the common name is set to the unique ID of my Dropcam (the same identifier used to set up the camera and view its stream, as discussed in my previous post):

$ openssl x509 -in keycert.pem -noout -text | grep CN
Issuer: C=US, CN=Dropcam Certificate Authority, O=Dropcam
Subject: C=US, CN=d024378182da4f37b0e981946989f40a, O=Dropcam

This means that each Dropcam has a unique client certificate that it uses to authenticate to the Dropcam cloud servers.

Exploring the running device

Now that I had modified the shadow file, I was able to log in as root without a password and inspect the system after it had booted normally:

# ps
PID USER TIME COMMAND
1 root 0:02 init
2 root 0:00 [kthreadd]
3 root 0:00 [ksoftirqd/0]
4 root 0:00 [kworker/0:0]
5 root 0:00 [kworker/u:0]
6 root 0:00 [khelper]
7 root 0:00 [kworker/u:1]
402 root 0:00 [sync_supers]
404 root 0:00 [bdi-default]
406 root 0:00 [kblockd]
513 root 0:00 [kswapd0]
514 root 0:00 [fsnotify_mark]
515 root 0:00 [aio]
517 root 0:00 [crypto]
558 root 0:00 [mtdblock0]
563 root 0:00 [mtdblock1]
568 root 0:00 [mtdblock2]
573 root 0:00 [mtdblock3]
578 root 0:00 [mtdblock4]
583 root 0:00 [mtdblock5]
588 root 0:00 [mtdblock6]
593 root 0:00 [mtdblock7]
598 root 0:00 [mtdblock8]
603 root 0:00 [mtdblock9]
611 root 0:00 [ubi_bgt0d]
628 root 0:00 [ubifs_bgt0_0]
629 root 0:00 [kworker/0:1]
643 root 0:00 [flush-ubifs_0_0]
646 root 0:00 [jffs2_gcd_mtd9]
699 root 0:00 [kworker/u:2]
735 root 0:00 /bin/ash /usr/bin/bootstrap.sh
736 root 0:00 -sh
738 root 0:00 syslogd -C128 -S
740 root 0:00 klogd
743 root 0:00 /usr/bin/connect
744 root 0:00 logger -t connect
745 root 0:00 /usr/bin/connect
746 root 0:00 /usr/bin/connect
760 root 0:00 [file-storage]
772 root 0:00 [kworker/0:2]
784 root 0:00 [cfg80211]
804 root 0:00 [AR6K Async]
811 root 0:00 [ksdioirqd/mmc1]
822 root 0:00 wpa_supplicant -iwlan0 -c/mnt/dropcam/wpa_supplicant.conf
829 root 0:00 [dsplogd]
830 root 0:00 [vsyncd]
860 root 0:00 [sh]
861 root 0:00 [sh]
868 root 0:00 ps

The /usr/bin/connect binary performs most of the operations of the Dropcam. It handles the TLS connections made out to Dropcam cloud servers (which, based on strings in the connect binary, carry a protocol named droptalk). It also handles loading and unloading the kernel driver, as well as the userspace portions of the USB mass storage network tunnel (which again, based on strings in the binary, is named FSNL). The connect binary is UPX packed, but it can be unpacked easily:

$ strings connect | tail -1
UPX!
$ upx -d connect
Ultimate Packer for eXecutables
Copyright (C) 1996 - 2013
UPX 3.09 Markus Oberhumer, Laszlo Molnar & John Reiser Feb 18th 2013

File size Ratio Format Name
-------------------- ------ ----------- -----------
789596 <- 420052 53.20% linux/armel connect

Unpacked 1 file.

One thing that we noticed when looking at this binary was that it contains references to the Lua scripting language. We weren't sure why until we saw that it was writing to a file named /tmp/connect.bin and then running this command via a call to system():

rm -rf /tmp/connect && mkdir /tmp/connect && tar zx -f /tmp/connect.bin -C /tmp/connect && rm /tmp/connect.bin

The connect binary itself contains an embedded tarball that gets extracted to /tmp/connect when it runs. The tarball contains an assortment of files including a number of compiled Lua scripts:

$ dd if=./connect of=connect.tar.gz bs=1 skip=473404 count=168451
168451+0 records in
168451+0 records out
168451 bytes (168 kB) copied, 0.364475 s, 462 kB/s
$ tar -tzvf connect.tar.gz
-rw-r--r-- dropcambuild/dropcambuild 10376 2013-04-22 20:25 dispatch.bin
-rw-r--r-- dropcambuild/dropcambuild 1243 2013-04-22 20:25 hello.bin
-rw-r--r-- dropcambuild/dropcambuild 545 2013-04-22 20:25 hwver.bin
-rw-r--r-- dropcambuild/dropcambuild 4279 2013-04-22 20:25 ir.bin
-rw-r--r-- dropcambuild/dropcambuild 879 2013-04-22 20:25 list.bin
-rw-r--r-- dropcambuild/dropcambuild 650 2013-04-22 20:25 main.bin
-rw-r--r-- dropcambuild/dropcambuild 2363 2013-04-22 20:25 monitor.bin
-rw-r--r-- dropcambuild/dropcambuild 708 2013-04-22 20:25 motion.bin
-rw-r--r-- dropcambuild/dropcambuild 2010 2013-04-22 20:25 net.bin
-rw-r--r-- dropcambuild/dropcambuild 2607 2013-04-22 20:25 oldiags.bin
-rw-r--r-- dropcambuild/dropcambuild 3280 2013-04-22 20:25 persistence.bin
-rw-r--r-- dropcambuild/dropcambuild 329 2013-04-22 20:25 platform.bin
-rw-r--r-- dropcambuild/dropcambuild 3365 2013-04-22 20:25 platform_a5s.bin
-rw-r--r-- dropcambuild/dropcambuild 551 2013-04-22 20:25 platform_local.bin
-rw-r--r-- dropcambuild/dropcambuild 822 2013-04-22 20:25 ravg.bin
-rw-r--r-- dropcambuild/dropcambuild 191 2013-04-22 20:25 rtp.bin
-rw-r--r-- dropcambuild/dropcambuild 643 2013-04-22 20:25 settings.bin
-rw-r--r-- dropcambuild/dropcambuild 9931 2013-04-22 20:25 states.bin
-rw-r--r-- dropcambuild/dropcambuild 912 2013-04-22 20:25 status.bin
-rw-r--r-- dropcambuild/dropcambuild 3822 2013-04-22 20:25 streams.bin
-rw-r--r-- dropcambuild/dropcambuild 3047 2013-04-22 20:25 update.bin
-rw-r--r-- dropcambuild/dropcambuild 601 2013-04-22 20:25 usb.bin
-rw-r--r-- dropcambuild/dropcambuild 2602 2013-04-22 20:25 util.bin
-rw-r--r-- dropcambuild/dropcambuild 1468 2013-04-22 20:25 watchdog.bin
-rw-r--r-- dropcambuild/dropcambuild 54727 2013-04-22 20:25 droptalk_pb.bin
-rw-r--r-- dropcambuild/dropcambuild 1504 2013-04-22 20:25 containers.bin
-rw-r--r-- dropcambuild/dropcambuild 5879 2013-04-22 20:25 decoder.bin
-rw-r--r-- dropcambuild/dropcambuild 1038 2013-04-22 20:25 descriptor.bin
-rw-r--r-- dropcambuild/dropcambuild 9360 2013-04-22 20:25 encoder.bin
-rw-r--r-- dropcambuild/dropcambuild 615 2013-04-22 20:25 listener.bin
-rw-r--r-- dropcambuild/dropcambuild 20750 2013-04-22 20:25 protobuf.bin
-rw-r--r-- dropcambuild/dropcambuild 1505 2013-04-22 20:25 text_format.bin
-rw-r--r-- dropcambuild/dropcambuild 1525 2013-04-22 20:25 type_checkers.bin
-rw-r--r-- dropcambuild/dropcambuild 3620 2013-04-22 20:25 wire_format.bin
-rw-r--r-- dropcambuild/dropcambuild 1686 2013-04-22 17:24 a5s_boot.sh
-rw-r--r-- dropcambuild/dropcambuild 78 2013-04-18 16:45 wpa_supplicant_a5s.conf
-rwxr-xr-x dropcambuild/dropcambuild 1286 2013-04-18 16:45 udhcpc.script
-rwxr-xr-x dropcambuild/dropcambuild 1310 2013-04-18 16:45 udhcpc_provision.script
-rw-r--r-- dropcambuild/dropcambuild 17536 2013-04-18 16:45 ov9715_01_3D_hwrev_1.bin
-rw-r--r-- dropcambuild/dropcambuild 17536 2013-04-18 16:45 ov9715_01_3D_hwrev_2.bin
-rw-r--r-- dropcambuild/dropcambuild 17536 2013-04-18 16:45 ov9715_02_3D_hwrev_1.bin
-rw-r--r-- dropcambuild/dropcambuild 17536 2013-04-18 16:45 ov9715_02_3D_hwrev_2.bin
-rw-r--r-- dropcambuild/dropcambuild 17536 2013-04-18 16:45 ov9715_03_3D_hwrev_1.bin
-rw-r--r-- dropcambuild/dropcambuild 17536 2013-04-18 16:45 ov9715_03_3D_hwrev_2.bin
-rw-r--r-- dropcambuild/dropcambuild 17536 2013-04-18 16:45 ov9715_04_3D_hwrev_1.bin
-rw-r--r-- dropcambuild/dropcambuild 17536 2013-04-18 16:45 ov9715_04_3D_hwrev_2.bin
-rw-r--r-- dropcambuild/dropcambuild 27453 2013-04-18 16:45 ambarella_udc-pre-v16.ko
-rwxr-xr-x dropcambuild/dropcambuild 86828 2013-04-18 16:45 wmiconfig

We'll have another blog post coming up detailing how to reverse engineer those compiled Lua scripts, with a tool to make the RE work easier.

Transport encryption and exploring traffic interception

I wanted to perform a man-in-the-middle attack so that I could decode the TLS traffic from the camera. Every Dropcam has its own client certificate issued by the Dropcam CA; with a copy of my camera's client certificate I could start a TLS connection to the Dropcam servers, but I couldn't yet convince the connect binary to connect to me. In order to perform the man-in-the-middle attack, the simplest option was to patch the server certificate checking code out of the connect binary. This involved flipping one bit in the unpacked binary, re-packing it, and uploading it to the camera.

The droptalk transport layer has decent protection against eavesdropping attacks. It uses an OpenSSL TLSv1 connection with ephemeral elliptic curve Diffie-Hellman (ECDHE) key exchange, and either 128 or 256 bit AES encryption. This is the list of the two cipher suites that the connect binary will accept for the droptalk connection:

ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA

The ECDHE key exchange method made performing a man-in-the-middle on the droptalk connection harder because most tools that I tried to use didn't support that key exchange algorithm. However, I was able to hack some code together that given the camera's private key and certificate would let me intercept and examine the draptalk traffic between my patched connect binary and the Dropcam servers. Here's a picture of my test setup:

serialwifisetup.png

My Linux machine was configured to act as a wireless access point, using iptables to redirect the dropcam traffic to my listening droptalk interception process. In addition, I had a serial terminal connected to the Dropcam's serial port so I could upload the patched connect binary and examine its behavior. The droptalk protocol is simple – there is a 3-byte header consisting of a one-byte message type followed by a big-endian two-byte length field. Luckily, there is a function in the connect binary for converting droptalk message type identifiers (the first byte in the header) to human-readalble strings for inclusion in debug output:

droptalkfunctions.png

The function provides us with this list of droptalk message types:

00      RESERVED
01 REDIRECT
02 START_STREAM
03 STOP_STREAM
04 WIFI_SCAN
05 WIFI_CONNECT
06 RESTART
07 UPDATE
08 DEBUG
09 SET_STATUS_LIGHT
0a SET_ILLUMINATOR_LIGHT
0b SET_AUDIO_GAIN
0c STOP_BACKFILL
0d AUDIO_PAYLOAD
0e SET_IR_LED
0f SET_DPTZ
10 FORCE_IDR
11 EXEC
12 SET_WATERMARK
13 AUDIO_SOUND
14 SET_IMAGE_PROPERTIES
40 PING
80 HELLO
81 STREAM_BEGIN
82 STREAM_END
83 RTP
84 WIFI_SCAN_LIST
85 WIFI_CONNECT_STATUS
86 EVENT
87 BACKFILL_COMPLETE
8a UPDATE_RESULT
8c OFFLINE_DIAGNOSTIC_REPORT
8e STATUS_REPORT

Message types 0x01 through 0x14 appear to be messages that are sent to the camera, while types 0x80 through 0x8e appear to be intended to originate from the camera. Most of the droptalk messages contain protobufs which are decoded in the Lua code. For example, here's the first HELLO packet that my Dropcam sends when it connects to nexus.dropcam.com, decoded with the protoc tool:

7: "Dropcam Connect - Version: 162, Build: 57 (jenkins-connect-release-node=linux-57, a29560dbb0724e7dbafb19b9ac1268b6fb62f1d6, origin/hotfix/basil)"
9: 2
8: "Build: 181 (jenkins-ambarella-181, 8732f64a79aecdd16bf6562775015c303d71c839), Linux: Linux Ambarella 2.6.38.8 #15 PREEMPT Mon Oct 1 16:59:51 PDT 2012 armv6l GNU/Linux"
1: 1
5: 3
6: 15
4: "0.0.0.0"
2: 4
3: 162

The nexus.dropcam.com server always replies with a REDIRECT to an “oculus” server:

1: "oculus121.dropcam.com"

The client then connects to the “oculus” server and sends another HELLO packet. Most of the configuration options in the Dropcam web interface correspond to droptalk messages that are sent to the camera. When the server is ready to receive data, it sends a START_STREAM message with some video parameters in it. Video data is sent from the camera in RTP droptalk messages containing RTP formatted video data.

Conclusions

In this post I've written about the process of reverse engineering the Dropcam from the point of opening the case to having a basic understanding of its network protocols. With the information we've gathered, you could start to piece together a protobuf definition file (.proto file) for the various message types and write your own droptalk client or server. Alternatively, you could use the root shell on the Dropcam to modify or add to its functionality. Comment below, email us, or tweet @InCludeSecurity if you try these things, we'd love to hear what modifications you make to your Dropcam.

Source

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...