Hacking the RXS-3211

2011-06-18

After seeing Hack-a-Day’s post about a cheap IP webcam that runs Linux I couldn’t resist the urge to dig into yet another embedded system. I don’t really have a definite need for something like this, but thought it sounded like a neat piece of hardware to hack around with, so why not?

When I first plugged the camera in, I didn’t see it grab an IP over DHCP and went digging for the Manual (PDF). It boots up as 192.168.2.3 with a webserver on port 80. Default username and password: admin/1234.

After changing the IP to a more reasonable subnet, it functions as a nifty little IP webcam providing either a MJPEG or MPEG4 stream over RTSP. Not bad for $40.

Cracking the case open was a bit difficult, until I realized there was a screw hidden under the label on the back.

Time for hacking! I’ve found at least two potential ways of getting a shell on this thing, with several more theoretically possible. The easiest approach is the one that Hack-a-Day mentioned: wire up a serial console to some empty pads on the board and rock on. There are four pads on the back side of the device (the side without the camera sensor). In the picture below, from left to right: 3.3v, RX, TX, GND. Please excuse my horrible soldering job.

RXS-3211 serial header

For the sake of simplicity, I connected this header up to my Bus Pirate and configured the port as 115200 8e1.


Bus Pirate v3a
Firmware v5.10 (r559) Bootloader v4.1
DEVID:0x0447 REVID:0x3043 (24FJ64GA002 B5)

http://dangerousprototypes.com

HiZ>m
1. HiZ
2. 1-WIRE
3. UART
4. I2C
5. SPI
6. 2WIRE
7. 3WIRE
8. LCD
9. DIO
x. exit(without change)

(1)>3
Set serial port speed: (bps)
1. 300
2. 1200
3. 2400
4. 4800
5. 9600
6. 19200
7. 38400
8. 57600
9. 115200
10. BRG raw value

(1)>9
Data bits and parity:
1. 8, NONE *default
2. 8, EVEN
3. 8, ODD
4. 9, NONE
(1)>2
Stop bits:
1. 1 *default
2. 2
(1)>1
Receive polarity:
1. Idle 1 *default
2. Idle 0
(1)>1
Select output type:
1. Open drain (H=Hi-Z, L=GND)
2. Normal (H=3.3V, L=GND)

(1)>2
Ready
UART>(1)
UART bridge
Reset to exit
Are you sure? y

Assuming everything’s wired up correctly, you should now be able to watch the board boot up and interact with it on the console.

Welcome to Proboot 1.0
Prolific Technology Inc. 2003-2006

[General]
Version : 1.0.39
Date : 2009/10/26
CPU : ARM FA526
MemSize : 32 MB
Cache : vIbrSLWCaM
IP : 0.0.0.0
MAC : 00:00:00:00:00:00

[OnBoard NOR Flash]
Type : PPI-AMD
ID : 00a8
Sectors : 71
Size : 4MB

[Memery Layout]
Stack : 0x00400000 - 0x003c0000
Shadow : 0x00600000 - 0x006a4f68
Pages : 0x00004000 - 0x00008000
Buffer : 0x00700000 - 0x00800000
Tags : 0x00002000 - 0x00004000

script 0x19802000 8192 2
Running script (Ctrl-C to cancel)

