Reverse ASUS RT-AC5300

Downloading firmware

In this laboratory, we are going to use the model: RT-AC5300 firmware.
Routers ASUS - Escolha o seu Router ASUS e o seu operador de internet (MEO, NOS ou Vodafone)
Actualize o firmware do seu Router ASUS
ROG Rapture GT-AC5300 | Gaming Networking|ROG - Republic of Gamers|ROG Global
ROG

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.
1
unzip RT-AC5300_3.0.0.4_380_2356-g34e8f6b.trx.zip
2
binwalk RT-AC5300_3.0.0.4_380_2356-g34e8f6b.trx
3
binwalk -e RT-AC5300_3.0.0.4_380_2356-g34e8f6b.trx
Copied!
We can see the firmware uses little-endian, and this is probably a sign that it is using a 3x ARM version or minor.
1
cd _RT-AC5300_3.0.0.4_380_2356-g34e8f6b.trx.extracted
2
ls -la
3
ls -la squashfs-root
4
ls squashfs-root/www
Copied!
We got the WWW content
😎
After emulating it, seems like this:
ASUS Wireless Router RT-AX95Q - Network Map

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:
1
//CPIO file with the /dev and rootFS
2
139264 0x22000 ASCII cpio archive (SVR4 with no CRC), file name: "/dev", file name length: "0x00000005", file size: "0x00000000"
3
139380 0x22074 ASCII cpio archive (SVR4 with no CRC), file name: "/dev/console", file name length: "0x0000000D", file size: "0x00000000"
4
139504 0x220F0 ASCII cpio archive (SVR4 with no CRC), file name: "/root", file name length: "0x00000006", file size: "0x00000000"
5
139620 0x22164 ASCII cpio archive (SVR4 with no CRC), file name: "TRAILER!!!", file name length: "0x0000000B", file size: "0x00000000"
6
7
//Linux kernel version - it's important to full emulation
8
3163712 0x304640 Linux kernel version 2.6.36
9
10
//UNIX path - cool for searching related files/content on web
11
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
Copied!
We can confirm some details by using the Linux strings utility:
1
cat 1C | strings | grep "version"
2
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
3
2.6.36.4brcmarm SMP preempt mod_unload modversions ARMv7
4
slabinfo - version: 2.1
5
squashfs: version 4.0 (2009/01/31) Phillip Lougher
6
7
cat 1C | strings | grep "/etc/"
8
/etc/init
9
10
cat 1C | strings | grep "/root/"
11
/root/initrd
Copied!
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
ASUS RT-AC5300 - TechInfoDepot

Using qemu-arm approach

Per-process emulation is useful when only one binary needs to be emulated. To this that, next install full dependencies:
1
sudo apt-get install qemu
2
sudo apt-get install qemu-utils
3
sudo apt install qemu-kvm libvirt-clients libvirt-daemon-system bridge-utils
4
sudo adduser kali libvirt
5
sudo adduser kali kvm
6
sudo apt install qemu-system-arm
7
sudo apt install qemu-user
Copied!
The user-mode emulation can be made by using the following command:
1
cd squashfs-root/usr/sbin
2
qemu-arm -L <prefix> ./httpd
3
or
4
qemu-arm-static ./httpd
Copied!
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:
1
qemu-arm -L . usr/sbin/httpd
2
3
/dev/nvram: Permission denied
4
/dev/nvram: Permission denied
5
/dev/nvram: Permission denied
6
/dev/nvram: Permission denied
7
/dev/nvram: Permission denied
8
/dev/nvram: Permission denied
9
/dev/nvram: Permission denied
10
/dev/nvram: Permission denied
11
/dev/nvram: Permission denied
12
Generating SSL certificate...
13
1068532656:error:02001002:system library:fopen:No such file or directory:bss_file.c:391:fopen('/etc/cert.pem','r')
14
1068532656:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:393:
15
1068532656:error:140DC002:SSL routines:SSL_CTX_use_certificate_chain_file:system lib:ssl_rsa.c:682:
16
/dev/nvram: Permission denied
17
/dev/nvram: Permission denied
18
/dev/nvram: Permission denied
19
/dev/nvram: Permission denied
20
/dev/nvram: Permission denied
21
Generating SSL certificate...
22
1068532656:error:02001002:system library:fopen:No such file or directory:bss_file.c:391:fopen('/etc/cert.pem','r')
23
1068532656:error:20074002:BIO routines:FILE_CTRL:system lib:bss_file.c:393:
24
1068532656:error:140DC002:SSL routines:SSL_CTX_use_certificate_chain_file:system lib:ssl_rsa.c:682:
25
/dev/nvram: Permission denied
26
/dev/nvram: Permission denied
Copied!

