Reverse ASUS RT-AC5300

Downloading firmware

In this laboratory, we are going to use the model: RT-AC5300 firmware.

Extracting the firmware

At this moment, we need to unzip the zip file and use binwalk to analyze the .trx file. Using the option "-e" we can extract all the files from the .trx file.

unzip RT-AC5300_3.0.0.4_380_2356-g34e8f6b.trx.zip
binwalk RT-AC5300_3.0.0.4_380_2356-g34e8f6b.trx
binwalk -e RT-AC5300_3.0.0.4_380_2356-g34e8f6b.trx

We can see the firmware uses little-endian, and this is probably a sign that it is using a 3x ARM version or minor.

cd _RT-AC5300_3.0.0.4_380_2356-g34e8f6b.trx.extracted
ls -la
ls -la squashfs-root
ls squashfs-root/www

We got the WWW content 😎

After emulating it, seems like this:

User mode - Firmware emulation

Why not emulation your router firmware instead of getting a physical device? 🤓

Backing to the extracted folder from the .trx file (firmware itself), we have a file called 1C we need to analyze. We got some precious information, such as:

//CPIO file with the /dev and rootFS
139264 0x22000 ASCII cpio archive (SVR4 with no CRC), file name: "/dev", file name length: "0x00000005", file size: "0x00000000"
139380 0x22074 ASCII cpio archive (SVR4 with no CRC), file name: "/dev/console", file name length: "0x0000000D", file size: "0x00000000"
139504 0x220F0 ASCII cpio archive (SVR4 with no CRC), file name: "/root", file name length: "0x00000006", file size: "0x00000000"
139620 0x22164 ASCII cpio archive (SVR4 with no CRC), file name: "TRAILER!!!", file name length: "0x0000000B", file size: "0x00000000"
//Linux kernel version - it's important to full emulation
3163712 0x304640 Linux kernel version 2.6.36
//UNIX path - cool for searching related files/content on web
3735664 0x390070 Unix path: /home/yau/asuswrt/release/src-rt-7.14.114.x/src/linux/linux-2.6.36/arch/arm/include/asm/dma-mapping.h

We can confirm some details by using the Linux strings utility:

cat 1C | strings | grep "version"
Linux version 2.6.36.4brcmarm ([email protected]) (gcc version 4.5.3 (Buildroot 2012.02) ) #1 SMP PREEMPT Fri Mar 4 20:12:49 CST 2016
2.6.36.4brcmarm SMP preempt mod_unload modversions ARMv7
slabinfo - version: 2.1
squashfs: version 4.0 (2009/01/31) Phillip Lougher
cat 1C | strings | grep "/etc/"
/etc/init
cat 1C | strings | grep "/root/"
/root/initrd

In sum, we can confirm the following details:

  • Kernel version: 2.6.36.4

  • gcc version 4.5.3

  • Buildroot 2012.02 (used to compile the rootFS)

  • ARMv7 processor - Dual Core 32-bit ARMv7 (Cortex-A9) @ 1.4GHz

  • FS ini present on /etc and /root folders! 😱

In fact, we should check everytime the device configuration available on the vendor page to learn about it, and get the device datasheet in order to confirm some details.

