The Firmware Exploitation Methodology
In part two of our firmware analysis, we discovered a potential overflow in the administration server,
alphapd. It appears if you send a long string in the
WEPEncryption field to
wireless.htm, it can cause a buffer overflow.
At this point, we still don’t want to buy the camera until we prove the vulnerability is exploitable. So, how do we prove it? Via emulation!
Emulating Binaries Found in Firmware
The easiest way (usually) to quickly emulate binaries that don’t match the architecture of our machine is to use QEMU, which stands for Quick Emulator. QEMU supports a ton of architectures including the one we need, MIPS, and it’s pretty simple to use.
However, we can’t just throw the
alphapd binary at QEMU and expect it to run. The device needs to perform a setup process before running
alphapd. And, we need to change our root directory so when
alphapd runs, it uses the libraries in the firmware. We don’t want it using our local libraries. To do this, we’ll use the chroot command.
Chroot will sandbox our command to a specified directory essentially making it the root directory for that command. Since we are changing the root to the firmware’s directory, we also need a statically linked version of QEMU copied into the root of the firmware. Running the file command will tell us the architecture so we know which version of QEMU to grab.
The giant MIPS tells us it’s…. MIPS. The LSB, or least-significant byte, indicates it is little endian. From there we can chroot and run
And it’s an immediate fail. But this is expected behavior. We jumped right to running a server on a system that expected some setup to have been performed and none of that happened. Some missing file and missing directory errors are expected. So we just run the server and keep fixing errors as they come up. Some of the errors, like the one we see now
alphapd: cannot open pid file will require looking at the disassembly and tracing the errors back to their source. In this case: a missing file.
Very early in main, the server attempts to open the PID file along this path
/var/run/alphapd.pid. But the
run directory does not exist. So, we can just create that directory as well as the PID file.
The next error is a little more challenging and deserves its own blog post.
please execute nvram_daemon first
The server is waiting for the NVRAM daemon to start. That will never happen because this is hardware based. The only option is to emulate NVRAM as well.
This tool compiles to a library that is meant to expose functionality with the same prototype the server is expecting of its NVRAM function calls. Instead of the real call being executed and calling out to hardware, our calls will return prefabbed data from a file.
But how do we make
alphapd use our calls instead of the real calls?
There’s a handy Linux environment variable, LD_PRELOAD that allows for specifying libraries to be loaded before any others. Preloading it means that its functions will be used before others of the same prototype in later libraries.
The most difficult part of this whole process is compiling the nvram-faker library with the same, or similar enough, toolchain so it will run. It’s not unusual to have to try different toolchains. And you might need to copy over some libraries from that toolchain to the firmware’s
lib/ directory. Luckily, I have one that is close enough, but I did need to copy a few libs from the toolchain.
On top of LD_PRELOADing nvram-faker, we also need to create a PID file for the non-existant NVRAM daemon.
Now it’s running but it quickly crashes because it didn’t find a valid value for a variable it requested from NVRAM. We need to find the values that NVRAM is loading by default from the factory. These values usually exist somewhere in the file system. It just takes a little searching.
The nvram-faker library provides logging output each time a value is accessed. Therefore, we know exactly what values the binary is expecting. We can search for these in the unpacked firmware.
This directory contains everything we need to populate a file that nvram-faker can parse and use to return values. Once that is set, we can emulate the server and try requesting the main page.
Because we are running a local QEMU, a request to
https://127.0.0.1 is sent directly to
alphapd. And it actually returns a page. Awesome! That wasn’t so hard, right?
Triggering the Firmware Exploit
The server is running now. We can make requests and it will send responses. We can even navigate around the camera’s configuration pages. What happens if we try to trigger our exploit?
Hmm. Unable to connect. That’s unfortunate. Did we type something wrong? Does that page not exist? Going back to the terminal where we ran
alphapd, we see some interesting output indicating that it may have worked.
alphapd crashed when it tried to process that URL. Actually, this is good news. It could indicate that we overflowed the stack and jumped to address 0x41414141 (AAAA). Only one way to find out: run a debugger on the server.
Fortunately, QEMU has a handy option (-g) that runs a GDB server and waits for a connection. Once it is waiting, we can use IDA to connect and interactively step through the server while it’s processing the URL we sent.
The part we care about is the epilogue of the function that our overflow occurred in. The epilogue will restore the saved register, frame pointer, stack pointer, global pointer, and return address to their values before this function was called. These values are restored directly from the stack. If everything works, it should be full of ’A’s and they are.
Full System Emulation
We need to take this emulation one step further before we can declare absolute victory. Our emulation was performed on an Intel system. When
alphapd tries to execute a system call, it will be attempting to run a MIPS binary on an Intel system, which will fail every time.
So our next step is to emulate the full system so when the server tries to execute other programs, those programs actually work. To perform full system emulation, we will need a virtual machine (VM) that matches the target’s architecture.
Building a VM is an in-depth process so I’m not going to go through it here. But here’s a link that explains how to build a MIPS Debian VM with a newer kernel.
Once everything is up and running in a full system emulation environment, we’ll notice that
alphapd now requests a password when logging in, which makes this an authenticated exploit.
The next hurdle is that we are forbidden from requesting
wireless.htm even after authenticating.
But if we navigate manually to
wireless.htm through the GUI, everything is fine. So why the difference?
We’ll use Firefox’s Web Developer Tools to look at the requests sent to the server. What we find is the lack of a
referer field in the forbidden request. Therefore, we need to add this field to our request.
Now when we send the request, the server crashes indicating we successfully overflowed the buffer!
To Be Continued…
By emulating the firmware’s
alphapd binary, we have proven that the
strcpy function is vulnerable by sending a request to the server. So far it’s been completely cost-free to validate. No actual hardware needed.
Next time we are going to put on our big-boy hacking pants and write a ROP chain to exploit this vulnerability. Then watch the magic happen!
About the Author
Evan Walls is a vulnerability analyst and developer at Tactical Network Solutions, focusing on embedded system exploitation. When he isn’t searching for new exploits, he teaches training courses developed by TNS, including IoT Firmware Exploitation. Prior to working at TNS he was a Windows developer for the Department of Defense. Now that he’s seen the glory and freedom that is Linux he vowed never to use another windows development machine again.