echo "loading compressed kernel"
loading compressed kernel
load 0x20000 0x220000 786432
echo "execute kernel"
execute kernel
exec 0x220000 "root=/dev/norblock/disc0/disc rootfstype=squashfs nor=b:0x320000@0xe0000,c:8192@0x4000,c:40960@0x6000 prolific.keypad=GPIO_IN(11);GPIO_OE(5,6);"
Uncompressing Linux......................................... done, booting the kernel.
Linux version 2.4.19-pl1029 (root@neo) (gcc version 3.3.4) #219 ?| 7?? 29 10:55:30 CST 2010
CPU: Faraday FA526id(wb) revision 1
ICache:16KB enabled, DCache:16KB enabled, BTB support, IDLE support
Machine: Prolific ARM9v4 - PL1029
Prolific arm arch version 1.0.12
On node 0 totalpages: 8192
zone(0): 8192 pages.
zone(1): 0 pages.
zone(2): 0 pages.
Kernel command line: root=/dev/norblock/disc0/disc rootfstype=squashfs nor=b:0x320000@0xe0000,c:8192@0x4000,c:40960@0x6000 prolific.keypad=GPIO_IN(11);GPIO_OE(5,6);
plser console driver v2.0.0
Calibrating delay loop... 147.56 BogoMIPS
Memory: 32MB = 32MB total
Memory: 30948KB available (1064K code, 297K data, 64K init)
Dentry cache hash table entries: 4096 (order: 3, 32768 bytes)
Inode cache hash table entries: 2048 (order: 2, 16384 bytes)
Mount-cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer-cache hash table entries: 1024 (order: 0, 4096 bytes)
Page-cache hash table entries: 8192 (order: 3, 32768 bytes)
POSIX conformance testing by UNIFIX
PCI: Probing PCI hardware on host bus 0.
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
Prolific addr driver v0.0.4
tts/%d0 at MEM 0x1b000400 (irq = 2) is a PLSER
Starting kswapd
devfs: v1.12a (20020514) Richard Gooch (rgooch@atnf.csiro.au)
devfs: boot_options: 0x1
squashfs: version 3.1 (2006/08/19) Phillip Lougher
i2c-core.o: i2c core module version 2.8.1 (20031005)
i2c-dev.o: i2c /dev entries driver module version 2.8.1 (20031005)
Prolific i2c algorithm module v1.2
Initialize Prolific I2C adapter module v1.2.1
found i2c adapter at 0xd9440000 irq 17. Data tranfer clock is 100000Hz
i2c-proc.o version 2.8.1 (20031005)
pty: 256 Unix98 ptys configured
PL-1029 NOR flash driver, version 0.8.4
NOR flash type: ppi-amd 8x8 64x63
NOR: PPI
NOR flash id = 0xa8
nor interrupt 30 registered
Partition check:
norblocka: unknown partition table
RAMDISK driver initialized: 16 RAM disks of 2048K size 1024 blocksize
PPP generic driver version 2.4.2
PPP Deflate Compression module registered
PPP BSD Compression module registered
usb.c: registered new driver usbdevfs
usb.c: registered new driver hub
usb-ohci-pci.c: usb-00:05.0, PCI device 180d:2300
usb-ohci.c: USB OHCI at membase 0xd8400000, IRQ 9
usb.c: new USB bus registered, assigned bus number 1
usb.c: ### @@@ usb_set_address

usb.c: >>> usb_get_device_descriptor

usb.c: >>> usb_get_configuration

Product: USB OHCI Root Hub
SerialNumber: d8400000
hub.c: USB hub found
hub.c: 4 ports detected
Prolific Real-Time Clock Driver version 1.0.0 (2003-04-02)
Prolific keypad driver v1.0.8
PL UART driver version 1.1.0-1 (2007-02-15)
ov7670.o version 1.0.0.0 (20070316) [ fine tune ]
OV7670AttachAdapter() be called
OV7670Detect() be called
Set 166 registers value
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 2048 bind 4096)
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
NET4: Ethernet Bridge 008 for NET4.0
Fast Floating Point Emulator V0.9 (c) Peter Teichmann.
VFS: Mounted root (squashfs filesystem) readonly.
Mounted devfs on /dev
Freeing init memory: 64K
pl serial only support even parity
MAC address: 00:1F:1F:CE:C8:25
MAC address: 00:1F:1F:CE:C8:25
init started: BusyBox v1.01 (2009.10.29-06:28+0000) multi-call binary
init started: BusyBox v1.01 (2009.10.29-06:28+0000) multi-call binary
Starting pid 10, console /dev/tts/0: '/etc/rc.d/rcS'
F: applet not found
Enable alignment-fixup function...
$Starting tmpfs:---->

