Backdooring a TP-LINK Router

Today we’ll be installing a backdoor into a common TPLINK home router, the TL-WR841N. It can be found on Amazon for only $22.99 (what a steal!). Not only is it cheap, but it was also prove as an easy introduction to router firmware.


First, we need to get our hands on the firmware for our router. Head on over to this page in order to download the firmware for your version of the router. To find out what version firmware you should download, you can look on the back of your router and will find the version number next to the model label.


Next, follow this step-by-step procedure:

  1. Download the firmware image for the TP-LINK TL-WR841N Router using the following link:
  2. Download and unzip the firmware_mod_kit using the following link:

NOTE: You can find other copies of this kit online but I had to fix some of the utilities it provides to work with this router (and its already compiled).

  1. Run the following commands to get binwalk, lzma, and zlib:
sudo apt-get install binwalk       
sudo apt-get install zlib1g-dev
sudo apt-get install liblzma-dev
  1. Use the tool to automatically parse out the kernel and SquashFS filesystem.x3
  2. You will now find that there are three folders located in the target directory of extracted-firmware:x4
    1. Image_parts – these are the binary parts of the original firmware image that were used to create the filesystem
    2. Logs – these are the logs created from the tools binwalk and unsquashify which the tool used to analyze the router firmware file.
    3. Rootfs – this is the squashfs filesystem that holds all of the executables and files used for the router’s web interface. This is the juicy stuff and what we’ll be playing with.
  3. Take a look inside the rootfs folder. You’ll see that the layout closely resembles the standard root directory of a *nix OS. Explore the directories until you get a feeling of where everything is.
  4. When you enter the bin/ directory you will notice that almost all of the files are highlighted blue. This is because these executables were spawned and symbolically linked to the busybox utility. Busybox is extremely common amongst embedded systems and to quote their website: “Busybox combines tiny versions of many common Unix utilities into a single small executable.” In other words, busybox allows us to invoke ubiquitous commands (such as ls, cat, ifconfig) by providing those said commands as an argument to its execution.


So if I wished to run ls using busybox, I could simply run the command “busybox ls”. Because of how compact busybox is and the way it can be configured to support only the commands that the device needs to operate, embedded devices almost always have a version of busybox on their system. The blue-colored files in the bin/ directory indicate symbolically linked files that are simply linked for convenience-sake so scripts don’t need to write “busybox” before every command.

Try to run one of the commands by either running ./busybox [command] or simply ./[command] by itself. You will see that you get an invalid ELF error. This is because we are running on an x86_64 architecture which is incapable of understanding the commands of these files. If you run the “file” command on one of the executables, you will see the following:

Wouldn’t it be great if we could run these commands to see what they do? Well what do you know, there exists an emulator for various processors called “qemu”. Although qemu can emulate many processors, we only need the 32bit MIPS emulator which you can download from the following link:

(chmod u+x qemu-mips)

All the qemu emulators are available in the Ubuntu repo and can be installed used apt-get. Unfortunately, the MIPS emulators that are statically compiled (which we need as opposed to dynamically compiled for reasons we’ll explore later) are out of date and will not work with the stripped executables in this firmware’s filesystem. Therefore, the download link provided above is an ELF that I compiled and statically linked myself and must be used instead of the Ubuntu packages.

  1. Now that you have the qemu MIPS emulator, you can use it run the any of the commands located in the bin directory. Why is this important if we obviously know what ls, cat, etc. do? Because if we want to install a backdoor onto this firmware, we sure as hell need some way to listen for commands across the network. So first we need to see what commands we have available to use via busybox. Copy qemu-mips to the rootfs folder and use chroot and qemu to run the busybox command without any arguments, You will get a list of all of the commands it supports. We need to use chroot so that the executables know to use the shared libraries in the rootfs/lib folder instead of the ones that our architecture uses in our /lib folder.

As you can see, it doesn’t support that many. Also it looks as though it doesn’t offer any way to listen for commands (i.e. netcat). So what we’re going to do is replace busybox with our own that offers a much more commands and most importantly, “nc”.

Busybox allows you to specify what commands you want supported at compile time so to save space, I kept all of the commands that the firmware’s busybox offered in addition to a few more that we’ll need including “nc”.

Download the MIPS 32 capable busybox binary I compiled from the following link:

Then we’re going to replace the busybox in the /bin file with our new well-equipped one.

Run the busybox command without any arguments one more time and we’ll see that we have much more to work with.

  1. Now that we have netcat to work with, we need to find a way to automatically start listening for commands when the router starts up. The best way to do this is to look for bash scripts in the filesystem and add our backdoor with “nc”. To save you the trouble, there is a bash script located in /etc/rc.d named rcS:

This is definitely what we’re looking for. So let’s drop our nc command in this script, save the file, and finish our investigation into this router’s firmware.

  1. We now have an adapted busybox executable that supports netcat and the corresponding backdoor build into one of the init scripts. Although we’d love to build the firmware back up again, we have a bit of a problem. Our firmware image would be slightly bigger than the original due to the increase in the size of busybox and those few extra bytes we added to the rcS script. So we’re going to be super hacky and delete all of the help files from the web/ directory. Ideally we would parse through the firmware and know it like the back of our hands so we can cut corners in various places in order to avoid a user seeing a difference between the firmwares. But this will work for now.
  2. Now that we have inserted our backdoor and reconciled for our increase in size, we can rebuild the firmware and flash it to the router. To rebuild the firmware, we are going to use the utility provided by our trusty firmware_mod_kit. Make sure to use the -min command in order to increase the block size of the firmware to decrease the overall size of our new firmware image.
  3. Once finished, we can connect the router’s interface by contacting and upgrade the firmware. Most routers perform some sort of MD5 hashing authentication on the firmware image to ensure it is not custom/malicious. TP-Link does not. It simply checks the filename of the firmware image and a few of the section headers.





Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s