HackFortressOS - Adventures with Buildroot

About The Project

Arch Cloud Labs’ last three blog posts were diving into different aspects of IoT/embedded vulnerabilities. Coming off of these bug hunting adventures, I wanted to build a unique set of Capture The Flag (CTF) challenges for this year’s Hack Fortress. To do this, I referenced OWASP’s Top 10 for IoT and Buildroot to build the custom operating system for a Raspberry Pi 1 that was deemed “HackFortress OS”. This blog post will give a high level overview on how Buildroot was used to make a custom platform along with a discussion on some of the challenges that were spun off from HackFortress OS.


Buildroot - Make, but for Entire Embedded Systems

Buildroot is a build system that enables end users to build custom operating systems for a given embedded platform. Ultimately, you pick a Linux kernel, select the options for the kernel/packages/etc., and end up with your final embedded operating system. Obtaining the latest release and listing the contents of the board directory shows the various platforms Buildroot supports. Below is a truncated output of supported boards. Notably, we see “Raspberry Pi” as in the first Raspberry Pi made. A platform that’s over ten years old, and just the appropriate board to build a vulnerable embedded system to let hackers poke at for the ShmooCon conference weekend.

ls ~/buildroot/board/
minnowboard  openblocks  qemu           raspberrypi2      raspberrypicm4io-64  sipeed             
nexbox       orangepi    qmtech         raspberrypi3      raspberrypizero2w    solidrun          
nezha        pandaboard  radxa          raspberrypi3-64   roseapplepi          spike            
octavo       pc          raspberrypi    raspberrypi4      seeed                stmicroelectronics  
olimex       pcengines   raspberrypi0   raspberrypi4-64   sheevaplug           synopsys       
olpc         pine64      raspberrypi0w  raspberrypicm4io  sifive               technexion        

With Raspbery Pi identified as the target system, the next step is to build a default configuration to modify to the end user’s desired needs.

 buildroot $> make raspberrypi_defconfig
# configuration written to /home/dllcoolj/buildroot/.config
➜  buildroot 

Those familiar with building custom kernels and the ncurses view provided by make menuconfig will be right at home with this next section. The initial configuration menu contains numerous submenus that allow Buildroot users a lot of flexibility when it comes to building a custom image. Prior to going forth and exploring all of the submenus, I recommend you build a simple default config (make defconfig) to make sure your hardware works as expected and you gain familiarity with the build process. Diving into the submenus, here’s a brief breakdown of what’s available and relevant to how HackFortress OS was built:

  • Toolchain: This is where you can specify target options for the underlying architecture you’re using. The Raspberry Pi is an ARM based platform, but you can specify additional architecture options should you be building on a device where the ARM chip supports it. This is another example of why building the defconfig and tweaking from a known good state is a recommended practice.


  • Build options: This submenu specifies caching options for the actual building of the embedded system. Additionally, here is where you can enable or disable core security features that help prevent against memory corruption. One of the challenges for competitors this year was a basic buffer overflow, and naturally, we had this option disabled.


  • Target packages: This submenu allows you to specify what packages you want on the embedded device. It also includes several popular Python packages you would normally expect to install through pip. A challenge this year was exploiting a vulnerable web API which required Flask. While the Raspberry Pi 1 took about five seconds to launch the Flask app (thus really showing its age), Buildroot had no problems running a recent version of Flask for such an old device.


  • Filesystem options: This submenu allows you to specify the target filesystem for your device. For CTFs this was a big choice as your competitors are going to be leveraging a variety of forensic tools to carve out files. It’s also important to consider how large of a file system you’ll be giving the competitors as no one wants to transferred a 100GB image where the vast amount of image is effectively empty space.


After making your changes, simple execute make and the build process for your final image will be produced in the output/images directory.

