Azeria Labs Azeria Labs
  • ARM Assembly
    • Part 1: Introduction to ARM Assembly
    • Part 2: ARM Data Types and Registers
    • Part 3: ARM Instruction Set
    • Part 4: Memory Instructions: LDR/STR
    • Part 5: Load and Store Multiple
    • Part 6: Conditional Execution and Branching
    • Part 7: Stack and Functions
    • Assembly Basics Cheatsheet
  • Online Assembler
  • Exploitation
    • Writing ARM Shellcode
    • TCP Bind Shell in Assembly (ARM 32-bit)
    • TCP Reverse Shell in Assembly (ARM 32-bit)
    • Process Memory and Memory Corruption
    • Stack Overflows (Arm32)
    • Return Oriented Programming (Arm32)
    • Stack Overflow Challenges
    • Process Continuation Shellcode
    • Glibc Heap – malloc
    • Glibc Heap – free, bins, tcache
    • Part 1: Heap Exploit Development
    • Part 2: Heap Overflows and the iOS Kernel
    • Part 3: Grooming the iOS Kernel Heap
  • Lab Environment
    • ARM Lab VM 1.0
    • ARM Lab VM 2.0
    • Debugging with GDB and GEF
    • Emulate Raspberry Pi with QEMU
    • Running Arm Binaries on x86 with QEMU-User
    • Emulating Arm Firmware
  • TrustZone Research
    • TEEs and Arm TrustZone
    • Trustonic’s Kinibi TEE
  • Self-Improvement
    • Deep Work & The 30-Hour Method
    • Paradox of Choice
    • The Process of Mastering a Skill
  • About
Azeria Labs Azeria Labs
  • ARM Assembly
    • Part 1: Introduction to ARM Assembly
    • Part 2: ARM Data Types and Registers
    • Part 3: ARM Instruction Set
    • Part 4: Memory Instructions: LDR/STR
    • Part 5: Load and Store Multiple
    • Part 6: Conditional Execution and Branching
    • Part 7: Stack and Functions
    • Assembly Basics Cheatsheet
  • Online Assembler
  • Exploitation
    • Writing ARM Shellcode
    • TCP Bind Shell in Assembly (ARM 32-bit)
    • TCP Reverse Shell in Assembly (ARM 32-bit)
    • Process Memory and Memory Corruption
    • Stack Overflows (Arm32)
    • Return Oriented Programming (Arm32)
    • Stack Overflow Challenges
    • Process Continuation Shellcode
    • Glibc Heap – malloc
    • Glibc Heap – free, bins, tcache
    • Part 1: Heap Exploit Development
    • Part 2: Heap Overflows and the iOS Kernel
    • Part 3: Grooming the iOS Kernel Heap
  • Lab Environment
    • ARM Lab VM 1.0
    • ARM Lab VM 2.0
    • Debugging with GDB and GEF
    • Emulate Raspberry Pi with QEMU
    • Running Arm Binaries on x86 with QEMU-User
    • Emulating Arm Firmware
  • TrustZone Research
    • TEEs and Arm TrustZone
    • Trustonic’s Kinibi TEE
  • Self-Improvement
    • Deep Work & The 30-Hour Method
    • Paradox of Choice
    • The Process of Mastering a Skill
  • About

Emulating ARM Router Firmware

There are various reasons you might want to emulate firmware. If you want to do security research on router firmware, for example, emulation can help you debug certain services and look for vulnerabilities. You could also debug IoT firmware without emulating it. In that case you would gain root on the device via hardware hacking and drop gdbserver on the device and debug services remotely. But what if you don’t have the device? You download the firmware and emulate it.

In this post, I will show you how to emulate Arm router firmware. First, you need an Arm environment. Don’t have a spare Arm processor? No problem, QEMU is your friend!

For those of you who want to save time and get straight into it, I have prepared a new Lab VM that contains:

  • QEMU emulated Armv7 environment ready to start
  • Two different Tenda router firmware versions (AC6 and AC15)
  • All scripts necessary to start the firmware emulation
  • Two small Arm exploitation challenges to learn the basics of bypassing XN (more details in the next blog post)

Download the Lab VM here.

Extracting Firmware

Let’s say you want to emulate the Tenda AC6. Many vendors let you download firmware versions from their website. Once you chose and downloaded your firmware, you need to unpack and extract the binary with binwalk.

