Open-source project
pr0v3rbs/FirmAE avatar
pr0v3rbs/FirmAE

FirmAE: emulating IoT firmware to find bugs in routers and cameras

Towards Large-Scale Emulation of IoT Firmware for Dynamic Analysis

955 stars155 forksPythonMIT

At a glance

What is it?
FirmAE is a research framework from KAIST's SysSec Lab that boots consumer router and IP camera firmware under emulation and hunts for vulnerabilities automatically, using five arbitration techniques to raise the rate at which firmware boots. It is a security research tool, tested on Ubuntu 20.04, and the last tagged release dates from 2020.
Who is it for?
FirmAE fits a security researcher who needs to boot vendor firmware images they do not own hardware for, and it does not fit a production pipeline or an untested corporate environment, because the authors tested it on Ubuntu 20.04, the requirements pin old versions such as Flask 2.0.1 and cryptography 3.4.7, and the only tagged release is v1.0 from 2020-11-23 even though the last push was on 2026-06-24.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 121 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem is firmware you cannot boot on the hardware you own

FirmAE is described as a fully-automated framework that performs emulation and vulnerability analysis on firmware images. The practical problem it addresses is straightforward. A security researcher who wants to look at a consumer router or IP camera image usually faces two bad options: buy the device and instrument it, which is expensive and slow, or try to run the firmware under QEMU, which frequently fails because the image expects specific hardware, a specific network layout and a specific kernel behaviour. The project reports that its five arbitration techniques lift the emulation success rate from Firmadyne's 16.28% to 79.36%, and that it was tested on 1,124 wireless router and IP camera firmware images from the top eight vendors. Read those as the authors' own reported figures rather than as independently confirmed numbers, since the repository links a Google spreadsheet of results rather than a published benchmark suite. The audience is narrow: firmware security researchers and the labs that support them.

Arbitration is the part that decides whether a firmware boots

The arbitration techniques are the core mechanism, and the documentation exposes them as shell variables in a config file rather than hiding them behind command line flags.

sh
$ head firmae.config
#!/bin/sh

FIRMAE_BOOT=true
FIRMAE_NETWORK=true
FIRMAE_NVRAM=true
FIRMAE_KERNEL=true
FIRMAE_ETC=true

Each flag corresponds to a class of arbitration the framework can apply when a boot attempt misbehaves: booting, networking, NVRAM handling, kernel level and a catch-all. The documentation notes that when FIRMAE_ETC is on, TIMEOUT is set to 240. Because these are plain shell variables in firmae.config, an analyst can turn a single technique off, rerun the same image and see whether the boot succeeds. That is the practical debugging loop, and it is also the honest way to understand the 79.36% figure: it is a headline number over a set of techniques, and each technique can be isolated.

Installation is three shell steps and one OS assumption

The documentation is explicit that the project was tested on Ubuntu 20.04, which is the single most important constraint for anyone planning to run it today. The install sequence is three commands, and the clone is recursive, which matters because the repository carries a .gitmodules file and submodules are needed for the framework to work.

console
$ git clone --recursive https://github.com/pr0v3rbs/FirmAE
$ ./download.sh
$ ./install.sh

download.sh fetches the external components, and install.sh sets up the environment. The Python side is pinned hard in requirements.txt: Flask 2.0.1, werkzeug 2.0.3, cryptography 3.4.7, pycryptodome 3.10.1, paramiko 2.7.2, psycopg2 2.9.1, scrapy 2.5.0, selenium 4.27.1, beautifulsoup4 4.9.3, requests 2.32.3, urllib3 2.2.3 and python_magic 0.4.24, with pytest 6.2.4 for tests. The presence of Flask, selenium, scrapy and psycopg2 tells you the analysis side drives a web service, a browser and a PostgreSQL database, so this is a multi-service tool rather than a single script.

run.sh has four modes, and two of them drive the network

The runtime entry point is run.sh, and the mode letter decides what happens. Preparation starts with init.sh, which prepares the environment, and the documentation then shows a sample firmware download with wget for a D-Link DIR-868L image. The modes are as follows.

console
$ sudo ./run.sh -c <brand> <firmware>
$ sudo ./run.sh -a <brand> <firmware>
$ sudo ./run.sh -r <brand> <firmware>
$ sudo ./run.sh -d <brand> <firmware>
$ sudo ./run.sh -b <brand> <firmware>

-c checks emulation only, -a analyses the target firmware with the FirmAE analyzer, -r is a run mode for testing the web service or executing a custom analyzer, -d is a user level debugging utility, and -b is a kernel level boot debugging mode. The brand argument selects a device profile, so the framework is driven by per-vendor knowledge rather than by generic heuristics alone. The repeated use of sudo is not incidental: the emulation opens privileged resources and the debug modes attach network services.

Debug mode opens a reverse shell on 31337 and telnet on 31338

