Kuboid
Open Luck·Kuboid.in

Emulating Embedded Linux Devices at Scale with Light-Touch Firmware Rehosting

DEFCONConference728 views38:276 months ago

This talk demonstrates a light-touch firmware rehosting technique for emulating embedded Linux devices by modifying the kernel and QEMU machine rather than patching user-space binaries. The approach focuses on creating a rehosting environment that satisfies the kernel's expectations for hardware, such as NVRAM and GPIO, to enable full-system emulation. This method allows for scalable vulnerability research and the deployment of honeypots across multiple devices sharing the same SoC. The speaker provides a practical walkthrough of patching QEMU and the Linux kernel to support various router firmware images.

Beyond LD_PRELOAD: Scaling Embedded Linux Emulation via Kernel-Level Rehosting

TLDR: Traditional embedded Linux emulation often relies on fragile user-space hacks like LD_PRELOAD to bypass missing hardware dependencies, which fails when dealing with complex, tightly coupled system-on-chip (SoC) architectures. By shifting the focus from patching binaries to modifying the kernel and QEMU machine, researchers can achieve high-fidelity, scalable emulation of entire firmware images. This approach allows for rapid vulnerability research and the deployment of honeypots across diverse hardware platforms without requiring the physical device.

Most of us have spent hours fighting with qemu-arm or qemu-mips, only to have a binary crash because it couldn't find a specific NVRAM key or a GPIO pin. The standard workflow for emulating embedded Linux—unpacking the firmware, chroot-ing into the root filesystem, and using LD_PRELOAD to shim missing libraries—is a dead end for anything beyond trivial binaries. It is a brittle, manual process that breaks the moment the target binary expects a holistic system environment.

The research presented at DEF CON 2025 on light-touch firmware rehosting changes the game by treating the kernel as the primary interface for emulation. Instead of fighting the user-space, you build a custom kernel and QEMU machine that satisfies the hardware expectations of the firmware. This is not about emulating every transistor on the SoC; it is about providing just enough of the hardware abstraction layer to keep the init process and core services happy.

The Architecture of the Rehosting Environment

Embedded Linux systems are almost always built on SoCs like those from Broadcom or Qualcomm. These chips are reused across dozens of different router models from vendors like ASUS, Netgear, and Tenda. The key insight here is that while the vendors differentiate their products in user-space, they all rely on the same underlying SoC-specific kernel drivers and hardware interfaces.

When you attempt to boot a firmware image in a generic QEMU environment, the kernel often hangs during the boot process because it cannot find the expected hardware. The rehosting approach involves identifying these "blockers"—typically NVRAM, GPIO, and network interfaces—and creating "fake" implementations within the kernel.

For instance, many Broadcom-based routers use a custom libnvram.so that communicates with a character device at /dev/nvram. If you build a kernel module that exposes a character device at that same path and implements the expected ioctl calls, you can satisfy the firmware's requirements without needing the actual hardware. You are essentially performing a man-in-the-middle attack on the kernel-user-space boundary.

Patching the Kernel for Hardware Parity

The most common point of failure in firmware rehosting is the NVRAM interface. On the ASUS RT-AC87U, for example, the firmware expects a contiguous block of memory to store key-value pairs. You can implement this by creating a kernel module that registers a character device and maps a portion of the flash memory to serve as the backing store.

Here is a simplified look at how you might handle the ioctl calls in your custom kernel module to satisfy the firmware's nvram_commit request:

static long nvram_ioctl(struct file *file, unsigned int cmd, unsigned long arg) {
    switch (cmd) {
        case NVRAM_COMMIT:
            // Write the current NVRAM buffer back to the emulated flash partition
            return write_to_flash(nvram_buffer);
        case NVRAM_GET:
            // Return the requested key-value pair from the buffer
            return get_key(arg);
        default:
            return -EINVAL;
    }
}

By intercepting these calls, you can ensure that the firmware believes it is running on a real router. Once the NVRAM is handled, the next hurdle is usually GPIO. Many routers poll GPIO pins to check for button presses (like the reset button). If the driver fails to open /dev/gpio, the init process might enter a boot loop. Creating a dummy GPIO driver that simply returns a neutral state—or a state that mimics the "up" signal—is usually enough to bypass these checks.

Scaling Research Across Vendors

This technique is highly transportable. Because many vendors use the same Broadcom SoCs, the same kernel patches and QEMU machine definitions can often be reused across different devices. If you have successfully emulated one router based on the BCM4709, you are 90% of the way to emulating another.

For a pentester, this means you can build a library of "rehosting profiles" for common SoCs. When you encounter a new target during an engagement, you don't start from scratch. You pull the appropriate SoC profile, drop in the new firmware image, and you have a running system in minutes. This is invaluable for fuzzing network services or testing authentication bypasses that require a fully initialized system state.

Defensive Considerations

From a defensive perspective, this research highlights the danger of relying on "security through obscurity" in hardware interfaces. If an attacker can easily emulate your device, they can automate the discovery of vulnerabilities at a scale that was previously impossible. Manufacturers should focus on hardening the kernel-user-space interface and ensuring that critical system services do not fail gracefully when hardware components are missing or unresponsive.

If you are working with embedded devices, stop trying to patch individual binaries. Start looking at the kernel interfaces those binaries rely on. By building a robust rehosting environment, you move from fighting the system to controlling it. The next time you are staring at a boot loop on a serial console, don't just look for the error—look for the hardware expectation that the kernel is failing to meet.

Talk Type
research presentation
Difficulty
advanced
Category
iot security
Has Demo Has Code Tool Released


DEF CON 33 Main Stage Talks

98 talks · 2025
Browse conference →
Premium Security Audit

We break your app before they do.

Professional penetration testing and vulnerability assessments by the Kuboid Secure Layer team. Securing your infrastructure at every layer.

Get in Touch
Official Security Partner
kuboid.in