Using qemu-user-static approach

Another way to emulate the process is to perform a cross-architectural chroot with QEMU.
1
[email protected]:~$ sudo apt-get install binfmt-support qemu qemu-user-static debootstrap
Copied!
You can also download the target qemu-user static file pre-compiled from GitHub
😼
Release v6.0.0-1 · multiarch/qemu-user-static
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:
1
which qemu-arm-static 130 ⨯
2
/usr/bin/qemu-arm-static
3
4
cp /usr/bin/qemu-arm-static squashfs-root/
5
cd squashfs-root/
6
sudo chroot . ./qemu-arm-static /bin/sh
Copied!
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 ;)
1
---inside chroot FS----
2
/usr/sbin # telnetd
3
called setup()
4
/usr/sbin #
5
6
---Guest machine---
7
└─$ netstat -antp
8
9
Active Internet connections (servers and established)
10
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
11
tcp6 0 0 :::23 :::* LISTEN -
Copied!

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.
GitHub - firmadyne/libnvram: NVRAM emulator
GitHub
1
wget https://github.com/firmadyne/libnvram/releases/download/v1.0/libnvram.so.armel
2
mkdir -p squashfs-root/firmadyne/
3
cp libnvram.so /firmadyne/libnvram.so
4
mkdir -p /firmadyne/libnvram/ mkdir -p /firmadyne/libnvram.override/
5
6
sudo chroot . ./qemu-arm-static /bin/sh
7
export LD_PRELOAD="/firmadyne/libnvram.so"
8
httpd
Copied!
You can also compile the nvram file using a cross-compiler for ARM architectures.
1
wget https://uclibc.org/downloads/binaries/0.9.30.1/cross-compiler-armv5l.tar.bz2
2
tar xjf cross-compiler-armv5l.tar.bz2
3
4
git clone https://github.com/firmadyne/libnvram.git
5
cd libnvram
6
../cross-compiler-armv5l/bin/armv5l-gcc nvram.c -o nvram -shared -ldl
7
cp nvram ../../_RT-AC5300_3.0.0.4_380_2356-g34e8f6b.trx.extracted/squashfs-root/firmadyne
8
mv nvram libnvram.so
9
10
sudo chroot . ./qemu-arm-static /bin/sh
11
export LD_PRELOAD="/firmadyne/libnvram.so"
12
httpd
Copied!
It works
😋
1
sudo chroot . ./qemu-arm-static /bin/sh
2
export LD_PRELOAD="/firmadyne/libnvram.so"
3
httpd
Copied!

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.
1
#define _GNU_SOURCE
2
3
#include <stdio.h>
4
#include <dlfcn.h>
5
6
typedef FILE *(*fopen_t)(const char *pathname, const char *mode);
7
fopen_t real_fopen;
8
9
FILE *fopen(const char *pathname, const char *mode) {
10
fprintf(stderr, "called fopen(%s, %s)\n", pathname, mode);
11
return real_fopen(pathname, mode);
12
}
13
14
__attribute__((constructor)) static void setup(void) {
15
real_fopen = dlsym(RTLD_NEXT, "fopen");
16
fprintf(stderr, "called setup()\n");
17
}
Copied!
We can compile it onto ARM using a cross compiler:
1
wget https://uclibc.org/downloads/binaries/0.9.30.1/cross-compiler-armv5l.tar.bz2
2
tar xjf cross-compiler-armv5l.tar.bz2
3
cross-compiler-armv5l/bin/armv5l-gcc hook.c -o hooks.so -shared -ldl
4
5
sudo chroot . ./qemu-arm-static /bin/sh
6
export LD_PRELOAD="/firmadyne/libnvram.so /hooks.so"
7
httpd
Copied!
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.
Index of /downloads
To compile it, you can use a normal Linux distribution (Kali Linux), or try to use an old version of ubuntu 16.4.
Ubuntu 16.04.7 LTS (Xenial Xerus)
To start using buildroot, you need to compile the manual and learn about it.
For this ASUS router, the best configs are the following:
1
make menuconfig
Copied!
board config name:
u-boot/boards.cfg at master · lentinj/u-boot
GitHub
To choose the right kernel defconfig:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm/configs
git.kernel.org
or accessing: output/build/linux-2.6.36.4/arch/arm/configs
1
acs5k_defconfig mv78xx0_defconfig
2
acs5k_tiny_defconfig mx1_defconfig
3
afeb9260_defconfig mx21_defconfig
4
am200epdkit_defconfig mx27_defconfig
5
ams_delta_defconfig mx31pdk_defconfig
6
ap4evb_defconfig mx3_defconfig
7
assabet_defconfig mx51_defconfig
8
at572d940hfek_defconfig n770_defconfig
9
at91cap9adk_defconfig n8x0_defconfig
10
at91rm9200dk_defconfig neocore926_defconfig
11
at91rm9200ek_defconfig neponset_defconfig
12
at91sam9260ek_defconfig netwinder_defconfig
13
at91sam9261ek_defconfig netx_defconfig
14
at91sam9263ek_defconfig nhk8815_defconfig
15
at91sam9g20ek_defconfig ns9xxx_defconfig
16
at91sam9rlek_defconfig nuc910_defconfig
17
ateb9200_defconfig nuc950_defconfig
18
badge4_defconfig nuc960_defconfig
19
bcmring_defconfig omap3_defconfig
20
cam60_defconfig omap_4430sdp_defconfig
21
carmeva_defconfig omap_generic_1510_defconfig
22
cerfcube_defconfig omap_generic_1610_defconfig
23
cm_x2xx_defconfig omap_generic_1710_defconfig
24
cm_x300_defconfig omap_generic_2420_defconfig
25
cns3420vb_defconfig omap_h2_1610_defconfig
26
colibri_pxa270_defconfig omap_innovator_1510_defconfig
27
colibri_pxa300_defconfig omap_innovator_1610_defconfig
28
collie_defconfig omap_osk_5912_defconfig
29
corgi_defconfig omap_perseus2_730_defconfig
30
cpu9260_defconfig onearm_defconfig
31
cpu9g20_defconfig orion5x_defconfig
32
cpuat91_defconfig palmte_defconfig
33
csb337_defconfig palmtt_defconfig
34
csb637_defconfig palmz71_defconfig
35
da8xx_omapl_defconfig palmz72_defconfig
36
davinci_all_defconfig pcm027_defconfig
37
dove_defconfig picotux200_defconfig
38
ebsa110_defconfig pleb_defconfig
39
ecbat91_defconfig pnx4008_defconfig
40
edb7211_defconfig pxa168_defconfig
41
em_x270_defconfig pxa255-idp_defconfig
42
ep93xx_defconfig pxa3xx_defconfig
43
eseries_pxa_defconfig pxa910_defconfig
44
ezx_defconfig qil-a9260_defconfig
45
footbridge_defconfig raumfeld_defconfig
46
fortunet_defconfig realview_defconfig
47
g3evm_defconfig realview-smp_defconfig
48
g4evm_defconfig rpc_defconfig
49
h3600_defconfig s3c2410_defconfig
50
h5000_defconfig s3c6400_defconfig
51
h7201_defconfig s5p6440_defconfig
52
h7202_defconfig s5p6442_defconfig
53
hackkit_defconfig s5pc100_defconfig
54
htcherald_defconfig s5pv210_defconfig
55
imote2_defconfig sam9_l9260_defconfig
56
integrator_defconfig shannon_defconfig
57
iop13xx_defconfig shark_defconfig
58
iop32x_defconfig simpad_defconfig
59
iop33x_defconfig spear300_defconfig
60
ixp2000_defconfig spear310_defconfig
61
ixp23xx_defconfig spear320_defconfig
62
ixp4xx_defconfig spear600_defconfig
63
jornada720_defconfig spitz_defconfig
64
kafa_defconfig stamp9g20_defconfig
65
kb9202_defconfig stmp378x_defconfig
66
kirkwood_defconfig stmp37xx_defconfig
67
ks8695_defconfig sx1_defconfig
68
lart_defconfig tct_hammer_defconfig
69
loki_defconfig trizeps4_defconfig
70
lpd270_defconfig u300_defconfig
71
lpd7a400_defconfig u8500_defconfig
72
lpd7a404_defconfig usb-a9260_defconfig
73
lubbock_defconfig usb-a9263_defconfig
74
magician_defconfig versatile_defconfig
75
mainstone_defconfig viper_defconfig
76
mini2440_defconfig xcep_defconfig
77
mmp2_defconfig yl9200_defconfig
78
msm_defconfig zeus_defconfig
Copied!
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