user@Azeria-Lab-VM $ wget https://down.tendacn.com/uploadfile/AC6/US_AC6V1.0BR_V15.03.05.16_multi_TD01.rar
user@Azeria-Lab-VM $ unrar e US_AC6V1.0BR_V15.03.05.16_multi_TD01.rar 
user@Azeria-Lab-VM $ binwalk -e US_AC6V1.0BR_V15.03.05.16_multi_TD01.bin

DECIMAL       HEXADECIMAL     DESCRIPTION
--------------------------------------------------------------------------------
64            0x40            TRX firmware header, little endian, image size: 6778880 bytes, CRC32: 0x80AD82D6, flags: 0x0, version: 1, header size: 28 bytes, loader offset: 0x1C, linux kernel offset: 0x1A488C, rootfs offset: 0x0
92            0x5C            LZMA compressed data, properties: 0x5D, dictionary size: 65536 bytes, uncompressed size: 4177792 bytes
1722572       0x1A48CC        Squashfs filesystem, little endian, version 4.0, compression:xz, size: 5052332 bytes, 848 inodes, blocksize: 131072 bytes, created: 2017-04-19 16:18:08

user@Azeria-Lab-VM $ cd _US_AC6V1.0BR_V15.03.05.16_multi_TD01.bin.extracted

What you want from this is the Squashfs filesystem.

user@Azeria-Lab-VM $ ls _US_AC6V1.0BR_V15.03.05.16_multi_TD01.bin.extracted/ | grep squashfs-root
squashfs-root

Inside the Azeria Labs VM, boot up the ARMv7 environment by clicking on the blue ARM icon in the sidebar. Wait until you see the following screen.

This is the terminal you can start your firmware emulation in. The emulation will make constant noise by spitting errors saying it can’t access certain peripherals.

Let’s start with the firmware emulation. From the folder binwalk extracted, run the following command to transfer the squashfs-root to the Arm environment.

user@Azeria-Lab-VM $ rsync -av squashfs-root user@192.168.0.1:/home/user/Tenda-AC6

Minimize this terminal and open Terminator (red terminal icon in the side bar). Terminator is neat because it let’s you split screens more easily. You can SSH into the Arm environment with the shortcut “ssh arm”.

You can install Terminator with:

user@Azeria-Lab-VM $ sudo apt-get install terminator

In your Arm environment, you should now have a folder with the squashfs-root of the firmware you extracted. In this folder, you create a script that starts the emulation. Normally, and in most cases, this process is simple and the script looks like this:

# disable ASLR
sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"

# Switch to legacy memory layout. Kernel will use the legacy (2.4) layout for all processes
sudo sh -c "echo 1 > /proc/sys/vm/legacy_va_layout"

# Mount special folders to the existing Debian ARM environment to provide the emulated environment awareness of the Linux surroundings
sudo mount --bind /proc /home/user/Router/squashfs-root/proc
sudo mount --bind /sys /home/user/Router/squashfs-root/sys
sudo mount --bind /dev /home/user/Router/squashfs-root/dev

# Trigger the startup of the firmware
sudo chroot /home/user/Router/squashfs-root /etc/init.d/rcS

Router firmware emulation is not magic, it’s as simple as the above script. However, turns out there are always exceptions to the rule. The first time I tried emulating the Tenda AC6 firmware, this script didn’t work and the process kept crashing without booting up in the first place. I solved this problem in a rather messy way, by reverse engineering the firmware and tracing back which parameters it’s complaining about. I wrote a program (hooks.c on Github)to simply give it what it wants and voila, it worked. I thought this was a very custom way of making this specific version of the firmware work. To my surprise, emulating a different Tenda firmware (AC15) resulted in the same problem, and guess what? The hooks I coded for the AC6 firmware still worked. I haven’t tested it on other Tenda firmware versions, but if seeing it work on the two I randomly selected made me want to release it for people who might run into the same problem. And who know, maybe it works for more Tenda versions? You can find the code on the Azeria Labs GitHub and on the Lab VM.

But let’s quickly go through the process of cross-compiling it for your emulation:

user@Azeria-Lab-VM $ wget https://uclibc.org/downloads/binaries/0.9.30.1/cross-compiler-armv5l.tar.bz2 
user@Azeria-Lab-VM $ tar xjf cross-compiler-armv5l.tar.bz2 
user@Azeria-Lab-VM $ wget https://raw.githubusercontent.com/azeria-labs/Arm-firmware-emulation/master/hooks.c
user@Azeria-Lab-VM $ cross-compiler-armv5l/bin/armv5l-gcc hooks.c -o hooks.so -shared
user@Azeria-Lab-VM $ scp hooks.so user@arm:/home/user/Tenda-AC6/squashfs-root/hooks.so

