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  || <----------------+
|      +-----------+
|                  |
+------------------+

Use the prebuild environment

You got 2 options: Build you own lab environment and build your own ROP chain. Since Archlinux updated libc, the ROP chain I will show you in the last part of this series will not work. The second option is to download my prepared armbox image, boot it and enjoy a working ROP exploit.

If you choose the second option you need to add a bridge on your host called "vmboxnet", IP: 192.168.250.1/24. The armbox will add itself to that bridge and will be reachable on 192.168.250.100/24.

You will also need to to create the file /etc/qemu/bridge.conf and add:

allow vmboxnet

to that file so that the qemu vm boots successfully.

If you choose the first option, continue. If you want to know how I build the armbox, continue.

Set up the QEMU environment on your own

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.

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)

  1. Download the latest ArchLinuxARM image using 0_download_archlinuxarm.sh
  2. 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.
  3. 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.
  4. 3_get_zImage.sh will extract the kernel image (zImage).
  5. 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. To update the image you have to initialize the archlinuxarm keyring:

pacman-key --populate archlinuxarm

Then you can update and install packages:

pacman -Syu

pacman -S gdb git gcc libmicrohttpd

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:

allow vmboxnet

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

To connect to the armbox, you need to set the IP:

ip addr add 192.168.250.100/24 dev eth0

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 -fno-stack-protector -lmicrohttpd httpd.c -o myhttpd

and copy it into the folder /usr/sbin.

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

Tools

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.

For reference:

armbox: while true; do gdbserver --attach :5000 $(pidof myhttpd);done
host: r2 -a arm -D gdb gdb://192.168.250.100:5000

<< previous post of this series | next post of this series >>