Vuln research on the WAG54G home router
Intro to bug hunting on an embedded device
Intro to bug hunting on an embedded device
To avoid the typical intro preamble, let’s dive straight into the juicy bits of doing this research.
While we already had command line access to the WAG54G available through the serial console, we chose to find another way of gaining remote access to the device for some added flavor. Having console access is an important first step in understanding how the device works and beginning analysis. The WAG54G router comes with an option to enable remote management via Telnet, and can be enabled using its web interface:
Unfortunately the default shell is restricted and only exposes typical “admin” commands that are available through the routers web interface. This means we lose the ability to explore the underlying Linux OS and filesystem, and basically looks something like this:
Well that’s just not good enough. One option is to exploit a vulnerability in the shells command line parsing, which is a promising vector and quickly revealed trivial bugs like the following:
However it still feels a little dirty even having to see the custom shell prompt, surely there’s a better way of breaking out? The bug above is nice enough to show us the admin users shell is /bin/configurator
. What if we can update that entry to point to /bin/sh
?
Fortunately, Protip #1 of router hacking dictates: When thou needeth a shell, pop a command injection into the “diagnostic ping” page. Rumor has it that 80% of the time, it works every time.
Voilà! The command injection in ping_interval
overwrites /etc/passwd
with a new entry for admin, and successfully breaks out of the restricted shell. The next time we try authenticating over Telnet, we’re greeted with a friendly busybox prompt:
So far so good, but this hasn’t technically advanced any further than our previous blog post. The next steps are where things get better, we use the WAG54G devices tftp
client to upload binaries and library dependencies onto our laptop for offline analysis.
Now we’re finally ready to begin the real adventures. To get a lay of the land, we ran the file
command against the binaries to see how they’re linked:
Learning that our target is a dynamically linked (and stripped) ELF executable compiled for the 32-bit MIPS little endian architecture. Having a copy of the MIPS instruction set documentation handy for reference, an iced-tea, and a copy of IDA Pro - we’ve got everything we need to begin hacking.
This vulnerability is not going to stop the press, but it was a personal moment of celebration. It’s significance shows that we understand enough about the MIPS instruction set to successfully find bugs!
The following screenshot shows a fragment of code which parses an HTTP request, attempting to break apart the request method from the URI by calling the strsep()
libc function:
The problem is strsep()
can set *curptr
to NULL
if the end of the source string is reached and no tokens are found. This condition is not tested for in the code, and as a result the dereference at 0x00407898
causes an access violation reading unmapped memory.
The following commands can be used to verify the issue (note the lack of whitespaces):
Which results in the following segmentation fault:
The next bug we came across was slightly more interesting. The code attempts to parse the Host:
header while copying its value into the re_ip_des
global char array. The problem is the use of strcpy()
which performs an unbounded copy using an attacker supplied string, and the destination is of a fixed-length (~64 byte) buffer. By sending a large value in the header, an attacker can exploit this to overwrite other global variables on the heap - a construct which might be useful for privesc:
The following commands can be used to verify the issue:
In which the entry_config_buf
variable is after re_ip_des
and is overwritten with “BBBB”:
The final bug we came across is potentially the most interesting, however it’s triggered post-auth so would need to be combined with another vulnerability to be useful.
The issue itself is a result of calling fread()
into a fixed-size global buffer, but using an unbounded Content-Length
size which has been provided by the remote user:
What is nice about this construct is global_post_buffer
is 10,000 bytes in size, and is directly followed by function pointers for handling mime types and other goodies. This makes exploitation relatively straight forward:
The following commands can be used to verify the issue:
NB: The auth token is required in this case, as POST requests are only handled after a connection has been authenticated.
To ensure that our understanding of MIPS assembly was correct, it was necessary to perform runtime testing on the binaries and ensure our triggers lead to a crash. While this activity could have been done against the WAG54G device itself, we chose to use an emulated environment with full control over tools and debuggers. We achieved this by using QEMU.
A great stack exchange post can be found here which details much of the needed steps to get ready. On our OSX laptop with the brew package manager, these are the commands that were used:
Once the machine has booted we can update it and install our binaries:
The following screenshot shows what it looks like running the httpd in our emulated environment:
Although we are successfully running the executables in our own environment, several errors related to /dev/nvram
access are causing “401 Unauthorized” errors. This may limit the amount of code we are able to exercise.
To resolve this issue, we decided to perform LD_PRELOAD
hooking to intercept requests to the nvram device and send custom responses back. The hooks used an export of the WAG54G routers configuration, which was decoded with the tool here. The following Vim macro was used to convert the tools output into a C like structure, representing the devices configuration as key-value pairs:
The final version of the nvram hooking code can be downloaded here.
Re-executing the daemon with the hook shows no further errors, indicating we have successfully emulated the runtime found on the physical device.
Using the above steps, we have successfully started the process of vulnerability discovery and proof of concept development against the router. In a future blog post, we hope to explore ways in which these vulnerabilities can be exploited to enable flashing C&C firmware onto the device pre-auth.
If you’re wondering about the disclosure timeline for these bugs, long story short the WAG54G has reached end-of-life support. If you’re an internet hero, you can always release your own updates! or choose to flash your router with the great OpenWRT firmware.
Vuln research on the WAG54G home router
October 2024 - A Monocle on Chronicles
August 2024 - DUCTF 2024 ESPecially Secure Boot Writeup
July 2024 - plORMbing your Prisma ORM with Time-based Attacks
June 2024 - plORMbing your Django ORM
January 2024 - Keeping up with the Pwnses
October 2023 - Exploring the STSAFE-A110
elttam is a globally recognised, independent information security company, renowned for our advanced technical security assessments.
Read more about our services at elttam.com
Connect with us on LinkedIn
Follow us at @elttam