RT-AC5300 - Tech Specs|WiFi Routers|ASUS USA
Detailed specification of RT-AC5300 Tech Specs,Network Standard :IEEE 802.11a|IEEE 802.11b|IEEE 802.11g|WiFi 4 (802.11n)|WiFi 5 (802.11ac)|IPv4|IPv6、Data Rate :802.11a : up to 54 Mbps|802.11b : up to 11 Mbps|802.11g : up to 54 Mbps|WiFi 4 (802.11n) : up to 600 Mbps|802.11ac : up to 1734 Mbps|1024QAM (2.4GHz) : up to 1000 Mbps|1024QAM (5GHz) : up to 2167 Mbps、Antenna :External antenna x 8、Transmit/Receive :MIMO technology|2.4 GHz 4 x 4|5 GHz-1 4 x 4|5 GHz-2 4 x 4、Memory :128 MB Flash, 512 MB RAM、Boosts speed:Beamforming: standard-based and universal 1024-QAM high data rate 20/40/80 MHz bandwidth、Operating Frequency :2.4G Hz / 5 GHz-1 / 5 GHz-2、Ports :RJ45 for 10/100/1000 BaseT for WAN x 1, RJ45 for 10/100/1000/Gigabits BaseT for LAN x 4 USB 2.0 x 1 USB 3.0 x 1、Button :WPS Button, Reset Button, Power Button, Wireless on/off Button、LED Indicator :Power x 1 WAN x 1 LAN x 1 Wireless x 2 WPS x 1、Power Supply :AC Input : 110V~240V(50~60Hz) DC Output : 19 V with max. 3.42 A current、Package content :RT-AC5300 Tri-band Gigabit Router RJ-45 Cable Power Adapter Quick Start Guide Warranty Card Support CD (User manual & Utility software)、Product Weight (g):1880 g、AiMesh:AiMesh : Yes|Primary AiMesh router : Yes|AiMesh node : Yes、Router APP:ASUS Router APP : Yes、Game:Game Boost/acceleration : Yes|WTFast : Yes、Alexa:Support Alexa skil : Yes、IFTTT:Support IFTTT : Yes、AiProtection:AiProtection : AiProtection Pro|Router Security Assessment : Yes|Malicious site blocking : Yes|Two-Way IPS : Yes|Infected Device Prevention and Blocking ; Yes、Parental Control:Parental Control : Yes|Parental Control Customized Internet schedule : Yes、Traffic Control:Adaptive QoS : Yes|Bandwidth Monitor : Yes|Bandwidth limiter : Yes|Maximum Bandwidth limiter rule : 32|Traditional QoS : Yes|Maximum Traditional QoS rule : 32|Traffic Monitor : Yes|Real-time traffic monitor : Yes|Wired Traffic Monitor : Yes|Wireless Traffic Monitor : Yes|Traffic Analyzer : Yes|Traffic analysis period : Daily, Weekly, Monthly|Website history : Yes、Wireless:IPv6 : Yes|MU-MIMO : Yes|Wi-Fi Encryption : Open system, WPA/WPA2-Personal, WPA/WPA2-Enterprise|UTF-8 SSID : Yes|Guest Network : Yes|Maximum Guest Network rule : 2.4GHz x3, 5GHz-1 x3, 5GHz-2 x3|Guest Network Encryption : Open system, WPA/WPA2-Personal|WPS : Yes|Wi-Fi MAC address filter : Yes|Maximum MAC filters : 64|Wireless scheduler : Yes|Airtime fairness : Yes|RADIUS Server : Yes|Universal beamforming : Yes|Explicit beamforming : Yes|IGMP snooping : Yes、WAN:Internet connection Type : PPPoE, PPTP, L2TP, Automatic IP, Static IP|Dual WAN : Yes|WAN Aggregation : No|3G/4G LTE dongle : Yes|Android tethering : Yes|Port forwarding : Yes|Maximum port forwarding rule : 64|Port triggering : Yes|Maximum port triggering rule : 32|DMZ : Yes|DDNS : Yes|NAT Passthrough : PPTP, L2TP, IPSec, RTSP, H.323, SIP Passthrough,PPPoE relay、LAN:DHCP Server : Yes|IPTV : Yes|LAN Link Aggregation : Yes|Manually assign IP address : Yes|Maximum manually assign IP address rule : 64、VPN:VPN Client L2PT : Yes|VPN Client OVPN : Yes|VPN Client PPTP : Yes|VPN Server IPSec : No|VPN Server OVPN : Yes|VPN Server PPTP : Yes|VPN Fusion : No、USB application:File System : HFS+, NTFS, vFAT, ext2, ext3, ext4|3G/4G LTE dongle : Yes|HDD hibernation : Yes|Safely Remove disk : Yes|AiCloud : Yes|Download master : Yes|AiDisk : Yes|Media Server : Yes|Time Machine : Yes|Samba Server : Yes|FTP Server : Yes|Shared Folder privileges : Yes、Administration:Operating mode : Accesspoint, AiMeshnode, Mediabridge, Repeater, Router|Operating system : ASUSWRT|Free OS upgrade : Yes|Firewall : Yes|Maximum Firewall keyword filter : 64|Maximum Firewall network service filter : 32|Maximum Firewall URL filter : 64|Wake on LAN (WOL) : Yes|SSH : Yes|Configuration backup and restore : Yes|Diagnosis tools : Yes|Feedback system : Yes|System log : Yes…
www.asus.com