$Starting encoder driver module: ---->
Using /lib/modules/plmedia.o
plmedia version 1.3.0
Hello Grabber!
[Grab] : Preallocation memory space 2097152 bytes
Hello Encoder!
Hello PLMD!
Warning: loading plmedia will taint the kernel: non-GPL license - PLGRAB
See http://www.tux.org/lkml/#export-tainted for information about tainted modules
Using /lib/modules/crypt.o
aes interrupt 12 registered
ic3010_ctrl_init...
Using /lib/modules/ic3005_ctrl.o
Warning: loading ic3005_ctrl will taint the kernel: no license
See http://www.tux.org/lkml/#export-tainted for information about tainted modules
Using /lib/modules/rt3070sta.o
Warning: loading rt3070sta will taint the kernel: no license
See http://www.tux.org/lkml/#export-tainted for information about tainted modules
rtusb init --->
usb.c: registered new driver rt2870
SIOCGIFFLAGS: No such device
Using /lib/modules/sundance.o
sundance.c:v1.30b 7-9-2007 Written by Donald Becker

http://www.scyld.com/network/sundance.html

eth0: IC Plus IP100A Fast Ethernet Adapter at 0xc28bf000, 00:00:00:00:00:00, IRQ 5.
eth0: MII PHY found at address 0, status 0x7849 advertising 01e1.

Starting enet...

****************************************************************
Initializing ipc between Spook and Enet....: Success
****************************************************************

: Success
total enet structure = 5693 (163D) checksum:(enet:532F) (flash:532F)

default MAC address: 00 1F 1F CE C8 25
eth0 Link down, 7849.
neo: netdev_open Reset PHY
neo: netdev_open Reset PHY 2
eth0: Promiscuous mode enabled.
device eth0 entered promiscuous mode
Starting pibr0: port 1(eth0) entering learning state
d 48,br0: port 1(eth0) entering forwarding state
br0: topology change detected, propagating
console /dev/tts/0: '/bin/ash'

