Gaining Serial Console Access on the Control4 Mini Touch Screen

I became interested in the Control4 Mini Touch Screen after watching a teardown video on YouTube by Connor Wolf. It’s an embedded computer system with a touch screen which can be mounted into a wall. Its intended use is to interface with a Control4 home automation controller. To me it seemed like an interesting platform to repurpose as a development board.

Since the Mini Touch Screen is a few generations behind it can be found inexpensively on sites like eBay, given enough patience. I purchased a lot of seven with a unit cost of around $12 USD, well below that of the included ARM processor.

The Mini Touch Screens I received are second generation, comprised of a single PCB and LCD assembly. The PCB is universal and only populated with the purchased options. Every PCB is populated with the following components:

The models I have operate using power-over-ethernet. There are other models which run off hard-wired A/C and network using standard 802.11 Wifi. To support power-over-ethernet and ethernet networking the following chips are installed:

If the Mini Touch Screen has the ZigBee option fitted, used to control lighting and other home automation novelties, two additional chips will be populated on the board. This chip pair appears in some of Control4’s other ZigBee enabled hardware:

This device has already been examined from a distance. It is reachable over telnet and this ability is documented by the manufacturer. The root password is also known, documented in OSVDB-73136 and subsequently documented by the manufacturer. I was personally interested in gaining access at the hardware level to monitor the boot process and explore the system in depth. At the same time I wanted to better understand the methods used to reveal passwords on opaque hardware systems.

While poking around inside I was immediately drawn to a four-pin header (J10) which seemed like an ideal candidate for a UART. Between a multimeter and a Jtagulator I determined that it was in fact a standard 3.3V UART running at 56700bps. Pins are numbered right to left: pin 1 is TX, pin 2 is GND, pin 3 is RX, and pin 4 is +3.3VDC.

Capturing the boot process reveals a lot of information about the hardware. The bootstrap environment is Redboot and the device is running a Linux 2.4 kernel. Since this is not a highly custom software stack, further interaction will be much more pleasant. A log of the boot process is availble for download.

I wanted to boot the into Linux’s single user mode in order to gain initial shell access without the need to authenticate myself. During boot it’s possible to drop into Redboot’s own interactive shell environment by interrupting with Ctrl-C during the first few seconds. Redboot can be interrogated to reveal its configuration, which includes the script it follows to bootstrap the system and execute the kernel.

+Ethernet eth0: MAC address 0e:00:00:ea:18:f0
IP: 10.11.200.34/255.255.0.0, Gateway: 10.11.1.1
Default server: 10.11.11.83, DNS server IP: 10.11.11.14

RedBoot(tm) bootstrap and debug environment [ROMRAM]
Non-certified release, version v2_0 - built 13:38:26, Aug 11 2006

Platform: Cirrus Logic EDB9307 Board (ARM920T) Rev A
Copyright (C) 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.

RAM: 0x00000000-0x04000000, [0x000444e8-0x03fbc000] available
FLASH: 0x60000000 - 0x62000000, 128 blocks of 0x00040000 bytes each.
== Executing boot script in 1.000 seconds - enter ^C to abort
^C

RedBoot> fconfig -l
Run script at boot: true
Boot script:
.. fis unlock -f 0x60000000 -l 0x1ffffff
.. mfill -b 0x1000000 -l 0x8000 -p 0x0
.. fis load update_script
.. script -b 0x1000000
.. fis load zImage
.. exec

Boot script timeout (1000ms resolution): 1
Use BOOTP for network configuration: false
Gateway IP address: 10.11.1.1
Local IP address: 10.11.200.34
Local IP address mask: 255.255.0.0
Default server IP address: 10.11.11.83
DNS server IP address: 10.11.11.14
Set eth0 network hardware address [MAC]: true
eth0 network hardware address [MAC]: 0x0E:0x00:0x00:0xEA:0x18:0xF0
GDB connection port: 9000
Force console for special debug messages: false
Network debug at boot time: false

Redboot allows us to pass parameters to the kernel when booting via the exec command. Helpfully, the boot process prints out the kernel parameters normally used. From these I created a new set which would drop me into single user mode.

