Finding and exploiting command injection vulnerabilities can have tremendous reward for the time invested. One thing that makes this type of vulnerability extremely nasty in IoT/embedded devices, is that web server processes are often running with root privileges — this means there is no further privilege escalation needed to obtain full control of the target device. Injecting and running shellcode is also not necessary like with memory corruption vulnerabilities. IoT devices seem to be full of command execution vulnerabilities because often the code running on web management interfaces is made up of simple scripts (like python or CGI) that simply accept input and feed it straight to operating system commands. In a more modern web application built with Multitier architecture, and using concepts like MVC, additional layers of sanitization and strong typing exist that can help prevent command injection vulnerabilities.

Initial dynamic analysis pass

In the first post of this “Professional IoT Hacking” series, we decompressed the firmware for our target Vivotek FD1836 network camera, and identified the filesystem location for scripts and binaries being used by a Boa web server management interface. In order to have a fully functioning version for dynamic analysis, we purchased the device, connected it to a Power over Ethernet (PoE) connection, and placed it inside a lab network. Upon booting the device, it was possible to interact with the web management interface so we piped our browser traffic through the interception proxy Burp Suite and proceeded to map out the web application. As can be observed in the screen captures below, the web management interface seems to mirror the files identified in the decompressed firmware.

By simply using Burp Suite’s scanner functionality to dynamically fuzz all of the web request inputs, we did not discover command injection. In addition to that, the tool commix was used to dynamically fuzz for command execution, without any successful results. Both of these tools are great for dynamic analysis, but such out-of-the-box automation is only useful to a point. How can we improve our command injection fuzzing to hunt deeper bugs? What information can we glean from static analysis of the firmware that could be used to improve our command injection fuzzing? How can we succeed where most dynamic-only assessments would give up?

Combining static and dynamic analysis

One advantage we have on the static analysis front is the ability to view information about binaries that are running on the actual device. If we view the contents of “../squashfs-root/usr/bin/” we can observe that busybox is being used. We also notice that busybox supports the “wget” command. In our first pass at fuzzing web parameters for command injection, we wondered: did our toolset provide full coverage of binary paths, and did the automation check for remote blind command injection by attempting to trigger commands like “ping,” “nslookup,” or “wget?”

Taking this information from statically analyzing the decompressed firmware, what would happen if we tried injecting a full path to the “wget” binary or symbolic link and specified a remote web server? Its time to try this method out with Burp Suite repeater. On the left side of the screen capture below, we captured a request between our browser and the web management interface of the target device, injected a full path reference to the “wget” binary with a specified remote web server(/usr/bin/wget, and then replayed the request to our device. On the right side of the screen capture below, our remote web server at received a request for the “whatthe?” page from our target device.

This successfully demonstrates that we obtained blind remote command execution. By using static analysis of the decompressed firmware and combining it with manual injection attempts, we were able to succeed where simple dynamic-only analysis might not. We used this methodology to find another command injection vulnerability in our target device. Both command injection vulnerabilities are pending CVE numbers (CVE-2018-14494, CVE-2018-14495).

Lets rain some shellz

On many IoT devices, the common ways to quickly create reverse and bind shells for remote command and control (C2) are not always there. For example, our target device does not support many of the common languages like perl, python, ruby, or php. Lets examine the device to look for something native we can use to establish remote C2. We could use “wget” to download and then execute an ARM binary stager, but that would place artifacts on disk. After a little more digging around the decompressed firmware, we located the “telnet” and “telnetd” binaries.

Using “telnetd” for a remote shell should do the trick. Besides simply using the “telnetd” binary to create a simple bind shell, this reverse shell cheat sheet contains a great way to establish a remote shell from the target device to an IP address of our choice. By injecting the payload “/usr/sbin/telnetd -p37 /bin/sh,” a successful bind shell on TCP port 37 was established. On the right side of the screen capture below, you can see that we connected to our target device over TELNET as the “root” user.

Next steps

In this post we covered some basics about hunting command injection and learned that we can typically find vulnerabilities faster by leveraging static and dynamic analysis together. One of the things we noticed about this device is that some of the web management functionality is composed of simple CGI scripts, and other components are actual 32-bit ARM binaries. In the next post in this “Professional IoT Hacking” series, we will extract some of the ARM binaries and perform some static analysis to hunt memory corruption vulnerabilities with IDA Pro.