This lab is build around a vulnerable HTTP daemon which runs on a virtualized QEMU environment on an eumulated ARMv7 Cortex-A15 processor.
+------------------+ | | | armbox | | | | +-----------+ attacking myhttpd | |myhttpd || | |TCP 8080 || <----------------+ | +-----------+ | | +------------------+
I prepared scripts, the vulnerable daemon and everything else you need to successfully write your own ROP chain. You can find the latest version of the scripts and the vulnerable daemon in my Github repository. If you have suggestions to improve the setup, I'd happy to include them!
Clone the whole repo. For this part of this series you will need the scripts in the armbox directory.
Set up the QEMU environment
QEMU is a pain. I wrote a set of scripts to build a RAW QEMU ArchLinuxArm image, which boots in QEMUs with a emulated Cortex-A15. Use the scripts as reference - I do not make any checks for failed commands. I used the "-M virt" as emulated maschine in QEMU.
The basic process to set up the initial QEMU armbox (folder in repo: inital_image)
- Download the latest ArchLinuxARM image using 0_download_archlinuxarm.sh
- 1_create_rootimg.sh will create a RAW QEMU image, loopback-mount it, extract the downloaded ArchLinuxARM-armv7-latest.tar.gz into the mounted image.
- 2_create_initramfs.sh will create an initramfs. This initramfs will contain ALL current kernel modules. That way we can be sure that all QEMU devices are initialized correctly in initramfs during boot. This script will extract the latest modules from the downloaded ArchLinuxArm tar.gz file and repack them into a new all-modules containing initramfs.
- 3_get_zImage.sh will extract the kernel image (zImage).
- boot your device using 4_start_armbox_initial.sh. Take a look at the QEMU start command, which will explain the previous scripts further more.
After you booted the initial image successfully, you may update the image. After the first kernel update inside the armbox use 1_get_latest_initramfs.sh to
extract the latest initramfs and kernel image out of the updated armbox.img RAW image partition. We need these files to boot our system in QEMU (we add the
initramfs and the kernel image (zImage) as parameters, when
qemu-system-arm is executed. See 4_start_armbox_initial.sh). You have to extract the initramfs
and the kernel image after each kernel update!
Why the extraction process?
The qemu-system-arm's "-M virt" emulated hardware needs kernel modules which are not included in the default initramfs of ArchLinuxARM. Thats why I added a script to prepare an initramfs which includes all-modules. When Archlinux updates the kernel on a booted installation, an autodetect script checks the current hardware and includes only the modules which are really needed for booting YOUR hardware into the new initramfs. Thats also the reason for the really big initial initramfs my script builds and the comparatively small one, after the first kernel update, extracted by 1_get_latest_initramfs.sh.
You can use the 2_start_armbox_latest.sh to boot QEMU using the extracted initramfs and kernel image.
The armbox has 2 network interfaces, one NATed and the other one is added to a bridge on the host called vmboxnet. On my host thats an interface on which I bind services (like SSH and in this case myhttpd) to access them. If you see IP addresses through this post:
- 192.168.250.1 is the hosts IP on the vmboxnet
- 192.168.250.100 is the virtualized armbox QEMU guest on vmboxnet
You will also need to to create the file
/etc/qemu/bridge.conf and add:
to that file so that the qemu vm boots successfully.
Important: (For now) disable ASLR on the virtual environment:
echo 0 > /proc/sys/kernel/randomize_va_space
myhttpd: vulnerable microhttpd implementation
I created a simple vulnerable HTTP daemon based on GNU Libmicrohttpd's example code. Spot the Stack Based Overflow :)
Find the code in my GitHub
You will need libmicrohttpd installed on the armbox. Archlinux has a precompiled package:
pacman -S libmicrohttpd
Then compile myhttpd:
gcc -lmicrohttpd httpd.c -o myhttpd`
and copy it into the folder
For easier use I wrote a systemd service file, which restarts myhttpd, after it crashed:
[root@armbox microhttps]# cat /etc/systemd/system/myhttpd.service [Unit] Description=myhttpd [Service] ExecStart=/usr/sbin/myhttpd 8080 Restart=always [Install] WantedBy=multi-user.target
systemctl enable myhttpd systemctl start myhttpd
I am going to use the latest radare2 version, together with gdbserver running on the armbox. Through the vmboxnet interface I connect radare2 to armboxnet.
armbox: while true; do gdbserver --attach :5000 $(pidof myhttpd);done
host: r2 -a arm -D gdb gdb://192.168.250.100:5000