[dllcoolj@thonkpad images]$ pwd
[dllcoolj@thonkpad images]$ ls -l
total 154052
-rwxr-xr-x 1 dllcoolj docker     27696 Jan  7 20:58 bcm2708-rpi-b.dtb
-rwxr-xr-x 1 dllcoolj docker     27967 Jan  7 20:58 bcm2708-rpi-b-plus.dtb
-rwxr-xr-x 1 dllcoolj docker     27581 Jan  7 20:58 bcm2708-rpi-cm.dtb
-rw-r--r-- 1 dllcoolj docker  33554432 Jan  7 20:58 boot.vfat
-rw-r--r-- 1 dllcoolj docker 125829120 Jan  7 20:58 rootfs.ext2                 // file system
lrwxrwxrwx 1 dllcoolj docker        11 Jan  7 20:58 rootfs.ext4 -> rootfs.ext2
drwxr-xr-x 1 dllcoolj docker       118 Jan  7 20:45 rpi-firmware
-rw-r--r-- 1 dllcoolj docker 159384064 Jan  7 20:58 sdcard.img                  // the Raspberry Pi image to 
-rw-r--r-- 1 dllcoolj docker   6012640 Jan  7 20:58 zImage                      // the kernel

At this point you should have a bootable image for your target device. Logging into HackFortressOS (HFOS) we see a whopping 32MB of RAM used. As you can see, when you build a “farm-to-table” embedded OS, you can really optimize out all pesky those security features and get the most out of your embedded system.

# hostname

# free -h
              total        used        free      shared  buff/cache   available
Mem:         394.2M       29.0M      332.4M      116.0K       32.7M      355.4M
Swap:             0           0           0

Making Things Boot - Exploring Init Systems

Buildroot lets you specify what you’d like your embedded OS to have as an init system. Choices include Systemd, SysV, and “BusyBox’s Init” scripts. Hackfortress OS uses BusyBox’s init scripts, and custom modifications are placed within output/target/etc/init.d. Why use BusyBox’s init scripts vs SysV? This manifesto was enough of a justification for me, and it was simple enough to throw together and get running. This file structure is what ends up getting built into the final filesystem image.

[dllcoolj@thonkpad init.d]$ ls -l
total 28
-rwxr-xr-x 1 dllcoolj docker  423 Jan  7 20:43 rcK
-rwxr-xr-x 1 dllcoolj docker  408 Jan  7 20:43 rcS
-rwxr-xr-x 1 dllcoolj docker 1243 Jan  7 20:45 S01seedrng
-rwxr-xr-x 1 dllcoolj docker 1012 Jan  7 20:43 S01syslogd
-rwxr-xr-x 1 dllcoolj docker 1004 Jan  7 20:43 S02klogd
-rwxr-xr-x 1 dllcoolj docker 2804 Jan  7 20:43 S02sysctl
-rwxr-xr-x 1 dllcoolj docker  438 Jan  7 20:43 S40network

Building Challenges from The Custom OS

With HackFortress OS built, now we can move onto identifying the challenges to spin off of the concept of a vulnerable embedded system. This project ultimately this produced a series of challenges that covered the following items from the OWASP IoT Top Ten:

  • Hardcoded passwords/keys (1/10 on OWASP IoT 2018)
  • Insecure network services (2/10 on OWASP IoT 2018)
  • An insecure update mechanism (4/10 on OWASP IoT 2018)

These three tenets of vulnerability patterns led to the creation of a handful of fun puzzles. Here’s three that I liked the most:

  • HFOS API The HFOS API was a bytecode compiled Python Flask application that the competitor must reverse engineer to identify vulnerable endpoints. Ultimately there was a vulnerable code path that led to arbitrary file upload and execution.

  • HFOS Secure Firmware Update* For the “HFOS Secure Firmware Update” puzzle, the SDCard image that was produced from buildroot was then wrapped into a custom file format. This fileformat was then trasnferred to an “upstream staging server” via TFTP. Competitors had to extract the image from the TFTP stream and then reverse the image format to extract the SDCard image. Once the image was extract and mounted, the flag was obtained.

  • HFOS Lost SSH Keys Derek, a fellow Hack Fortress judge always loses his SSH keys. To make fun of this, I created a puzzle where you carve out a file system and find over 1k ssh keys. The competitor must then brute force the key combination to successfully log into the destination host.


Buildroot is a really cool utility that enables any Linux enthusiast the ability to build their own embedded OS. For purposes of CTF creation, there’s countless possibilities and scenarios where this utility can be employed to create a unique experience for your competitors. Thank you for reading and hackers thank you for playing. I look forward to next year where the last Hack Fortress at Shmoocon will be held.