BusyBox v1.01 (2009.10.29-06:28+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

/ # NTP thread start.. PID:52
udpsock port: 4322
httpd->port:80

link_status->wlg_ifindex: 0
link_status->lan_ifindex: 2
enet_watchdog_init
eNET main task started
Init eth0: Promiscuous mode enabled.
random number generator with value: 505
System startbr0: port 1(eth0) entering disabled state
up [ v1.0 (Jul 29 2010 10:55:12) ]
enet_watchdog_start
klogd thread started
Set gateway (change the routing table)
add 255.255.255.255/255.255.255.255 to routing table for broadcast
embedded av stream server started PID:58

Starting mpeg4 pipe server for Spook
Waiting for a connection from spook... (video)
video device thread started PID:60
motion detect thread started PID:61
audio device thread started PID:62
embedded av stream controller started 63
SO_SNDBUF:131070 SO_SNDLOWAT:1
set audio capture properties
start audio capture ok
stop video capture
stop video device.....
set video capture properties
Enter normal VGA mode...
set webpush fps to 30
set video capture properties done
set motion detection properties
set motion detection properties done
start video capture
success to open digits.bmp file

Set 166 registers value
Opened /dev/pl_grab successfully
uDenominator:30 uNumerator:1
******************************************************
MPEG4 encoding source: 640 X 480
MPEG4 encoding format: 640 X 480
MPEG4 bitrate: 0
MPEG4 FPS: 30
MPEG4 VBR nQuant: 5
Opened /dev/pl_enc successfully (MPEG4)
******************************************************
skip MPEG4 encoder!! Using MD profile instead
Jan 1 00:00:12 spook[65]: listening on control socket /tmp/spook.sock
Jan 1 00:00:12 spook[65]: unable to open /tmp/spook.conf: No such file or directory
killall: spook: no process killed
generate new spook.conf... (MPEG4)
******************************************************
MJPEG encoding source: 640 X 480
MJPEG encoding format: 640 X 480
MJPEG quality: 4
MJPEG FPS: 30
Opened /dev/pl_enc successfully (MJPEG)
******************************************************
******************************************************
MD encoding source: 640 X 480
MD encoding format: 640 X 480
MD FPS: 30
MD VBR nQuant: 5
Opened /dev/pl_enc successfully (MD)
******************************************************
start video capture ok
httpd thread started PID:69
mmap Y[0]
enet agentd started PID:73
This board has no wireless supported.
encode VOS header...
enet
00 00 01 B0 08 00 00 01 B5 89 13 00 00 01 00 00 00 01 20 00 C4 88 80 0F 51 40 43 C1 46 3F 00 00
first read video at 13:54
mmap Y[2]
eth0: Promiscuous mode enabled.
eth0 Link down, 7849.
neo: netdev_open Reset PHY
neo: netdev_open Reset PHY 2
eth0: Promiscuous mode enabled.
eth0: Promiscuous mode enabled.
br0: port 1(eth0) entering learning state
eth0: Promiscuous mode enabled.
br0: port 1(eth0) entering forwarding state
br0: topology change detected, propagating
E-mail schedule system started (PID:51)
FTP schedule system started (PID:50)
mmap Y[1]
Jan 1 00:00:15 spook[78]: listening on control socket /tmp/spook.sock
Jan 1 00:00:15 spook[78]: listening on tcp port 554
Jan 1 00:00:15 spook[78]: pl1029-video: start_block
Jan 1 00:00:15 spook[78]: pl1029-video: set_device
Jan 1 00:00:15 spook[78]: pl1029-video: set_framesize
Jan 1 00:00:15 spook[78]: pl1029-video: set_bitrate
Jan 1 00:00:15 spook[78]: pl1029-video: set_format
Jan 1 00:00:15 spook[78]: pl1029-video: set_framerate_num
Jan 1 00:00:15 spook[78]: pl1029-video: set_output
Jan 1 00:00:15 spook[78]: pl1029-video: end_block
Jan 1 00:00:15 spook[78]: pl1029-video: device: /tmp/mpeg4Stream
Jan 1 00:00:15 spook[78]: pl1029-video: format: 100
Jan 1 00:00:15 spook[78]: pl1029-video: bitrate: 2048
Jan 1 00:00:15 spook[78]: pl1029-video: width: 640
Jan 1 00:00:15 spook[78]: pl1029-video: height: 480
Jan 1 00:00:15 spook[78]: pl1029-video: fps: eth0: Promiscuous mode enabled.
30
Jan 1br0: port 1(eth0) entering disabled state
00:00:15 spook[78]: pl1029-video: gopsize: 30eth0: Promiscuous mode enabled.
eth0 Link down, 7849.
neo: netdev_open Reset PHY
neo: netdev_open Reset PHY 2
eth0: Promiscuous mode enabled.

Jan 1 00:00:eth0: Promiscuous mode enabled.
br0: port 1(eth0) entering learning state
eth0: Promiscuous mode enabled.
15 spbr0: port 1(eth0) entering forwarding state
br0: topology change detected, propagating
ook[78]: pl1029-video: quality: 12
Accepted a new connection from spook... (video)
Jan 1 00:0br0: port 1(eth0) entering disabled state
0:15 spook[78]: pl1029-video: capture_loop
=============== reinit br0: port 1(eth0) entering learning state
libbrbr0: port 1(eth0) entering forwarding state
br0: topology change detected, propagating
idge ================ ...
Jan 1 00Inconsistent of vop_type (i-vop)!!
:00:15 spook[78]: pl1029-video: set_running
Jan 1 00:00:17 spook[78]: waiting for VOS header...
Set gateway (change the routing table)
add 255.255.255.255/255.255.255.255 to routing table for broadcast
encode VOS header...
enet
00 00 01 B0 08 00 00 01 B5 89 13 00 00 01 00 00 00 01 20 00 C4 88 80 0F 51 40 43 C1 46 3F 00 00
Jan 1 00:00:17 spook[78]: pl1029-video: set_running
Terminated
generate new spook.conf... (MPEG4)
send mpeg4 data to spook pipe failed. aborted..
Waiting for a connection from spook... (video)
Inconsistent of vop_type (i-vop)!!
Jan 1 00:00:18 spook[86]: listening on control socket /tmp/spook.sock
Jan 1 00:00:18 spook[86]: listening on tcp port 554
Jan 1 00:00:18 spook[86]: pl1029-video: start_block
Jan 1 00:00:18 spook[86]: pl1029-video: set_device
Jan 1 00:00:18 spook[86]: pl1029-video: set_framesize
Jan 1 00:00:18 spook[86]: pl1029-video: set_bitrate
Jan 1 00:00:18 spook[86]: pl1029-video: set_format
Jan 1 00:00:18 spook[86]: pl1029-video: set_framerate_num
Jan 1 00:00:18 spook[86]: pl1029-video: set_output
Jan 1 00:00:18 spook[86]: pl1029-video: end_block
Jan 1 00:00:18 spook[86]: pl1029-video: device: /tmp/mpeg4Stream
Jan 1 00:00:18 spook[86]: pl1029-video: format: 100
Jan 1 00:00:18 spook[86]: pl1029-video: bitrate: 2048
Jan 1 00:00:18 spook[86]: pl1029-video: width: 640
Jan 1 00:00:18 spook[86]: pl1029-video: height: 480
Jan 1 00:00:18 spook[86]: pl1029-video: fps: 30
Jan 1 00:00:18 spook[86]: pl1029-video: gopsize: 30
Jan 1 00:00:18 spook[86]: pl1029-video: quality: 12
Accepted a new connection from spook... (video)
Jan 1 00:00:18 spook[86]: pl1029-video: set_running
Jan 1 00:00:18 spook[86]: pl1029-video: capture_loop
Jan 1 00:00:18 spook[86]: waiting for VOS header...
Inconsistent of vop_type (i-vop)!!
encode VOS header...
enet
00 00 01 B0 08 00 00 01 B5 89 13 00 00 01 00 00 00 01 20 00 C4 88 80 0F 51 40 43 C1 46 3F 00 00
Jan 1 00:00:19 spook[86]: pl1029-video: set_running
Inconsistent of vop_type (i-vop)!!
enet link_status thread started PID:81
eth0: Promiscuous mode enabled.
Network initial status: WLAN
WLAN was disabled! link status still was LAN
/ #

At this point, you can poke around a bit. The system has a relatively minimal busybox config installed with two processes making up the webcam interface. “/bin/spook” and “/sbin/enet”. Taking a step back, the web server sends a Server header in it’s responses identifying it as a GoAhead web server. This is a small web server designed to be embedded into another process, in this case, spook. The GoAhead web server has a long list of vulnerabilities attributed to it, including a couple good remote buffer overflows. For someone so inclined, this might provide an alternate method of hacking the RXS-3211 without modifying the hardware.

Getting back to the software itself, I noticed some strange behavior if I attempted to use any program to communicate with the network other than spook. After examining dmesg and thinking carefully about how such a low-powered device can provide streaming video at 30fps, I can make an educated guess about how the system works. When the snoop process starts, it maps a shared memory section with the enet process. snoop instructs the hardware to capture frames, encode them as either MPEG4 or MJPEG and write the result into the shared memory area. The enet process then instructs the ethernet hardware to copy the data out of shared memory and send it out to the network. Assuming that this hypothesis is correct, then doing *anything* that attempts to send data to the network while the enet process is copying data directly to the ethernet chip’s buffers will cause the whole network stack to lock up and break all network connectivity. This makes it exceedingly difficult to copy files off the device or interact with it over the network in anything other than the prescribed manner.

Faced with this setback, I started looking toward the bootloader. Astute readers will have noticed that the bootloader pauses for a couple seconds at startup, prompting for Ctrl-C on the serial console. Doing so drops you into a “proboot>” prompt.


proboot> credit
We fight for the honor of our company.
Prolific bootloader - Proboot - Professional bootloader
by Jun Chen, Hugo Leu, Jedy Wei, CC Yen 2003-2006

It seems to be a fairly sane bootloader with some nice options like loading and dumping images over tftp. Unfortunately, proboot does not recognize the PL1023′s network hardware and expects a Realtek 8139 to be connected. I suspect that this is what the extra set of pads on the I/O board are for: an RTL8139 chip and RJ-45 jack for interacting with the bootloader. What’s left on the board is likely a relic of the development cycle.

Faced with spotty network access in userspace and no viable network interface in the bootloader, I decided to dump out the firmware image to the serial console using the “memdump” command. memdump takes a memory address and length and reads the whole thing out in the common hex/ascii dump format. While this format is intended more for human consumption than machines, I was able to turn it into a binary dump by parsing my terminal emulator’s output log with a few Python scripts.

Based on the default boot script, I was able to deduce the locations of the kernel and three sections of the NOR flash, one of which appears to be the root filesystem… I assume the other two flash sections store non-volatile configuration that is preserved between reboots.

Now that I have access to the firmware, I plan to modify the /etc/rc.d/rcS script in the rootfs to not start spook so that I’ll have a chance to interact with the device over the network unhindered. Eventually, I’d like to build an entirely new rootfs image with some sort of support for writing to flash, currently the system is read-only.

Other observations:

  • The reset button does nothing
  • There are configuration and firmware files for at least three different wireless chipsets, implying that the same software may be running on other IP webcams with better hardware.
  • Without networked access to the bootloader, I’ll have to figure out what sort of “Firmware upgrade” image the webserver expects to be uploaded. Rosewill has not released any upgrade image for this device, so I don’t have a whole lot to go on.


/ # cat /proc/cpuinfo
Processor : Faraday FA526id(wb) rev 1 (v4l)
BogoMIPS : 147.56
Features : swp half

Hardware : Prolific ARM9v4 - PL1029
Revision : 0000
Serial : 0000000000000000
/ # cat /proc/gpio
GPIO_0: Disabled.
GPIO_1: Disabled.
GPIO_2: Disabled.
GPIO_3: Disabled.
GPIO_4: Disabled.
GPIO_5: Disabled.
GPIO_6: Disabled.
GPIO_7: Disabled.
GPIO_8: Disabled.
GPIO_9: Disabled.
GPIO_10: Disabled.
GPIO_11: key = '0x00'
GPIO_12: Disabled.
GPIO_13: Disabled.
GPIO_14: Disabled.
GPIO_15: Disabled.
/ # cat /proc/hardware
ROM Ver: 1970/1/1

[Routing Detail]
Source: 24MHz
clk range: 12M~24MHz
multiply_on: pllm
pllm_range: 100M~300MHz
pllout = xclk_in * 8/1 (n/m)
mem src = independ
pci_bridge = enabled

[Divider and Register]
cfg_fdiv: 0 cfg_hdiv: 1 cfg_pdiv: 1
cfg_ediv: 5 cfg_ddiv: 1 cfg_udiv: 3
External PCI: enabled
PCI Deskew: enabled (20M~100MHz)
PCI Drive: 4mA
ccr: 3a95c848
ccr3: 00000111

[Clock Detail]
XCLK_IN: 24000 kHz
PLL_OUT: 192000 kHz
CPU clock: 192000 kHz
MEM clock: 96000 kHz
PCI clock: 96000 kHz
EPCI clock: 32000 kHz
DEV clock: 96000 kHz
USB clock: 48000 kHz

[Device Clock Detail]
NAND: 0 kHz
I2C: 24000 kHz
AC97: 96000 kHz
GPIO: 48000 kHz
IDE1: 0 kHz
SD: 0 kHz
GPIO2: 96000 kHz
UART: 48000 kHz
MS: 0 kHz
JMP4: 96000 kHz
SPI: 12000 kHz
AES: 96000 kHz
NOR: 48000 kHz
/ # cat /proc/pl_grab
Grabbed Frames : 9405
Output Frames : 9405
Dropped Frames : 0
Grabbed fps : 28.67
Output fps : 28.67
Time Stamp Unit : 90000
Last Frame Squence : 9404
Buffer Allocated Size : 524288
Buffer Actual Size : 460800
Buffer Number : 3
Overflow Times : 1
Free List Empty Times : 33
Ready List Empty Times : 0
Free List Size : 1
Ready List Size : 0
Grabbing Index : 1
Frame Interval : 3000
Is grabbing : 1
Grab Mode : Streaming
Using Catched Frame : Off
Preallocated space : 2097152
Used preallocation : 1388544
FG_CNFG : 0x000F0049
FG_STRIDE : 0x00A000A0
FG_HCROP : 0x01400000
FG_VCROP : 0x01E00000