Skip to content

Latest commit

 

History

History
780 lines (571 loc) · 25 KB

File metadata and controls

780 lines (571 loc) · 25 KB

EMBA Firmware Analysis Walkthrough

Date: 2026-05-25

Purpose: use EMBA as a firmware triage engine for IoT reverse engineering and vulnerability research. EMBA should produce leads. Manual analysis decides whether a lead is real, reachable, and worth reporting.

Clickable Menu

Role Of EMBA

Use EMBA for:

  • extraction attempts
  • component/version inventory
  • SBOM-style package discovery
  • CVE and exploitability hints
  • weak binary-function ranking
  • credential/private-key/config discovery
  • web/service/config attack-surface discovery
  • report/evidence generation

Do not use EMBA as:

  • the final vulnerability judge
  • proof of reachability
  • proof that a CVE applies to the actual shipped firmware behavior
  • a replacement for reading the vulnerable script/binary/config path yourself

Good final-reviewer sentence:

EMBA identified <lead>. I manually verified reachability through <route/service/config>, traced the vulnerable data flow into <file/function>, and reproduced <impact> with <command/request/test>.

How To Make The Most Of EMBA

Use EMBA in layers:

static inventory -> candidate lead -> reachability proof -> impact proof -> report

For an interview assignment, this is the best workflow:

  1. Run a quick/default scan and let EMBA build the first inventory.
  2. Open the HTML report only to orient yourself.
  3. Move to the raw logs and extracted filesystem for evidence.
  4. Pick leads with attacker reachability: web route, exposed service, update path, parser, script, credential, or command execution sink.
  5. Prove one path deeply instead of listing ten unverified CVEs.

The most useful EMBA modules/results are the ones that point to manual verification:

EMBA result Manual follow-up
Version/SBOM/CVE finding Confirm exact binary/library/version, then prove the vulnerable code is reachable.
Shell/Python/PHP/Lua finding Trace input to sink and build a minimal request/command that reaches it.
Credential/key/config hit Identify the service or account that consumes it.
Weak binary/security hardening result Find caller, reachable parser, or service context before claiming impact.
System-emulated service Interact with the exposed port/route and capture evidence.

Use EMBA's AI/OpenAI mode only as an optional explainer for selected snippets. The official AI page now marks the older integration as under heavy rework, and the LocalAI page is still under construction. For now, manual AI usage over small copied evidence bundles is safer and easier to control.

Kali vs Ubuntu Tool Split

You do not need to give me the full list of tools inside the EMBA Docker image unless a scan fails or you want an exact dependency audit. For your roadmap, the useful split is enough:

If Kali/EMBA works well, Ubuntu is not required for the assignment. The smallest useful setup is:

Kali VM: EMBA + manual Linux CLI checks
Windows host: GUI reverse engineering if needed
Ubuntu VM: optional backup only
Environment Job Why
Kali VM EMBA classic Docker mode, broad automated triage, EMBA reports Matches EMBA's tested workflow best
Ubuntu VM manual workbench: extraction, grep, QEMU/GDB, scripts, tcpdump, report evidence Keeps manual analysis clean and avoids duplicating EMBA's container-heavy stack
Windows host GUI RE with IDA/Ghidra/Binary Ninja if installed More comfortable UI, less load inside the VM

The Ubuntu autoinstall package list is now intentionally lean. It keeps manual tools that complement EMBA:

binwalk, squashfs-tools, cpio, xz/lzma/zstd, file, binutils
ripgrep, jq, tree
python3, pip, venv
qemu-user-static, qemu-system-arm/mips/x86
gdb-multiarch, strace, ltrace
nmap, tcpdump, iproute2, net-tools

It no longer installs Docker by default. Add Docker to Ubuntu only if Ubuntu becomes your fallback EMBA host or you need containerized tools outside Kali.

What EMBA Installer Actually Touches

I checked upstream installer.sh and the installer modules. In default Docker mode (sudo ./installer.sh -d), EMBA still modifies/prepares the host, but the heavy analyzer stack is Docker-centered.

Host-side work includes:

  • distribution/architecture/RAM/disk checks
  • apt-get update
  • python3-venv
  • external/ and EMBA Python virtual environment
  • Docker CE / Docker Compose plugin if missing
  • small host helpers: jq, shellcheck, unzip, bc, coreutils, ncurses-bin, libnotify-bin, inotify-tools, dbus-x11, git, net-tools, curl, file, python3-pip, Python requests
  • pull/prepare embeddedanalyzer/emba
  • host-side NVD feed setup