Using qemu-arm approach

Per-process emulation is useful when only one binary needs to be emulated. To this that, next install full dependencies:

sudo apt-get install qemu
sudo apt-get install qemu-utils
sudo apt install qemu-kvm libvirt-clients libvirt-daemon-system bridge-utils
sudo adduser kali libvirt
sudo adduser kali kvm
sudo apt install qemu-system-arm
sudo apt install qemu-user

The user-mode emulation can be made by using the following command:

cd squashfs-root/usr/sbin
qemu-arm -L <prefix> ./httpd
or
qemu-arm-static ./httpd

The -L option is important for when the binary links to external dependencies such as uCLibc or encryption libraries. It tells the dynamic linker to look for dependencies with the provided prefix.

We can get the following error:

qemu-arm: Could not open '/lib/ld-uClibc.so.0': No such file or directory

By inspecting the /lib/ folder, we can see the following:

The file "ld-uClibc.so.0" is present, so we need to just add the current dir to the qemu-arm execution. Otherwise, if the UClibc.so file has another name, we could resolve that by doing a symbolic link, e.g.: squashfs-root/lib/ld-uClibc-0.9.29.so to squashfs-root/lib/ld-uClic.so.

So, the final qemu command is the following:

qemu-arm -L . usr/sbin/httpd
/dev/nvram: Permission denied
/dev/nvram: Permission denied
/dev/nvram: Permission denied
/dev/nvram: Permission denied
/dev/nvram: Permission denied
/dev/nvram: Permission denied
/dev/nvram: Permission denied
/dev/nvram: Permission denied
/dev/nvram: Permission denied
Generating SSL certificate...
1068532656:error:02001002:system library:fopen:No such file or directory:bss_file.c:391:fopen('/etc/cert.pem','r')
1068532656:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:393:
1068532656:error:140DC002:SSL routines:SSL_CTX_use_certificate_chain_file:system lib:ssl_rsa.c:682:
/dev/nvram: Permission denied
/dev/nvram: Permission denied
/dev/nvram: Permission denied
/dev/nvram: Permission denied
/dev/nvram: Permission denied
Generating SSL certificate...
1068532656:error:02001002:system library:fopen:No such file or directory:bss_file.c:391:fopen('/etc/cert.pem','r')
1068532656:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:393:
1068532656:error:140DC002:SSL routines:SSL_CTX_use_certificate_chain_file:system lib:ssl_rsa.c:682:
/dev/nvram: Permission denied
/dev/nvram: Permission denied

Using qemu-user-static approach

Another way to emulate the process is to perform a cross-architectural chroot with QEMU.

[email protected]:~$ sudo apt-get install binfmt-support qemu qemu-user-static debootstrap

You can also download the target qemu-user static file pre-compiled from GitHub 😼

Next, we copy the qemu-arm-static binary to the rootFS directory of the firmware. We then chroot into the firmware root and obtain a working shell:

which qemu-arm-static 130 ⨯
/usr/bin/qemu-arm-static
cp /usr/bin/qemu-arm-static squashfs-root/
cd squashfs-root/
sudo chroot . ./qemu-arm-static /bin/sh

This is possible due to QEMU registering with the kernel during installation to handle binaries with certain magic bytes via the binfmt_misc mechanism.

We can try to run the httpd service, getting some errors - of course, because the /etc/ folder is not mounted, NVRAM system is not present - but we will just workaround this later! 😎

This is the best method to test a single binary or feature in a short period of time without losing a lot of hours configuring and preparing the environment.

Next, we can start e.g., telnetd service inside our emulated environment ;)

---inside chroot FS----
/usr/sbin # telnetd
called setup()
/usr/sbin #
---Guest machine---
└─$ netstat -antp
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp6 0 0 :::23 :::* LISTEN -

Emulation NVRAM

