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.
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:
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.
Using qemu-arm approach
Per-process emulation is useful when only one binary needs to be emulated. To this that, next install full dependencies:
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.
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.
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
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 373has 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 (!@val) {
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