Docker/image-centered work includes the large analyzer toolchain modules such as extractors, disassembly/decompilation helpers, unblob/binwalk handling, APK/source/kernel checks, YARA/password/search tooling, CWE checker, system-emulation helpers, CVE tooling, and aggregator/reporting support. In -d mode the installer still calls the module installer functions, but heavy module installers are guarded so they are not broadly installed on the host; they are part of the Docker image/build path.

Implication:

Do not duplicate EMBA's heavy toolchain in Ubuntu by default.
Use Ubuntu only for manual tools or as a no-EMBA fallback.

Safety Rules

Always use EMBA classic Docker mode. Avoid developer mode:

Avoid: -D
Reason: developer mode runs on the host without container protection.

Understand EMBA emulation levels:

Mode Meaning Risk
normal profile scan mostly static triage, but current quick/default profiles enable some QEMU user-mode version checks moderate, Dockerized
-E / QEMULATION=1 QEMU user-mode execution of firmware binaries higher, still Dockerized in classic mode
-Q / FULL_EMULATION=1 QEMU full-system/service emulation highest

VMware network rule:

Install/update/Docker pull: NAT
Quick/default profile scan: NAT is acceptable if no bridged networking and no port forwarding
Any full emulation/service testing: Host-only, NAT disconnected if internet is not needed
Avoid: Bridged

Before -Q, default-scan-emulation.emba, or service testing:

ip -br addr
ip route

You want no bridged adapter and preferably no normal NAT default route.

Case Folder Layout

Use one folder per firmware image. Do not overwrite previous runs.

CASE=fw_case_01
mkdir -p ~/firmware/$CASE/original ~/firmware/$CASE/work ~/emba_logs/$CASE

Copy the firmware:

cp /path/to/firmware.bin ~/firmware/$CASE/original/
FW=~/firmware/$CASE/original/firmware.bin
LOG=~/emba_logs/$CASE

Record facts before scanning:

sha256sum "$FW" | tee "$LOG/sha256.txt"
file "$FW" | tee "$LOG/file.txt"
ls -lh "$FW" | tee "$LOG/size.txt"

Preflight

From the EMBA directory:

cd ~/tools/emba
sudo ./emba -V
sudo ./emba -d 1
ls -1 scan-profiles

Use dependency check meanings:

-d 1: host and container dependency check
-d 2: container-only dependency check

If -d 1 fails, fix setup before scanning. If only a non-critical module dependency fails, document it and decide whether the missing module matters.

If the only surprising line is:

Docker image version - Updates available

but the Docker-compose EMBA image version status line in the same EMBA output is ok and scans start, this is usually a digest mismatch against EMBA's online-check metadata. That phrase is EMBA output text, not a command to type. Run sudo ./emba -U before the assignment if you have time. If it still appears, record it in your setup notes and proceed unless Docker/container checks actually fail.

Walkthrough

Step 1: Quick Scan

Run this first. On your weaker host, keep it conservative:

cd ~/tools/emba
sudo ./emba \
  -l "$LOG/01_quick" \
  -f "$FW" \
  -p ./scan-profiles/quick-scan.emba \
  -P 1 \
  -T 1

What it is for:

  • confirms EMBA can extract/analyze the image
  • gives a first report quickly
  • avoids several long modules
  • gives enough evidence to choose a manual direction

Do not start with full-scan.emba.

Step 2: Read The Quick Results

Open the HTML report if available:

firefox "$LOG/01_quick/html-report/index.html"

Search the text logs:

rg -n "CRITICAL|HIGH|CVE|Exploit|password|passwd|shadow|private key|authorized_keys|dropbear|uhttpd|lighttpd|boa|cgi|command injection|setuid|world writable|strcpy|system\\(|popen\\(" "$LOG/01_quick"

Create a small lead table:

Lead | Evidence file/log | Reachable from network? | Exploit idea | Manual verification command

If a lead has no reachable route/service/config path, it is a lower priority.

Step 3: Default Scan

Run default after quick scan succeeds:

sudo ./emba \
  -l "$LOG/02_default" \
  -f "$FW" \
  -p ./scan-profiles/default-scan.emba \
  -P 1 \
  -T 1

Use -P 2 -T 1 or -P 2 -T 2 only if the VM remains responsive and RAM is stable.

Step 4: Manual Verification Outside EMBA

EMBA tells you where to look. Then you verify manually:

mkdir -p ~/firmware/$CASE/work
if [ -d "$LOG/02_default/firmware" ]; then
  cp -a "$LOG/02_default/firmware" ~/firmware/$CASE/work/extracted
fi
cd ~/firmware/$CASE/work/extracted

Manual triage commands:

find . -maxdepth 4 -type d | rg "/www|/web|/htdocs|/cgi|/etc|/init.d|/rc.d"
find . -type f \( -name "*.cgi" -o -name "*.sh" -o -name "*.php" -o -name "*.lua" \)
rg -n "system\\(|popen\\(|eval|exec|shell_exec|passthru|subprocess|os\\.system|`.*`|\\$\\(|nvram|uci|getenv|QUERY_STRING|REQUEST_METHOD" .
rg -n "password|passwd|shadow|authorized_keys|BEGIN .*PRIVATE KEY|telnet|dropbear|uhttpd|lighttpd|boa" .
find . -perm -4000 -o -perm -2000 2>/dev/null

For a binary lead:

file ./path/to/binary
checksec --file=./path/to/binary 2>/dev/null || true
readelf -h ./path/to/binary
strings -a ./path/to/binary | rg "http|cgi|password|system|popen|strcpy|sprintf|/bin/sh"

Then open the binary in Ghidra/IDA/Binary Ninja if the path looks reachable.

Step 5: Decide Whether Emulation Helps

Do not emulate just because EMBA can. Emulate only when it helps prove one of these:

  • a web route reaches the vulnerable parser
  • an init script starts the service
  • a binary crashes with controlled input
  • a version check proves a vulnerable component is present

Before full-system/service emulation, switch VMware to Host-only.

Most Useful Command Combinations

Health Check

cd ~/tools/emba
sudo ./emba -V
sudo ./emba -d 1
sudo ./emba -d 2

Use when:

  • after install
  • after an EMBA update
  • before a time-boxed assignment

First Pass

sudo ./emba -l "$LOG/01_quick" -f "$FW" -p ./scan-profiles/quick-scan.emba -P 1 -T 1

Use when:

  • first scan of any firmware
  • weak host
  • interview time pressure

Main Evidence Run

sudo ./emba -l "$LOG/02_default" -f "$FW" -p ./scan-profiles/default-scan.emba -P 1 -T 1

Use when:

  • quick scan completed
  • you need a web report, SBOM-style inventory, and prioritized leads

Slightly Faster Main Run

sudo ./emba -l "$LOG/02_default_fast" -f "$FW" -p ./scan-profiles/default-scan.emba -P 2 -T 1

Use only if:

  • the VM has enough RAM
  • the host remains responsive
  • you are not already seeing OOM messages in dmesg

Web/Auth/Secrets Focus

Use this after a baseline run, or when the assignment likely involves web admin panels, CGI, credentials, or startup configs:

sudo ./emba \
  -l "$LOG/03_web_auth_secrets" \
  -f "$FW" \
  -m p \
  -m s35 \
  -m s40 \
  -m s45 \
  -m s50 \
  -m s65 \
  -m s75 \
  -m s80 \
  -m s85 \
  -m s95 \
  -m s100 \
  -m s106 \
  -m s107 \
  -m f50 \
  -W \
  -z \
  -s \
  -P 1 \
  -T 1

Why -m p is included: pre-check/extraction modules prepare the firmware tree. Numeric p modules are not normally selected manually, but -m p asks EMBA to run the pre-checker group.

Binary Risk Focus

Use this when you already identified reachable native binaries:

sudo ./emba \
  -l "$LOG/04_binary_risk" \
  -f "$FW" \
  -m p \
  -m s10 \
  -m s12 \
  -m s13 \
  -m s17 \
  -m f50 \
  -c \
  -W \
  -z \
  -s \
  -P 1 \
  -T 1

Before relying on exact module numbers, confirm your local EMBA module names:

ls modules/S*_*.sh | rg "S10|S12|S13|S15|S16|S17|cwe|ghidra|radare|binary"

Module numbers can move over time. Profiles are safer than handcrafted module lists.

SBOM / Component Inventory

sudo ./emba -l "$LOG/05_sbom" -f "$FW" -p ./scan-profiles/default-sbom.emba -P 1 -T 1

Use when:

  • you need a clean component inventory
  • you want a smaller run focused on packages/versions
  • the reviewer cares about CVE triage, but you still need manual reachability proof

Full Emulation Profile

Only after switching VMware to Host-only:

sudo ./emba -l "$LOG/06_emulation" -f "$FW" -p ./scan-profiles/default-scan-emulation.emba -P 1 -T 1

Use when:

  • a static lead needs service/runtime confirmation
  • you have time to debug emulation failures
  • you already know which service or path you care about

Do not use this as the first scan.

EMBA Emulation: What To Do

Do not jump to emulation first. Use it only after you already have a candidate that benefits from runtime proof.