In the previous user emulation scenarios, we found problems to emulate correctly the NVRAM. In this way, we can use hooks in a simple library to intercept calls to libnvram using LD_PRELOAD.

You can simply access this project on GitHub, compiling the C files with the target arch (ARM) or just download the arm version from releases.

wget https://github.com/firmadyne/libnvram/releases/download/v1.0/libnvram.so.armel
mkdir -p squashfs-root/firmadyne/
cp libnvram.so /firmadyne/libnvram.so
mkdir -p /firmadyne/libnvram/ mkdir -p /firmadyne/libnvram.override/
sudo chroot . ./qemu-arm-static /bin/sh
export LD_PRELOAD="/firmadyne/libnvram.so"
httpd

You can also compile the nvram file using a cross-compiler for ARM architectures.

wget https://uclibc.org/downloads/binaries/0.9.30.1/cross-compiler-armv5l.tar.bz2
tar xjf cross-compiler-armv5l.tar.bz2
git clone https://github.com/firmadyne/libnvram.git
cd libnvram
../cross-compiler-armv5l/bin/armv5l-gcc nvram.c -o nvram -shared -ldl
cp nvram ../../_RT-AC5300_3.0.0.4_380_2356-g34e8f6b.trx.extracted/squashfs-root/firmadyne
mv nvram libnvram.so
sudo chroot . ./qemu-arm-static /bin/sh
export LD_PRELOAD="/firmadyne/libnvram.so"
httpd

It works 😋

sudo chroot . ./qemu-arm-static /bin/sh
export LD_PRELOAD="/firmadyne/libnvram.so"
httpd

Hook functions

If we need to hook any function, LD_PRELOAD is our best friend.

For example, the next hook will emulate the native open file call from gclib.

#define _GNU_SOURCE
#include <stdio.h>
#include <dlfcn.h>
typedef FILE *(*fopen_t)(const char *pathname, const char *mode);
fopen_t real_fopen;
FILE *fopen(const char *pathname, const char *mode) {
fprintf(stderr, "called fopen(%s, %s)\n", pathname, mode);
return real_fopen(pathname, mode);
}
__attribute__((constructor)) static void setup(void) {
real_fopen = dlsym(RTLD_NEXT, "fopen");
fprintf(stderr, "called setup()\n");
}

We can compile it onto ARM using a cross compiler:

wget https://uclibc.org/downloads/binaries/0.9.30.1/cross-compiler-armv5l.tar.bz2
tar xjf cross-compiler-armv5l.tar.bz2
cross-compiler-armv5l/bin/armv5l-gcc hook.c -o hooks.so -shared -ldl
sudo chroot . ./qemu-arm-static /bin/sh
export LD_PRELOAD="/firmadyne/libnvram.so /hooks.so"
httpd

Even though we don't have the /etc/rc.d or /etc/init.d to run the appropriate RC script to kick off the userland services, we were able to execute single binaries, which can give us some input about the device operation, or even finding vulnerabilities at this level.

Firmware full emulation

To do this, we can use Buildroot 2012.02 to create your rootFS and compile kernel version 2.6.36.

To compile it, you can use a normal Linux distribution (Kali Linux), or try to use an old version of ubuntu 16.4.

To start using buildroot, you need to compile the manual and learn about it.

For this ASUS router, the best configs are the following:

make menuconfig

board config name:

To choose the right kernel defconfig:

or accessing: output/build/linux-2.6.36.4/arch/arm/configs

