National Cyber Warfare Foundation (NCWF)

Inside moria: recursive firmware identification and extraction without root


0 user ratings
2026-09-28 23:28:53
milo
Red Team (CNA)
"Inside

moria is a self-contained C++ utility that identifies filesystems, kernels, and archives embedded in IoT firmware images and unpacks them in-process for authorized analysis.








Toolnmatt0/moria — IoT firmware identification, extraction, and carving tool with JSON output
CategoryFirmware analysis / binary structure identification
Primary UseIdentifying and recursively unpacking filesystems, kernels, and archives inside IoT firmware images during authorized security research, with -e extraction and -j JSON output for automation
Safe UseIntended for authorized firmware assessments, lab research on images you own or are licensed to analyze, and defensive vulnerability research; it contains no attack functionality and runs without root privileges
Telemetry Notemoria is purely offline and local — it contacts nothing, and its outputs (manifest.json, .extracted/ trees) appear only on the analyst's own filesystem

Firmware analysis usually begins with the least glamorous problem in the discipline: figuring out what is actually inside the blob you downloaded. moria, a self-contained C++20 tool from nmatt0, tackles exactly that. Given a firmware or IoT image, it identifies embedded structures — filesystems, kernels, bootloaders, archives, packed executables, even cryptographic keys — and reports each finding with a byte offset, a type, and a confidence score. The design goal is identification-first: you get a readable findings tree by default, and clean JSON with -j when you want scripts or LLM agents driving the analysis instead of a human.


The headline capability is breadth of extraction. moria unpacks an unusually wide set of filesystems entirely in-process, without shelling out to external tools and without sudo: SquashFS, ext2/3/4, F2FS, XFS, btrfs, HFS+, NTFS, EROFS, JFFS2, UBIFS, plus FAT, exFAT, romfs, YAFFS2, and cramfs. On top of that it handles archives and container images (ZIP, tar, cpio, ISO 9660, Android sparse and boot images), kernel wrappers like U-Boot uImage and FIT, standalone gzip/xz/zstd/lz4 streams, and even a vendor firmware package format (RAE Systems/Honeywell RFP, with per-section LZARI decompression). For an analyst who normally chains binwalk, unsquashfs, mount, and a handful of vendor scripts, that consolidation into one binary is the whole pitch.


Recursion is the default behavior, and this is where moria earns its keep on real IoT images, which are rarely a single flat container. A gzip-wrapped SquashFS sitting inside a UBI volume unpacks all the way down automatically, and UBI images are rebuilt volume by volume. Extraction with -e writes results under .extracted/, one directory per region named 0x-/, accompanied by a manifest.json mapping offsets to paths. That manifest is a small but thoughtful detail: it turns the extraction output into something a downstream pipeline can correlate back to the original image precisely, rather than guessing from directory names.


The engineering posture deserves attention from anyone who points parsers at untrusted binaries. The README states that every read is bounds-checked, every write goes through openat with O_NOFOLLOW (closing off path-traversal and symlink-escape attacks from malicious images), and decompression is bounded against compression bombs. Extraction guards — --depth, --max-files, --max-bytes, and a decompression-ratio cap — limit hostile input, and notably a tripped guard stops only that branch while still returning everything recovered up to that point. Determinism is also explicit: the same input always produces the same output because conflict resolution contains no random tie-break, which matters when you want reproducible analysis pipelines or diffable results across firmware versions.


A distinctive capability is the handling of packed executables. moria detects UPX-packed binaries across ELF, PE, and Mach-O and across architectures, using the checksum-verified PackHeader trailer to recover format, method, and size information. More interesting for adversaries-in-firmware work, it also flags stubs whose header was zeroed or otherwise altered specifically to defeat the standard upx -d unpacking route — a common cheap anti-analysis trick in embedded malware and grey-market firmware. Being able to flag that condition during triage, before you waste time on a stubborn unpack, is a genuine workflow accelerant.


Signature architecture follows a three-tier layout that reflects how the tool is meant to be used. The signatures/ directory holds the hand-written core — firmware filesystems, containers, kernels, and common formats — each with structural validation rather than bare magic-byte matching. signatures-firmware/ carries vendor firmware-container magics and loads by default. signatures-generated/ holds roughly 2.5k general file-type magics derived from file(1)'s magic database and loads only when you pass --broad, keeping the default scan fast and firmware-focused. Extending the tool is deliberately low-friction: drop a .toml file into signatures/, and only reach for a small C++ validator when the declarative layer cannot express something like CRCs or cross-block pointers.


The binary itself is built to be portable in a way that matters for incident-response style work. All signature sets are embedded at build time, so a compiled moria runs anywhere with nothing installed alongside it — copying the binary into ~/.local/bin is sufficient. If you are iterating on a new .toml signature and do not want to rebuild, --sigs DIR or the $MORIA_SIGDIR environment variable points the tool at external signatures instead. Building from source requires cmake, a C++20 compiler, and the zlib, liblzma, lz4, and zstd development libraries; a typical build looks like cmake -S . -B build -DCMAKE_BUILD_TYPE=Release followed by cmake --build build -j. A -DMORIA_OPTIONAL_CODECS=ON configure flag produces a minimal identify-only build when a codec library is missing.


Day-to-day usage maps cleanly onto an analyst's triage sequence. moria produces the human-readable findings tree; moria -j yields JSON for tooling; -e extracts, -c carves raw byte ranges into .carved/ without parsing, and -E runs an entropy pass that flags unidentified or possibly-encrypted regions — a useful signal for encrypted vendor payloads or deliberately obfuscated sections. --list enumerates tar/cpio/zip members without extraction, which is the right call when you only need an inventory. Directing moria at a directory instead of a file produces a type summary plus notable files, making it viable for batch triage of a dumped firmware corpus.


The scope boundaries are clearly drawn, which is refreshing in a tool that could easily sprawl. moria does structural identification, extraction, and carving — full stop. Secret and credential scanning, SBOM generation, CVE matching, and license analysis live in a sibling project, mithril, by the same author. That separation keeps moria fast and auditable while inviting composition: moria tells you what is in the image and lays it out on disk, and downstream tooling reasons about the contents.


Licensing is MIT, with a transparent note about the few on-disk formats handled by clean reimplementations rather than copied code: the UCL/NRV2B decompressor and CTO unfilters from UPX/UCL, the metadata-commit and CTZ skip-list layout of littlefs, and the page/object layout of SPIFFS. All were written independently against moria's own I/O layer, with the algorithm licenses acknowledged. At around 342 stars on GitHub, the project is modest in visibility but unusually rigorous in its documentation of safety properties and internal design.


Where does this fit in an authorized workflow? For consultants assessing vendor firmware under contract, for product security teams auditing their own supply chain, and for researchers working with lawfully obtained images in a lab, moria replaces the fragile binwalk-plus-mount dance with a single non-root binary whose outputs — offsets, types, confidence, manifest.json — are machine-consumable end to end. It is a tooling piece, not an attack piece: nothing in it touches a network, and its telemetry footprint is zero. The value is purely in making the first hour of firmware analysis deterministic, safe against hostile inputs, and scriptable, which is exactly the hour that most determines whether the rest of the assessment goes anywhere.



Official project repository for nmatt0/moria.

Download Tool

Educational analysis for authorized security professionals. Use only in controlled, authorized environments.






Source: OffensiveSec
Source Link: https://www.offsecblog.com/2026/09/inside-moria-recursive-firmware.html


Comments
new comment
Nobody has commented yet. Will you be the first?
 
Forum
Red Team (CNA)



Copyright 2012 through 2026 - National Cyber Warfare Foundation - All rights reserved worldwide.