Emulation is a way to answer a research question, not a success condition by itself. Use the smallest execution layer that can change your decision.
| Claim area | Source |
|---|---|
| QEMU user-mode runs foreign-architecture user programs on the host OS and translates syscalls | QEMU user-mode documentation |
| QEMU system emulation models a machine with CPU, memory, and emulated devices for a guest OS | QEMU system-emulation documentation |
| Single-service rehosting can avoid full-device fidelity for Linux firmware services | Greenhouse, USENIX Security 2023 |
| Large-scale full-system IoT rehosting depends on environment-recovery heuristics | FirmAE repository, FirmAE publication record |
| Peripheral behavior can be modeled only as needed to reach a point of interest | Jetset, USENIX Security 2021 |
| Kernel-module questions may require userland plus kernel-level rehosting | Pandawan repository |
| MCU firmware is blocked by peripheral and interrupt behavior, not just CPU ISA | P2IM, USENIX Security 2020 |
| EMBA L10/S115/S130 behavior in this repository | EMBA source-code capability map |
| A focused web-service harness can be enough for exploit development when route, CGI, auth state, and process context are known | Claroty Team82 Planet WGS-804HPT industrial switch research |
| A custom analysis OS can import vendor rootfs/firmware while exposing debug tools, NVRAM preload, NFS/shared files, and optional MTD flash | ARMX Firmware Emulation Framework, local emulation folder |
| Raw NAND/UBI reconstruction is justified when persistent state is outside the rootfs | Local Gemtek case: README, set-nandsim.sh |
| JFFS2/UBIFS reconstruction may depend on OOB/ECC, VID offset, bad-block reserve, and volume metadata | Claroty Avaya IP phone, Unauthorized Access Connexoon, Youngrok nandsim and UBIFS partitioning |
| eMMC storage has different evidence semantics from raw NAND/MTD | Youngrok eMMC raw access notes |
The ordering and scoring guidance below is a synthesized heuristic derived from those sources and the local EMBA source code.
| Layer | What it can prove | What it cannot prove | Minimum evidence output |
|---|---|---|---|
| Static analysis | Files, versions, routes, startup scripts, caller/sink relationships | Runtime reachability, board state, exact service behavior | Input-to-sink graph with file/function evidence |
| QEMU-user | One ELF can execute far enough to expose version/help output, syscall/file dependencies, parser behavior, or a crash under host-kernel syscall translation | Full device boot, real kernel behavior, real NVRAM/peripherals, network service defaults | Command, stdout/stderr, exit status, QEMU_STRACE/strace, breakpoint/crash |
| Service harness/chroot | A target service can start with selected libraries/config/env and receive requests | Faithful init, board devices, flash layout, hardware-backed state | Listener, request/response, missing-file/device/syscall list |
| Custom analysis OS / Buildroot guest | Vendor binaries run inside a controlled guest with compatible libc/kernel choices, debug tools, imported rootfs, and optional flash/NVRAM data | Original bootloader, board peripherals, exact init, production network exposure | Guest kernel/config, imported paths, launch commands, debug logs, synthetic assumptions |
| Full-system QEMU/FirmAE/EMBA L10 | Kernel/init/network/service hypotheses in a repaired generic machine | Exact target SoC, boot ROM, fuses, proprietary peripherals, original launch conditions | Serial log, process list, port scan, launch command, filesystem repairs |
| MTD/UBI simulation | Kernel MTD semantics for a raw flash partition: eraseblocks, UBI attach, JFFS2/UBIFS mount behavior, and /dev/mtd* consumers |
Secret material that was not present in the raw dump; vendor flash-controller ECC behavior unless modeled | /proc/mtd, ubiattach/mount output, partition geometry, files recovered from persistent storage |
| Hardware | Peripheral, boot-chain, flash, radio, secure-element, timing, and board-state evidence | Broad static coverage by itself | Boot log, read-only flash, pin/state observation, debug trace |
Write the unknown first:
Question:
Current evidence:
Two possible explanations:
Observation that would distinguish them:
Cheapest experiment:
Abandon condition:
Then choose:
file/version/route/sink question -> static
one binary/parser/version question -> QEMU-user
service startup/request question -> service harness
old libc/kernel/debug-tool compatibility question -> custom analysis OS
init/kernel/network/multiple-service question -> full-system emulation
peripheral/boot ROM/fuse/radio/flash-layout question -> hardware
Escalate only if the next layer can produce an observation that the previous layer cannot. If both hypotheses would look the same in QEMU-user, QEMU-user is not the next experiment.
Use nandsim, mtdram, ubiattach, JFFS2, or UBIFS tooling when the lead
depends on kernel MTD semantics or a persistent partition outside the extracted
rootfs. Do not use it merely because the device uses NAND.
The local Gemtek WVRTM-127ACN case shows the trigger pattern. The writeup records a
128 MB NAND dump, page and erase geometry (writesize=2048, oobsize=64,
erasesize=131072), a partition table with Config, Env, Kernel, and Storage
partitions, and boot evidence that mtd8 is attached as ubi8 and mounted as
UBIFS at /mnt/jffs2. The project script then loads nandsim with matching
partition sizes, erases /dev/mtd0 through /dev/mtd8, writes each partition
image with nandwrite, and mounts /dev/ubi8_0 at /mnt/jffs2.
README,
set-nandsim.sh
That evidence changes the decision:
| Observation | Interpretation | Cheapest next experiment | Abandon condition |
|---|---|---|---|
Secrets or accounts are absent from SquashFS but init links /etc into /mnt/jffs2 |
persistent UBIFS may be the real credential/config store | reconstruct the UBI partition read-only and list mounted files | raw dump lacks the relevant partition or mount geometry cannot be supported |
Boot log shows UBI: attached mtd8 to ubi8 and UBIFS: mounted |
kernel MTD/UBI behavior is part of the runtime filesystem | attach the matching MTD partition with the recorded VID/header offset | attach succeeds but recovered files do not feed the lead |
Binaries or scripts read /dev/mtd*, /proc/mtd, U-Boot env, factory, caldata, or storage partitions |
QEMU-user alone will miss the storage contract | provide an MTD/UBI-backed harness only for that consumer | the consumer only needs a constant value that static analysis already proves |
| Default password is generated by one helper from serial/MAC inputs | NAND simulation may be unnecessary | reverse or run the helper with vendor libraries and known inputs | no flash-backed value is consumed by the algorithm |
| Secret is expected to be per-device but only a vendor update package is available | simulation would create empty or generic state | search the package for raw config/factory images first | no raw partition image exists; hardware read is the next scoped question |
What this proves:
the dumped partition can be interpreted with the chosen MTD/UBI parameters
files or values exist in that recovered persistent storage
a script/binary path can consume those files or values
What it does not prove:
secrets that were never present in the dump
bad-block, OOB, ECC, or vendor controller behavior unless captured or modeled
that a service is reachable on the original board
that generated first-boot state matches a clean device unless the boot path is reproduced
False-positive risks are high when page size, eraseblock size, OOB handling, bad-block policy, UBI VID/header offset, or partition boundaries are guessed. A failed mount with guessed geometry is not evidence that the device lacks the secret. A successful mount of a synthetic empty partition is also not evidence about a shipped device.
Use the practitioner examples to classify failures:
| Failure or blocker | Likely meaning | Next action |
|---|---|---|
| JFFS2 mount works only after partition splitting | filesystem nodes from different partitions were being mixed | recover partition table before interpreting files |
| mount/write-back fails with ECC errors | OOB/ECC layout is controller-specific | preserve OOB evidence and avoid write-back claims until ECC is understood |
| UBI attach succeeds but available LEBs are unexpectedly low | bad-block reserve or volume sizing changed capacity | inspect ubinfo, ubiattach -b, VID offset, and ubinize parameters |
| extracted update has UBI volumes but no per-device data | update package is not the same as a full flash dump | downgrade secret claims or move to scoped hardware acquisition |
target uses /dev/mmcblk* instead of /dev/mtd* |
eMMC/SD partition semantics, not NAND MTD semantics | inspect GPT/MBR, boot partitions, read-only flags, and secure/RPMB-like areas |
| repeated test writes risk flash wear | dynamic experiment may damage the target | use removable-media pivot, overlay, emulator, or read-only proof first |
QEMU user-mode is strong evidence for local userland behavior. It is weak evidence for device behavior.
Use it when:
- a parser can be exercised by a file or packet-like buffer;
- a CGI/helper binary needs vendor libraries;
- version/help output is needed for SBOM/CVE triage;
- missing files or syscalls will tell you which config gates a path;
- a crash must be tied to controlled input before heavier work.
Record:
binary hash
architecture and endian
dynamic loader and library path
rootfs prefix
environment variables
arguments and input file
stdout/stderr/exit
strace/QEMU_STRACE findings
Do not claim network reachability, daemon default state, privilege context, or hardware behavior from QEMU-user alone. QEMU's own documentation describes user-mode as launching programs compiled for another CPU on the same OS, with syscall translation; that is not a virtual board.
A service harness is the middle path between one binary and the whole device. It is justified when the claim depends on a listener, route, config file, environment variable, or adjacent helper process.
Good harness questions:
- Does
/cgi-bin/diagreach the handler named in the config? - Does the service parse this request before authentication?
- Which missing NVRAM key decides whether the route is enabled?
- Does the daemon run as root in the original startup script?
False-positive risks:
- You supplied config that the device would not ship with.
- You disabled authentication or feature gates accidentally.
- You launched a helper outside the original working directory/user/env.
- You satisfied
/dev,/proc,/sys, or NVRAM with synthetic values.
Before using a harness result in a report, compare it against original startup files and record every synthetic file, argument, and environment variable.
The Claroty Planet WGS-804HPT case is the useful boundary: they extracted the
firmware, selected the Boa web service because it was the network-facing
management component, mapped dispatcher.cgi as a pre-auth CGI target, then
used QEMU/chroot and QEMU GDB support to validate the vulnerable cookie path.
The reusable rule is not "emulate the whole switch"; it is "emulate the
component whose route, auth state, and sink already make it the highest-value
candidate."
Use this pattern when a normal chroot is too thin, but faithful board emulation is not the research question. You build or reuse a Linux guest that is close enough for the target binaries, then import the vendor rootfs, firmware partitions, debug tools, and storage scripts.
Good triggers:
- QEMU-user finds libc, loader, thread, crypto, or kernel-version mismatches that block the target binary;
- the target needs old uClibc/glibc, libgcrypt, kernel headers, or GDB support that are easier to reproduce with Buildroot than on the host;
- you need
strace,ltrace,gdbserver, SSH, or file-transfer tools inside the guest while keeping the vendor rootfs mostly separate; - the lead depends on imported firmware files, update packages, NVRAM data, or MTD/UBI experiments, but not on exact board peripherals.
Local examples:
| Example | What it builds | What it imports | Decision lesson |
|---|---|---|---|
| emulation/myrootfs | old ARM/XScale-style Linux rootfs and toolchains | printer flash-root artifacts for selected binaries | use an older build environment when modern libc/toolchains distort behavior |
| emulation/buildroot-armv7 | ARMv7 vexpress-a9 Buildroot guest with Linux 3.4.11-rt19, uClibc, debug tools, MTD/UBI utilities |
Netgear DVA rootfs under /dva-root and firmware under /dva-firm |
build a compatible analysis OS, not a faithful router, when sig_verify and update-chain binaries are the target |
| emulation/hht | MIPS Malta Buildroot guest for the Hardware Hacking Tutorial/Gemtek-style workflow | router rootfs and set-nandsim.sh |
preserve old Buildroot/uClibc compatibility and flash tooling when the research needs it |
| NB6VAC emulation | early MIPS/Buildroot 2015.02 environment with UBIFS/JFFS2 tooling | NB6VAC artifacts and kernel/rootfs work | treat partial emulation as a hardware/rootfs experiment, not a secure-boot conclusion |
| ARMX | Docker-packaged ARM/QEMU framework with per-device config, NFS-shared /armx, NVRAM preload, optional flash memory, and helper commands |
rootfs archives, nvram.ini, optional flashmem, preload libraries |
formalize device onboarding with config, NVRAM, flash, port forwarding, and debug logs |
Evidence to record:
why QEMU-user/chroot was insufficient
guest CPU/machine/kernel/libc/toolchain versions
vendor rootfs and firmware import paths
original startup evidence versus guest launch commands
debug tools added to the guest
NVRAM, flash, `/proc`, `/sys`, `/dev`, or preload assumptions
which observation promoted or rejected the lead
False-positive risks:
- the guest kernel accepts behavior the original kernel would reject;
- imported rootfs paths are convenient but not original mount points;
- NVRAM or flash values are defaults, guesses, or copied from another device;
- Docker bind mounts expose more host state than the experiment needs;
- debug-friendly compiler flags, disabled stripping, or added libraries change timing, memory layout, or loader behavior.
Mount only the workspace needed to preserve paths. The local Buildroot examples
often mount the user's whole home directory so old scripts can see sibling
buildroot-*, firmware, and project directories at identical absolute paths.
That is a convenience pattern, not an evidence requirement. Prefer mounting the
smallest project parent that contains the Buildroot tree, emulation tree, and
firmware inputs.
Abandon this branch when the setup becomes a toolchain archaeology project and the lead can be answered by static analysis, targeted QEMU-user, or a simpler service harness. Reopen it when a specific binary or update-chain question requires the old userspace/kernel/debug environment.
Use full-system emulation when init, kernel, networking, or multiple services are material to the claim. It is not a certificate of device fidelity.
FirmAE reports large improvements over Firmadyne by applying arbitration heuristics to boot, network, NVRAM, kernel, and filesystem issues. That is the important lesson: successful rehosting often requires environment repair.
For EMBA specifically, read
emba-source-capability-map.md
before interpreting L10 output. In this local source tree, L10 modifies the
research image with scripts such as fixImage.sh, inferFile.sh,
inferService.sh, and run_service.sh. It may create device nodes, root
credentials, NVRAM placeholders, service-launch guesses, and debug listeners.
Therefore:
Booted -> kernel/userspace startup evidence
ICMP ok -> emulated host reached ICMP
TCP ok -> at least one scanned TCP/UDP service was observed
port -> must be mapped to PID and launch source
An open port is a lead. It becomes stronger only after you show the command line came from original firmware logic or you clearly label the synthetic launch conditions.
Hardware is worthwhile when software-only evidence cannot answer a question that materially changes the finding.
Proceed when all are true:
the missing fact is hardware-dependent
the exact board or a meaningfully compatible target is available
the access method is understood and authorized
the result will change the report or next experiment
Use hardware first for:
- secure boot, fuses, BootROM, trust anchors;
- external flash/NVRAM not present in an update image;
- GPIO, sensors, camera pipeline, radio, or USB feature gates;
- proprietary kernel drivers or MMIO/ioctl security decisions;
- timing/pairing/state machines that cannot be modeled cheaply.
Do not buy a generic board because the CPU architecture matches. Board wiring, flash layout, boot ROM policy, device tree, peripherals, and vendor drivers are often the claim.
Use this synthesized planning score when a lead competes with setup work:
emulation_value =
3 * importance_of_unknown
+ 2 * probability_the_layer_can_answer_it
+ 2 * reuse_for_other_leads
+ 1 * evidence_quality_gain
- 2 * setup_cost
- 2 * peripheral_or_state_uncertainty
Proceed only with a bounded experiment:
time box:
expected observation:
what I will do if it works:
what I will do if it fails:
If the score is negative, keep the lead as a hypothesis and choose a cheaper static or targeted test.
| Lead | Best first method | Why | Stop condition |
|---|---|---|---|
| Hardcoded credential string | Static consumer trace | Impact depends on where the credential is used | No reachable login/service consumes it |
| CGI command sink | Static route-to-sink, then harness | The route and quoting decide exploitability | No attacker-controlled parameter reaches the sink |
| Native parser crash | QEMU-user | The parser is the object under test | Crash requires synthetic-only state unrelated to shipped input |
| HTTP service appears only after init | Service harness or L10 | Startup/network context is material | Service launch is synthetic and original init does not support it |
| Firmware update rollback | Static updater trace, then full system/hardware | Persistence/slot state matters | Package cannot be attacker supplied or rollback is enforced |
| Kernel module ioctl | Hardware or kernel-level rehosting | Generic userland cannot prove driver/MMIO semantics | Module is absent, not loaded, or ioctl is unreachable |
| MCU RTOS firmware | Static plus targeted peripheral model/hardware | Peripherals and interrupts dominate | Required peripheral state is unknown and not relevant to the finding |
Stop an emulation branch when:
- it no longer answers the written question;
- setup consumes the time box without producing new evidence;
- missing behavior is synthetic and unrelated to the claim;
- the remaining blocker is hardware-only and out of scope;
- another lead has a complete input-to-impact chain at lower cost.
Write the stop note:
Attempt:
Evidence gained:
Missing edge:
Why more emulation is not worth it now:
Reopen condition:
Keep that note in the case record. It tells the next researcher exactly what was learned and where confidence ends.