acs5k_defconfig mv78xx0_defconfig
acs5k_tiny_defconfig mx1_defconfig
afeb9260_defconfig mx21_defconfig
am200epdkit_defconfig mx27_defconfig
ams_delta_defconfig mx31pdk_defconfig
ap4evb_defconfig mx3_defconfig
assabet_defconfig mx51_defconfig
at572d940hfek_defconfig n770_defconfig
at91cap9adk_defconfig n8x0_defconfig
at91rm9200dk_defconfig neocore926_defconfig
at91rm9200ek_defconfig neponset_defconfig
at91sam9260ek_defconfig netwinder_defconfig
at91sam9261ek_defconfig netx_defconfig
at91sam9263ek_defconfig nhk8815_defconfig
at91sam9g20ek_defconfig ns9xxx_defconfig
at91sam9rlek_defconfig nuc910_defconfig
ateb9200_defconfig nuc950_defconfig
badge4_defconfig nuc960_defconfig
bcmring_defconfig omap3_defconfig
cam60_defconfig omap_4430sdp_defconfig
carmeva_defconfig omap_generic_1510_defconfig
cerfcube_defconfig omap_generic_1610_defconfig
cm_x2xx_defconfig omap_generic_1710_defconfig
cm_x300_defconfig omap_generic_2420_defconfig
cns3420vb_defconfig omap_h2_1610_defconfig
colibri_pxa270_defconfig omap_innovator_1510_defconfig
colibri_pxa300_defconfig omap_innovator_1610_defconfig
collie_defconfig omap_osk_5912_defconfig
corgi_defconfig omap_perseus2_730_defconfig
cpu9260_defconfig onearm_defconfig
cpu9g20_defconfig orion5x_defconfig
cpuat91_defconfig palmte_defconfig
csb337_defconfig palmtt_defconfig
csb637_defconfig palmz71_defconfig
da8xx_omapl_defconfig palmz72_defconfig
davinci_all_defconfig pcm027_defconfig
dove_defconfig picotux200_defconfig
ebsa110_defconfig pleb_defconfig
ecbat91_defconfig pnx4008_defconfig
edb7211_defconfig pxa168_defconfig
em_x270_defconfig pxa255-idp_defconfig
ep93xx_defconfig pxa3xx_defconfig
eseries_pxa_defconfig pxa910_defconfig
ezx_defconfig qil-a9260_defconfig
footbridge_defconfig raumfeld_defconfig
fortunet_defconfig realview_defconfig
g3evm_defconfig realview-smp_defconfig
g4evm_defconfig rpc_defconfig
h3600_defconfig s3c2410_defconfig
h5000_defconfig s3c6400_defconfig
h7201_defconfig s5p6440_defconfig
h7202_defconfig s5p6442_defconfig
hackkit_defconfig s5pc100_defconfig
htcherald_defconfig s5pv210_defconfig
imote2_defconfig sam9_l9260_defconfig
integrator_defconfig shannon_defconfig
iop13xx_defconfig shark_defconfig
iop32x_defconfig simpad_defconfig
iop33x_defconfig spear300_defconfig
ixp2000_defconfig spear310_defconfig
ixp23xx_defconfig spear320_defconfig
ixp4xx_defconfig spear600_defconfig
jornada720_defconfig spitz_defconfig
kafa_defconfig stamp9g20_defconfig
kb9202_defconfig stmp378x_defconfig
kirkwood_defconfig stmp37xx_defconfig
ks8695_defconfig sx1_defconfig
lart_defconfig tct_hammer_defconfig
loki_defconfig trizeps4_defconfig
lpd270_defconfig u300_defconfig
lpd7a400_defconfig u8500_defconfig
lpd7a404_defconfig usb-a9260_defconfig
lubbock_defconfig usb-a9263_defconfig
magician_defconfig versatile_defconfig
mainstone_defconfig viper_defconfig
mini2440_defconfig xcep_defconfig
mmp2_defconfig yl9200_defconfig
msm_defconfig zeus_defconfig

To start the compilation process: make all or using a specific GCC version: make HOSTCC=gcc-4

Fixing kernel crashes or dependencies

"gets" undeclared here

In file included from clean-temp.h:22:0,
from clean-temp.c:23:
./stdio.h:477:1: error: 'gets' undeclared here (not in a function)
_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
^

Fix

find . -name stdio.in.h
./output/build/host-m4-1.4.16/lib/stdio.in.h
sed -i -e '/gets is a/d' lib/stdio.in.h

textinfo incompatibilities with GCC documentation

This is frustrating me too, I cannot install texinfo, because texinfo is compatible with the tex documentation for this version of the compiler I have to use, which is what's breaking the documentation in the first place.