RedBoot> fis unlock -f 0x60000000 -l 0x1ffffff
... Unlock from 0x60000000-0x61ffffff: ................................................................................................................................
RedBoot> mfill -b 0x1000000 -l 0x8000 -p 0x0
RedBoot> fis load zImage
** Warning - checksum failure.  stored: 0x52bbd379, computed: 0xeaeebcfe
RedBoot> exec -c "root=/dev/mtdblock4 ro single"
Using base address 0x00080000 and length 0x00180000
Uncompressing Linux..................................................... done, booting the kernel.
Linux version 2.4.21-rmk1-crus1.4.5 ([email protected]) (gcc version 3.3) #b1.6.0.10-mt2 Tue Jan 13 17:51:45 MST 2009
CPU: Arm920Tid(wb) revision 0
Machine: edb9307
Security risk: creating user accessible mapping for 0x80000000 at 0xff000000
On node 0 totalpages: 16384
zone(0): 24576 pages.
zone(1): 0 pages.
zone(2): 0 pages.
Kernel command line: root=/dev/mtdblock4 ro single
Console: colour dummy device 80x30
Calibrating delay loop... 99.73 BogoMIPS
Memory: 32MB 32MB = 64MB total
Memory: 62932KB available (1337K code, 378K data, 132K init)
Dentry cache hash table entries: 8192 (order: 4, 65536 bytes)
Inode cache hash table entries: 4096 (order: 3, 32768 bytes)
Mount cache hash table entries: 512 (order: 0, 4096 bytes)
Buffer-cache hash table entries: 4096 (order: 2, 16384 bytes)
Page-cache hash table entries: 16384 (order: 4, 65536 bytes)
POSIX conformance testing by UNIFIX
Linux NET4.0 for Linux 2.4
Based upon Swansea University Computer Society NET3.039
Initializing RT netlink socket
Starting kswapd
JFFS2 version 2.1. (C) 2001 Red Hat, Inc., designed by Axis Communications AB.
i2c-core.o: i2c core module version 2.8.7 (20040611)
i2c-dev.o: i2c /dev entries driver module version 2.8.7 (20040611)
i2c-proc.o version 2.8.7 (20040611)
ttyAM0 at MMIO 0xff8c0000 (irq = 52) is a AMBA
ttyAM1 at MMIO 0xff8d0000 (irq = 54) is a AMBA
ttyAM2 at MMIO 0xff8e0000 (irq = 55) is a AMBA
Enabling backlight, power supply, and LCD screen for NEC and DT
Enabling backlight, power supply, and LCD screen for NEC and DT
Console: switching to colour frame buffer device 40x30
I2C: DS1338 RTC driver successfully loaded
EP93xx touchscreen driver configured for 4-wire operation
ep93xx_eth() version: ep93xx_eth.c: V1.0 09/04/2003 Cirrus Logic
RAMDISK driver initialized: 16 RAM disks of 16384K size 1024 blocksize
SCSI subsystem driver Revision: 1.00
EDB9307-NOR:0x02000000 at 0x60000000
NOR flash on EDB9307: Found 2 x16 devices at 0x0 in 32-bit bank
 Intel/Sharp Extended Query Table at 0x010A
CFI interleave: 2, device type: 2
 Intel/Sharp Extended Query Table at 0x010A
CFI interleave: 2, device type: 2
 Intel/Sharp Extended Query Table at 0x010A
CFI interleave: 2, device type: 2
 Intel/Sharp Extended Query Table at 0x010A
CFI interleave: 2, device type: 2
 Intel/Sharp Extended Query Table at 0x010A