The user level debugging utility is documented as useful when an emulated firmware is network reachable or not, and it states that the setup is done automatically. The details matter for anyone running this on a shared machine. It supports a socat connection, an nc reverse shell on port 31337 and a telnet connection on port 31338. Those are the classic default ports for a netcat reverse shell, and they are unauthenticated by design, because the point is to get a shell inside the emulated environment. The documentation does not describe any authentication or bind-address restriction for these listeners. The kernel level boot debugging mode, -b, sits underneath that and is used after run.sh -c has finished, which is the point at which a failed boot has produced logs worth reading. Between these two modes, the framework gives you both halves of the debugging cycle, and both halves assume the host is a lab machine you control.

Docker mode runs a list of images instead of one at a time

For bulk work the project offers a Docker path, which starts with building the image.

console
$ ./docker-init.sh
$ ./docker-helper.py -ec <brand> <firmware>
$ ./docker-helper.py -ea <brand> <firmware>
$ ./docker-helper.py -ed <firmware>

The helper script takes -ec to check emulation only, -ea to check emulation and analyse for vulnerabilities, and -ed for debug mode after an image has already been emulated. The firmware argument here is different from the command line mode: the documentation says it can be a text file listing the paths of firmware images, with a sample at examples/test.list, and the top level of the repository also carries a firmwares/ directory and a database/ directory alongside core/, analyses/, sources/, scripts/ and util/. That layout reflects the pipeline: images come in through firmwares/, results land in the database/ directory, and the analysis code sits under analyses/. The Dockerfile path is the realistic way to process hundreds of images on a cluster, since it isolates the pinned dependency set from the host.

Firmadyne is the baseline, and the difference is arbitration

The comparison the project itself draws is with Firmadyne, the well-known open source firmware analysis platform, and it is a real architectural difference rather than a feature list. Firmadyne's approach is to boot firmware in an emulated environment with symbolic execution support, and its success rate on real consumer images is low for reasons that are not mysterious: the images depend on hardware behaviour, kernel quirks and network assumptions that a generic emulator does not reproduce. FirmAE's premise is that the missing piece is a set of arbitration techniques that intervene when the boot misbehaves, and by applying them selectively, a much larger fraction of images reach a usable state. The authors also built a dynamic analysis tool that infers web service information from the filesystem and kernel logs of the target, and report discovering 12 previously unknown vulnerabilities affecting 23 devices by running it over successfully emulated images. The CVE list in the repository is grouped by vendor, with entries for ASUS, Belkin, D-Link and TRENDNet, so the researchers published their findings rather than keeping them for themselves.

One release, an MIT licence, and an old Ubuntu assumption

The maintenance story is short. The repository is not archived and the last push was on 2026-06-24, but the only tagged release is v1.0, the first release, dated 2020-11-23. There is no 1.1, no 2.0, and no release notes describing what changed after 2020, so the work since then is on master and unpinned. The licence is MIT, with the text in a LICENSE.txt file at the root, which permits commercial use and modification and carries no copyleft obligation, though that says nothing about the terms of the firmware you analyse. The project is a research artefact from SysSec Lab at KAIST, and the documentation asks users to cite the ACSAC 2020 paper. Practically, the cost of adoption is not the licence but the environment: an Ubuntu 20.04 assumption, a dependency set frozen in 2020, and a framework that expects root-level access to a machine dedicated to running untrusted vendor code.

Editorial conclusion

FirmAE fits a security researcher who needs to boot vendor firmware images they do not own hardware for, and it does not fit a production pipeline or an untested corporate environment, because the authors tested it on Ubuntu 20.04, the requirements pin old versions such as Flask 2.0.1 and cryptography 3.4.7, and the only tagged release is v1.0 from 2020-11-23 even though the last push was on 2026-06-24. Before you run it, read the five arbitration flags in firmae.config and decide which of FIRMAE_BOOT, FIRMAE_NETWORK, FIRMAE_NVRAM, FIRMAE_KERNEL and FIRMAE_ETC you want enabled, and isolate the machine, since the debug mode opens a reverse shell on port 31337 and a telnet listener on 31338.

Frequently asked questions

What operating system does FirmAE need?

The documentation states that FirmAE was tested on Ubuntu 20.04. The install itself is a recursive git clone followed by running download.sh and install.sh, and the Python dependencies are pinned in requirements.txt.

What is the difference between run.sh -c, -a and -r?

Analysis mode uses the FirmAE analyzer with -a, run mode with -r helps you test the web service or execute a custom analyzer, and -c checks emulation only. There are also -d for user level debugging and -b for kernel level boot debugging.

How do I turn the FirmAE arbitration techniques on or off?

The five arbitration techniques are environment variables in the firmae.config file: FIRMAE_BOOT, FIRMAE_NETWORK, FIRMAE_NVRAM, FIRMAE_KERNEL and FIRMAE_ETC. Setting FIRMAE_ETC also sets TIMEOUT to 240.

What licence does FirmAE use?

FirmAE is MIT licensed, with the licence text in a LICENSE.txt file in the repository root. The project is a research artefact from SysSec Lab at KAIST.

Official sources

  1. Issues
  2. License: MIT
  3. pr0v3rbs/FirmAE on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pr0v3rbs-firmae.svg)](https://hysenlabs.com/projects/pr0v3rbs-firmae)

Was this useful?