/home/ubuntu/buildroot-2012.02/output/toolchain/gcc-4.5.3/gcc/doc/service.texi:6: warning: node prev `Service' in menu `Trouble' and in sectioning `Bugs' differ
/home/ubuntu/buildroot-2012.02/output/toolchain/gcc-4.5.3/gcc/doc/service.texi:6: warning: node up `Service' in menu `Bugs' and in sectioning `Top' differ
Makefile:4052: recipe for target 'doc/gcc.info' failed
make[2]: *** [doc/gcc.info] Error 1
make[2]: Leaving directory '/home/ubuntu/buildroot-2012.02/output/toolchain/gcc-4.5.3-initial/gcc'
Makefile:5027: recipe for target 'all-gcc' failed
make[1]: *** [all-gcc] Error 2
make[1]: Leaving directory '/home/ubuntu/buildroot-2012.02/output/toolchain/gcc-4.5.3-initial'

Instead of editing files, when I run make I pass the argument MAKEINFO.

One minor point about this. I think it should be pointed out what this does. It basically overrides the MAKEINFO variable predefined by GNU make, which normally points to the program to call in order to get makeinfo invoked. So by setting it to true you are effectively replacing calls to makeinfo by calls to /bin/true (can be seen with make -npf /dev/null |grep ^MAKEINFO).

Fix

make MAKEINFO=true

Can't use 'defined(@array)'

Can't use 'defined(@array)' (Maybe you should just omit the defined()?) at kernel/timeconst.pl line 373.
/home/ubuntu/buildroot-2012.02/output/build/linux-3.2.6/kernel/Makefile:141: recipe for target 'kernel/timeconst.h' failed
make[2]: *** [kernel/timeconst.h] Error 255
Makefile:945: recipe for target 'kernel' failed
make[1]: *** [kernel] Error 2
make[1]: *** Waiting for unfinished jobs....
make[1]: Leaving directory '/home/ubuntu/buildroot-2012.02/output/build/linux-3.2.6'
package/Makefile.package.in:393: recipe for target '/home/ubuntu/buildroot-2012.02/output/build/linux-3.2.6/.stamp_built' failed
make: *** [/home/ubuntu/buildroot-2012.02/output/build/linux-3.2.6/.stamp_built] Error 2

Fix

Can’t use ‘defined(@array)’ (Maybe you should just omit the defined()?) at kernel/timeconst.pl line 373 has prompted where is the delicate error message, open timeconst.pl to see (under the kerner directory).

cd output/build/linux-3.2.6/kernel/
vim timeconst.pl
/!defined(@val))
change this (line 373):
372 @val = @{$canned_values{$hz}};
373 if (!defined(@val)) {
374 @val = compute_values($hz);
375 }
376 output($hz, @val);
by:
372 @val = @{$canned_values{$hz}};
373 if ([email protected]) {
374 @val = compute_values($hz);
375 }
376 output($hz, @val);
make

Compiling everything is a long journey, you can also test more recent kernel versions and so on to avoid some errors when you are building your environment for emulation.

At the end, you will get something like this on your output/images folder:

-rw-r--r-- 1 kali kali 62914560 Jul 27 18:30 rootfs.ext2
-rw-r--r-- 1 kali kali 1437696 Jul 27 18:30 rootfs.squashfs
-rw-r--r-- 1 kali kali 4085760 Jul 27 18:30 rootfs.tar
-rwxr-xr-x 1 kali kali 446 Jul 27 18:30 start-qemu.sh
-rwxr-xr-x 1 kali kali 8880 Jul 27 18:27 versatile-pb.dtb
-rw-r--r-- 1 kali kali 2871872 Jul 27 18:27 zImage

Now, it's time to start your qemu emulator:

qemu-system-arm -M versatilepb -kernel zImage -dtb versatile-pb.dtb -drive file=rootfs.ext2,if=scsi,format=raw -append "rootwait root=/dev/sda console=ttyAMA0,115200"

Finally, merge the rootfs (host + router), and exploit it like a baws 😉

Using docker containers and relax to emulate your firmware 👾

Other options instead of using qemu are docker containers.

docker pull kelvinlawson/arm-cortex
sudo docker run --privileged=true --name=firmware -p 2221:22 -p 8888:80 -p 4443:443 -p 2223:23 -it 8d319a850335
shell$: cd /sbin
shell$: ./preninit

Resources