CFI interleave: 2, device type: 2
Using buffer write method
cfi_cmdset_0001: Erase suspend on write enabled
Searching for RedBoot partition table in NOR flash on EDB9307 at offset 0x1fc0000
FIS origin: 0x0
10 RedBoot partitions found on MTD device NOR flash on EDB9307
EDB9307-NOR:using detected partition definition
Creating 10 MTD partitions on "NOR flash on EDB9307":
0x00000000-0x00040000 : "RedBoot"
0x00040000-0x001c0000 : "zImage"
0x001c0000-0x00340000 : "zImage.new"
0x00340000-0x00940000 : "cramfs"
0x00940000-0x00f40000 : "cramfs.new"
0x00f40000-0x01f40000 : "jffs2.img"
0x01f40000-0x01f80000 : "update_script"
0x01f80000-0x01fc0000 : "unallocated"
0x01fc0000-0x01fff000 : "FIS directory"
mtd: partition "FIS directory" doesn't end on an erase block -- force read-only
0x01fff000-0x02000000 : "RedBoot config"
mtd: partition "RedBoot config" doesn't start on an erase block boundary -- force read-only
usb.c: registered new driver usbdevfs
usb.c: registered new driver hub
host/usb-ohci.c: USB OHCI at membase 0xff020000, IRQ 56
usb.c: new USB bus registered, assigned bus number 1
hub.c: USB hub found
hub.c: 3 ports detected
Initializing USB Mass Storage driver...
usb.c: registered new driver usb-storage
USB Mass Storage support registered.
eeprom.o version 2.8.7 (20040611)
NET4: Linux TCP/IP 1.0 for NET4.0
IP Protocols: ICMP, UDP, TCP, IGMP
IP: routing cache hash table of 512 buckets, 4Kbytes
TCP: Hash tables configured (established 4096 bind 8192)
NET4: Unix domain sockets 1.0/SMP for Linux NET4.0.
NetWinder Floating Point Emulator V0.97 (double precision)
VFS: Mounted root (cramfs filesystem) readonly.
Freeing init memory: 132K
init started:  BusyBox v1.1.3 (2008.07.29-19:32+0000) multi-call binary
Starting pid 11, console /dev/console: '/bin/sh'


BusyBox v1.1.3 (2008.07.29-19:32+0000) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

/#

I now have a BusyBox shell but an incomplete environment. /etc/ lacks passwd, the file in which I was most interested. I surmised that init scripts which execute at higher run levels were responsible for finalizing the environment. Consulting /etc/inittab confirmed my suspicions.

/# cat /etc/inittab
# This is run first except when booting in single-user mode.
#

::sysinit:/etc/rc.sysinit
::sysinit:/etc/rc.sysinit1
ttyAM0::askfirst:/bin/login
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/etc/init.d/watchdogd die
::shutdown:/etc/init.d/rc0
::shutdown:/sbin/swapoff -a
::shutdown:/bin/umount -a -r

Executing the two sysinit scripts take care of the necessary steps to mount the read-write partition of the flash which holds the rest of the operating environment. Really, only rc.sysinit1 is needed for this. rc.sysinit is entirely concerned with performing a system upgrade if a specially formatted USB drive is plugged in.

/# cd /etc/
/mnt/jffs2/etc# ./rc.sysinit
Starting up...
Making ramdisks...
ext2fs_check_if_mount: No such file or directory while determining whether /dev/ram0 is mounted.
*** Calling usbrestore ***
+ echo Mount proc and usbdevfs
Mount proc and usbdevfs
+ mount /proc
+ mount /dev/sda1 /mnt/usbrestore
mount: Mounting /dev/sda1 on /mnt/usbrestore failed: No such device or address
+ sleep 1
+ umount -f /mnt/usbrestore
umount: forced umount of /mnt/usbrestore failed!
+ mount -t usbdevfs none /proc/bus/usb
+ [ 0 -ne 0 ]
+ echo Checking for USB Restore:
Checking for USB Restore:
+ [ -e /usr/bin/usbrestore ]
+ /usr/bin/usbrestore
Device is a Mini Touchscreen Type 2
Initialize returned false -- Version 1.7.4.1
+ VAR=0
+ echo umount proc/bus/usb and /proc
umount proc/bus/usb and /proc
+ umount /proc/bus/usb
+ umount /proc
+ echo_success
+ echo -n Success
Success+ echo

+ return 0
*** usbrestore finished ***
mount: Mounting usbdevfs on /proc/bus/usb failed: No such file or directory
/mnt/jffs2/etc# ./rc.sysinit1
    mode:         16386
-o  offset:       0
-f  frequency:    -3200000
    maxerror:     16384000
    esterror:     16384000
    status:       64 ( UNSYNC )
-p  timeconstant: 2
    precision:    1
    tolerance:    33554432