Inside the Arm environment, cd to the folder you transferred the squashfs-root to and download the emulate.sh script.

user@azeria-labs-arm:~/Tenda-AC6$ wget https://raw.githubusercontent.com/azeria-labs/Arm-firmware-emulation/master/emulate.sh

The emulation script looks similar to the one I mentioned earlier, with the difference that it runs with the hooks.so file.

# Script to emulate Arm-based router firmware. This example is based on a QEMU emulated Debian environment. 
# You can download the VM with the QEMU Armv7 emulation (link in README)

# br0 interface existence is necessary for successful emulation
sudo ip link add br0 type dummy

# Disable ASLR for easier testing. Can be re-enabled with the same command by replacing 0 with 1 or 2.
sudo sh -c "echo 0 > /proc/sys/kernel/randomize_va_space"

# Switch to legacy memory layout. Kernel will use the legacy (2.4) layout for all processes to mimic an embedded environment which usually has old kernels
sudo sh -c "echo 1 > /proc/sys/vm/legacy_va_layout"

# Mount special linux folders to the existing Debian ARM environment to provide the emulated environment with the Linux context.
# Replace /home/user/Tenda with the path to your extracted squashfs-root. 
sudo mount --bind /proc /home/user/Tenda/squashfs-root/proc
sudo mount --bind /sys /home/user/Tenda/squashfs-root/sys
sudo mount --bind /dev /home/user/Tenda/squashfs-root/dev

# Set up an interactive shell in an encapsulated squashfs-root filesystem and trigger the startup of the firmware.
# Replace /home/user/Tenda with the path to your extracted squashfs-root. 
sudo chroot /home/user/Tenda/squashfs-root /bin/sh -c "LD_PRELOAD=/hooks.so /etc_ro/init.d/rcS"

Switch to the violet terminal (the one that popped up when you started the Arm environment) and run the emulation script from there. The reason is that it will generate a lot of noise, spitting out errors about not being able to reach certain peripherals and so on.

user@azeria-labs-arm:~/Tenda$ sudo ./emulate.sh

Now, let’s check if the firmware emulation has been successful. The first thing you want to check is if new processes are running.

user@azeria-labs-arm:~$ sudo netstat -tlpn
sudo: unable to resolve host Tenda: Resource temporarily unavailable
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address  State    PID/Program name 
tcp     0     0 0.0.0.0:22          0.0.0.0:*      LISTEN   236/sshd 
tcp     0     0 0.0.0.0:5500        0.0.0.0:*      LISTEN   809/miniupnpd 
tcp     0     0 0.0.0.0:9000        0.0.0.0:*      LISTEN   450/ucloud_v2 
tcp     0     0 172.18.166.182:80   0.0.0.0:*      LISTEN   585/dhttpd 
tcp     0     0 192.168.0.1:80      0.0.0.0:*      LISTEN   448/httpd 
tcp     0     0 127.0.0.1:10002     0.0.0.0:*      LISTEN   450/ucloud_v2 
tcp     0     0 127.0.0.1:10003     0.0.0.0:*      LISTEN   450/ucloud_v2 
tcp     0     0 0.0.0.0:10004       0.0.0.0:*      LISTEN   451/business_proc 
tcp6    0     0 :::22               :::*           LISTEN   236/sshd

Looks good! Now let’s check out the router interface by browsing to 192.168.0.1.

Perfect!

Now you can start playing around with the interface, attaching to processes, and debug them. Just a quick hint on how to attach to an httpd process with GDB to get you started:

user@azeria-labs-arm:~$ ps aux | grep httpd
root   448   0.3 0.2   3692  2136 ?      Ss  02:00  0:03 httpd
root   585   0.1 0.0   2628   716 ?      S   02:00  0:01 dhttpd
user   9073  0.0 0.0   6736   532 pts/0  S+  02:16  0:00 grep httpd
user@azeria-labs-arm:~$ sudo gdb -q -p 448 

Happy hacking!

Lab Fundamentals

  • ARM Lab VM 1.0
  • ARM Lab VM 2.0
  • Running Arm Binaries on x86 with QEMU-User
  • Debugging with GDB Introduction
  • Emulate Raspberry Pi with QEMU
  • Emulating Arm Firmware

Twitter: @Fox0x01 and @azeria_labs

New ARM Assembly Cheat Sheet

Poster Digital

Cheat Sheet
© 2017-2020 Azeria Labs™ | All Rights Reserved.