Good reasons to emulate:

  • confirm that an init script starts a web/service binary
  • identify the runtime IP/ports EMBA can bring up
  • collect Nmap/web checks from an emulated system
  • confirm that a candidate route/service exists at runtime
  • produce extra evidence for a report

Bad reasons to emulate:

  • "maybe it will find a vulnerability"
  • before extraction/static triage works
  • before you know what service/path you care about
  • while VMware is bridged to your LAN

Safe sequence:

1. Run quick/default scan.
2. Pick one candidate.
3. Snapshot VM.
4. Switch VMware to Host-only if doing service/full-system emulation.
5. Run default-scan-emulation.
6. Search emulation logs for IPs, ports, service names, URLs, and QEMU archive paths.
7. Manually test only the candidate surface.

Run:

sudo ./emba \
  -l "$LOG/06_emulation" \
  -f "$FW" \
  -p ./scan-profiles/default-scan-emulation.emba \
  -P 1 \
  -T 1

Then inspect:

rg -n "open port|Nmap scan report|ONLINE|IP address|network|http|https|login|admin|qemu|archive|emulation" "$LOG/06_emulation"
find "$LOG/06_emulation" -maxdepth 4 -type f | rg "L[0-9].*\\.txt|nmap|web|qemu|archive|html-report"
find "$LOG/06_emulation" -iname "*qemu*" -o -iname "*archive*"

If EMBA reports an emulated IP/port on the Host-only network, verify from the VM or Windows host:

nmap -sV -Pn <emulated-ip>
curl -i http://<emulated-ip>/
curl -i http://<emulated-ip>/cgi-bin/<candidate>

If EMBA cannot emulate the firmware, do not burn the whole assignment on it. Extract the rootfs and switch to the Ubuntu no-EMBA workflow:

ubuntu-no-emba-backup-guide.md

For a report, phrase emulation carefully:

EMBA system emulation exposed <service/port>. I then manually verified <route/request> and traced it to <file/function>.

Do not write:

EMBA proved the exploit.

EMBA vs QEMU vs Qiling vs Unicorn vs Ghidra

EMBA is not "better than Qiling/Unicorn" in the abstract. They answer different questions.

Tool What it is Best use
EMBA emulation automated firmware-analysis workflow around QEMU user-mode and full-system/service emulation, with extraction, kernel/rootfs/service setup, logs, Nmap/web checks, and reporting broad firmware triage and "can this firmware expose services under emulation?"
QEMU user-mode runs one Linux userland binary for another architecture, translating syscalls to the host quick binary behavior/version tests with target rootfs libraries
QEMU system-mode emulates a whole machine: CPU, memory, devices, kernel, storage, network booting a firmware/rootfs when you know the kernel/rootfs/device model path
Qiling Python framework built on Unicorn with OS/syscall abstractions, loaders, hooks, and scripting focused single-binary harnesses where you want hooks and repeatable instrumentation
Unicorn CPU emulator framework raw function/basic-block emulation when you provide memory/register/syscall scaffolding
Ghidra emulator p-code emulator tied to Ghidra's decompiler/language semantics stepping a function/basic block, experimenting with state/patches, understanding logic

Practical choice:

Need broad firmware triage/report: EMBA
Need to run one MIPS/ARM Linux binary with firmware libraries: QEMU user-mode
Need whole router service boot: EMBA first, manual QEMU/FirmAE-style work only if needed
Need hookable scripted harness for one binary: Qiling
Need emulate a function/snippet with full control: Unicorn
Need reason about one function in RE UI: Ghidra p-code emulator

EMBA's system emulation is QEMU-based, but it is not "just qemu." EMBA adds extraction context, architecture/rootfs selection, kernel choice, init/service helpers, networking attempts, follow-up checks, logs, reports, and reusable QEMU archives.

Ghidra's emulator is p-code emulation. It is useful for reasoning about code, not for accurately booting Linux services or proving network reachability.

Full Scan Overnight

Only if the assignment allows time and the VM is stable:

sudo ./emba -l "$LOG/99_full" -f "$FW" -p ./scan-profiles/full-scan.emba -P 1 -T 1

Use when:

  • you already have a manually verified primary finding
  • you want additional supporting leads
  • you can leave the VM running

Firmware Diff

Useful if you have two firmware versions:

OLD_FW=~/firmware/$CASE/original/old.bin
NEW_FW=~/firmware/$CASE/original/new.bin
sudo ./emba -l "$LOG/07_diff" -f "$OLD_FW" -o "$NEW_FW" -W -z -s -P 1 -T 1

Use when:

  • a vendor patched something
  • you want to locate changed services/scripts/binaries
  • you want to infer a vulnerability from a patch

Kernel Config Only

If you extracted a kernel config:

sudo ./emba -l "$LOG/08_kernel_config" -k ./kernel.config

Use when:

  • kernel hardening matters
  • you need a quick config assessment

Useful Flags

Flag Use
-l PATH log directory
-f PATH firmware path
-p PROFILE profile from scan-profiles/; safest normal usage
-m MODULE targeted module/group; advanced
-P N max modules in parallel
-T N max threads per module
-W create web report
-z color/format log output
-s short/relative paths
-E user-mode QEMU tests
-Q full-system emulation tests
-c extended binary analysis
-q disable deep extraction
-e PATH exclude path
-o PATH diff against second firmware
-r remove temporary extracted firmware after run
-y overwrite log directory
-U update EMBA and exit
-Y, -Z, -X, -N vendor/device/version/notes metadata; keep values simple

Avoid -r while learning. Keeping extracted files helps manual verification. Use -r only when disk pressure matters and you already copied evidence.

Avoid -y unless you intentionally want to destroy a previous run's logs.

Avoid -U during an active assignment unless EMBA is broken. Snapshot first.

How To Read Results

Start here:

$LOG/<run>/html-report/index.html
$LOG/<run>/emba.log
$LOG/<run>/f50_base_aggregator.txt
$LOG/<run>/csv_logs/
$LOG/<run>/json_logs/

Fast log searches:

rg -n "CRITICAL|HIGH|MEDIUM|CVE|Exploit|EPSS|KEV" "$LOG/02_default"
rg -n "password|passwd|shadow|private key|authorized_keys|root:" "$LOG/02_default"
rg -n "command injection|system\\(|popen\\(|shell|cgi|QUERY_STRING|REQUEST_METHOD" "$LOG/02_default"
rg -n "setuid|world writable|weak permission|dropbear|telnet|uhttpd|lighttpd|boa" "$LOG/02_default"

When EMBA shows a CVE:

  1. Identify the component and version evidence.
  2. Locate the actual file/binary/package in the firmware.
  3. Determine whether the vulnerable feature is built/enabled.
  4. Determine whether an attacker can reach it.
  5. Reproduce impact or explain exactly why reproduction was not possible.

Lead Selection

For a time-boxed firmware analysis, score each lead:

Factor Good sign
Reachability exposed web route, network service, update parser, startup script
Control attacker controls a parameter, file, header, config, archive, or network input
Sink command execution, path traversal, auth bypass, memory corruption, default credential, key leak
Evidence exact file/function/line, EMBA log, manual grep, decompiler screenshot, curl/QEMU/GDB output
Reproducer one command or request demonstrates behavior

Pick one strong reachable finding over five vague CVEs.

Good candidate examples:

CGI route -> unsanitized parameter -> system/popen
web upload/update handler -> tar/path traversal
hardcoded credential/key -> reachable SSH/web/admin path
setuid helper -> attacker-controlled argv/env/file path
network daemon -> unsafe parser -> crash or controlled overwrite
old component CVE -> exact version + vulnerable feature + reachable service

Bad primary candidates:

generic old BusyBox CVE with no reachable applet
private key that is never used
weak function count with no caller/data-flow
kernel CVE with no kernel config/build evidence
EMBA "possible exploit" with no local component proof

AI Usage

Use AI after EMBA has produced concrete artifacts.

Good prompt:

Here are EMBA excerpts for S35/S45/S50/S100 and the relevant files from the firmware.
Build a lead table with: reachable surface, source file, controlled input, dangerous sink, verification command, and confidence.
Do not invent routes or claims not present in the evidence.

Good prompt for a script:

Write a read-only Python script that parses this EMBA log directory and extracts candidate web routes, scripts, binaries, credentials, and CVEs into a CSV. Do not run commands. Do not modify files.

Bad prompt:

Find the vulnerability in this firmware.

The useful AI loop:

EMBA output -> narrow evidence bundle -> AI summary/lead table -> manual verification -> report

EMBA Built-In AI Mode

Treat EMBA's built-in OpenAI mode as optional.

It can help explain scripts and decompiled snippets, but it is not the best first move for an interview assignment. The current default-scan-gpt.emba profile enables GPT_OPTION=1 and also enables QEMULATION=1, so it is not just "static scan plus AI." The OpenAI module sends selected snippets to the OpenAI chat completions API and records the answers in EMBA logs.

Use it only if:

  • uploading firmware snippets is allowed
  • cost/rate limits are acceptable
  • you already have a normal scan and know what you want to ask

Better default:

Run quick/default scan without EMBA AI.
Bundle only relevant logs/files.
Ask AI for a lead table and verification plan.
Manually prove or reject each lead.

Sources