1
In file included from clean-temp.h:22:0,
2
from clean-temp.c:23:
3
./stdio.h:477:1: error: 'gets' undeclared here (not in a function)
4
_GL_WARN_ON_USE (gets, "gets is a security hole - use fgets instead");
5
^
Copied!
Fix
1
find . -name stdio.in.h
2
./output/build/host-m4-1.4.16/lib/stdio.in.h
3
4
sed -i -e '/gets is a/d' lib/stdio.in.h
Copied!

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.
1
/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
2
/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
3
Makefile:4052: recipe for target 'doc/gcc.info' failed
4
make[2]: *** [doc/gcc.info] Error 1
5
make[2]: Leaving directory '/home/ubuntu/buildroot-2012.02/output/toolchain/gcc-4.5.3-initial/gcc'
6
Makefile:5027: recipe for target 'all-gcc' failed
7
make[1]: *** [all-gcc] Error 2
8
make[1]: Leaving directory '/home/ubuntu/buildroot-2012.02/output/toolchain/gcc-4.5.3-initial'
Copied!
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
1
make MAKEINFO=true
Copied!
Can't use 'defined(@array)'
1
Can't use 'defined(@array)' (Maybe you should just omit the defined()?) at kernel/timeconst.pl line 373.
2
/home/ubuntu/buildroot-2012.02/output/build/linux-3.2.6/kernel/Makefile:141: recipe for target 'kernel/timeconst.h' failed
3
make[2]: *** [kernel/timeconst.h] Error 255
4
Makefile:945: recipe for target 'kernel' failed
5
make[1]: *** [kernel] Error 2
6
make[1]: *** Waiting for unfinished jobs....
7
make[1]: Leaving directory '/home/ubuntu/buildroot-2012.02/output/build/linux-3.2.6'
8
package/Makefile.package.in:393: recipe for target '/home/ubuntu/buildroot-2012.02/output/build/linux-3.2.6/.stamp_built' failed
9
make: *** [/home/ubuntu/buildroot-2012.02/output/build/linux-3.2.6/.stamp_built] Error 2
Copied!
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).
1
cd output/build/linux-3.2.6/kernel/
2
vim timeconst.pl
3
4
/!defined(@val))
5
6
change this (line 373):
7
8
372 @val = @{$canned_values{$hz}};
9
373 if (!defined(@val)) {
10
374 @val = compute_values($hz);
11
375 }
12
376 output($hz, @val);
13
14
15
by:
16
17
372 @val = @{$canned_values{$hz}};
18
373 if ([email protected]) {
19
374 @val = compute_values($hz);
20
375 }
21
376 output($hz, @val);
Copied!
Compile kernel error: Can't use'defined(@array)' (Maybe you should just omit the defined()?) at kernel/timeconst.pl - Programmer Sought
1
make
Copied!
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:
1
-rw-r--r-- 1 kali kali 62914560 Jul 27 18:30 rootfs.ext2
2
-rw-r--r-- 1 kali kali 1437696 Jul 27 18:30 rootfs.squashfs
3
-rw-r--r-- 1 kali kali 4085760 Jul 27 18:30 rootfs.tar
4
-rwxr-xr-x 1 kali kali 446 Jul 27 18:30 start-qemu.sh
5
-rwxr-xr-x 1 kali kali 8880 Jul 27 18:27 versatile-pb.dtb
6
-rw-r--r-- 1 kali kali 2871872 Jul 27 18:27 zImage
Copied!
Now, it's time to start your qemu emulator:
1
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"
Copied!
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 Hub
GitHub - digiampietro/buildroot-armv7: A set of scripts, configuration files and Buildroot external tree to setup a Qemu emulation environment to run and reverse engineer the *Netgear DVA 5592* executables. This environment uses Docker, Buildroot and Qemu to emulate a board with an ARMv7 Cortex A9 processor, Linux kernel 3.4.11-rt19, uClibc 0.9.33.2, and old versions of other libraries.
GitHub
Docker Hub
1
docker pull kelvinlawson/arm-cortex
2
sudo docker run --privileged=true --name=firmware -p 2221:22 -p 8888:80 -p 4443:443 -p 2223:23 -it 8d319a850335
3
shell$: cd /sbin
4
shell$: ./preninit
Copied!

Resources

Zero Day Initiative — MindShaRE: How to “Just Emulate It With QEMU”
Zero Day Initiative
Emulating Embedded Linux Systems with QEMU | Novetta Nexus
Novetta
Emulating Arm Firmware
Azeria-Labs
Buildroot - Making Embedded Linux Easy
Zero Day Initiative — Blog
Zero Day Initiative
Last modified 5mo ago