-t  tick:         9991
    time.tv_sec:  10883
    time.tv_usec: 272973
    return value: 5 (clock not synchronized)
Wed May 21 16:19:00 PDT 2008
Loading modules:
  watchdog
  zd1211b

 _____     ____    _    ____
|__  /   _|  _ \  / \  / ___|
  / / | | | | | |/ _ \ \___ \
 / /| |_| | |_| / ___ \ ___) |
/____\__, |____/_/   \_\____/
     |___/
ZD1211B - version 2.15.0.18-20090113
usb.c: registered new driver zd1211b
  zd1211_mod

 _____     ____    _    ____
|__  /   _|  _ \  / \  / ___|
  / / | | | | | |/ _ \ \___ \
 / /| |_| | |_| / ___ \ ___) |
/____\__, |____/_/   \_\____/
     |___/
zd1211 - version 2.15.0.18-20090113
usb.c: registered new driver zd1211
  ip_tables
ip_tables: (C) 2000-2002 Netfilter core team
  ipt_LOG
  ipt_mark
  ipt_tcpmss
  ipt_conntrack
  ipt_multiport
  ipt_tos
  ip_conntrack
ip_conntrack version 2.1 (512 buckets, 4096 max) - 160 bytes per conntrack
  ipt_limit
  ipt_pkttype
  iptable_filter
  ipt_mac
  ipt_state
  arptable_filter
  arp_tables
arp_tables: (C) 2002 David S. Miller
  ybuttons
  yencoder
Using interruptable GPIO to run encoder
  ydriver
ydriver: backlight setup for edb9307 hardware
  ep93xx-audio
  stac9758
EP93xx Ac97 audio support initialized (8384-7658).

Starting Watchdog timer manager...Watchdog at attention.
done.
killall: c4server: no process killed
ep93xx_eth: Disabled Auto MDIX on ICS Phy
TIME OUT: No Ethernet Signal Detected - check the cable
dhcpcd[247]: broadcasting DHCP_REQUEST for 10.10.10.101

dhcpcd[247]: Waiting 4000000 usec for a response...
killall: c4server: no process killed
Starting Control4 Button Watcher
Starting Syslog Daemon...
Starting Dropbear Server
Checking for server keys...
Starting Telnet Daemon...
No upgrade detected.
Checking image parity...detected. All systems go.
Checking for jffs2 corruption...clean.
Starting upmand: Success
Starting Cron Daemon...
Starting Dropbear Server
Checking for server keys...
Starting System Manager...done.
mount: Mounting none on /proc/bus/usb/ failed: Device or resource busy
/mnt/jffs2/etc#

I am now able to interrogate /etc/passwd to retrieve the crypted root password. Given what we know about the plain text password it would take an exhausing amount of time to brute-force it. It has enough complexity to be resistant to rule-based dictionary attacks. It’s quite fortunate that someone else has already released it. If someone had not I would look inside upgrade packages released by the manufacturer, examine the binaries on the filesystem, and finally resort to brute-force.

/# cat /etc/passwd
root:$1$$Y4p4VBptNwWmJyv9SRq3U.:0:0:root:/:/bin/sh
bin:*:1:1:bin:/bin:
daemon:*:2:2:daemon:/sbin:
adm:*:3:4:adm:/var/adm:
lp:*:4:7:lp:/var/spool/lpd:
sync:*:5:0:sync:/sbin:/bin/sync
shutdown:*:6:0:shutdown:/sbin:/sbin/shutdown
halt:*:7:0:halt:/sbin:/sbin/halt
mail:*:8:12:mail:/var/spool/mail:
news:*:9:13:news:/var/spool/news:
uucp:*:10:14:uucp:/var/spool/uucp:
operator:*:11:0:operator:/root:
games:*:12:100:games:/usr/games:
gopher:*:13:30:gopher:/usr/lib/gopher-data:
ftp:*:14:50:FTP User:/:
nobody:*:99:99:Nobody:/:

I now have access to the existing operating system. With the level of access achieved so far I can update root’s password to access the device under normal operation. However, my primary interest lies in flashing an updated kernel and environment to the device via Redboot. I will cover that in detail in another post.

Return to all posts