Repository navigation
Increase component identification rate
EMBA is designed as a complete firmware and binary analysis environment. This also means one of the goals is to answer one simple question: "Which software components are running on this embedded device, and are they vulnerable?" To answer this question we need to generate something that is called SBOM which stands for software bill of materials. Building such a SBOM for firmware could get tricky. There are no apt meta-files on a router, no python pip in a doorbell, and often no package managers at all. Everything has to be pieced together from fragments: package archives, lock files, in-band version strings, and the behavior of the binaries themselves.
This article explains the multi-layered detection strategy EMBA uses to assemble an as-complete-as-possible software inventory. It shows where the current detection gaps are, and how you can extend the detection arsenal with hand-crafted version identifiers and help keep EMBA competitive.
EMBA deliberately combines several independent detection channels. No single source is complete, but together they cover most of what you find in real-world firmware.
When a device does ship a package manager, it is the most reliable source available. EMBA ships dedicated submodules for the formats it encounters in the field, all orchestrated by the module S08_main_package_sbom.sh:
-
Debian/Ubuntu –
dpkgstatus databases and packaged.debarchives -
OpenWRT –
opkgmetadata and packaged.ipkarchives -
RPM-based – package management databases and
.rpmarchives -
Python –
pip,requirements.txt,Pipfile.lock,poetry.lock -
Node.js –
package-lock.json,yarn.lock -
Ruby –
.gemarchives -
Rust –
Cargo.lock - Java – JAR/WAR/class archives
-
PHP –
composer.lock - Perl – CPAN/META files
-
C/C++ –
conanfile.txt - BSD packages, Windows executable metadata, and vendor-specific XML (e.g. SINAMICS)
These submodules run in parallel and write their results into a shared SBOM component store, so every entry is deduplicated across different detection methods.
Even without a running package manager, firmware images frequently contain the package files themselves: .deb, .rpm, .ipk and similar archives that were baked in at build time. EMBA extracts and analyzes them directly, recovering vendor, product and version without relying on an installed database.
For everything that lacks package metadata, EMBA falls back to a hand-crafted arsenal of more than 500 (currently around 530) version identifiers. This is the heart of the detection capability for typical firmware.
Every component has a dedicated JSON configuration under config/bin_version_identifiers/ with one or multiple detection rules. A typical entry (bash.json) looks like this:
{
"identifier": "bash",
"parsing_mode": [
"normal"
],
"licenses": [
"GPL-3.0-only"
],
"grep_commands": [
"[Bb]ash,\\ version\\ [0-9](\\.[0-9]+)+?",
"[Bb]ash.*version\\ [0-9](\\.[0-9]+)+?"
],
"vendor_names": [
"gnu"
],
"product_names": [
"bash"
],
"version_extraction": [
"sed -r 's/[Bb]ash,\\ version\\ ([0-9](\\.[0-9]+)+?).*/:gnu:bash:\\1/'",
"sed -r 's/[Bb]ash.*version\\ ([0-9](\\.[0-9]+)+?).*/:gnu:bash:\\1/'"
],
"affected_paths": [
"NA"
]
}Each config carries:
-
grep_commands– regular expressions matched against the raw strings of every binary -
version_extraction– asedcommand that transforms a matched string into the canonical:vendor:product:versionrecord that feeds the SBOM -
vendor_names/product_names– the normalized identity used for vulnerability matching -
licenses– SPDX license identifiers for SBOM / license-compliance tooling -
parsing_mode–normal, but alsostrict,zgrep,multi_grepandno_staticfor special cases (let’s focus on thenormalmode for now)
During the module run of S09_firmware_base_version_check.sh, EMBA creates an archive of all printable strings from every binary. The archive is stored in the form strings_<MD5>_<name>.txt in the log sub-directory s09_firmware_base_version_check/strings_bins/. Afterwards, she tests each identifier regex against the resulting string files with grep -a -E. Identified components are stored in CSV and json log that further supports the SBOM generation.
It is also possible to combine multiple grep commands like <IDENTIFIER1>AND<IDENTIFIER2>AND<IDENTIFIER3>. This mechanism allows to detect very weak identifiers like a version 1.2.3 in a binary that also includes some further identifiers. Very handy mechanism.
Static strings only tell half the story. EMBA therefore verifies and extends its inventory dynamically:
- User-mode emulation – selected binaries are executed in a QEMU user-mode environment, and version identifiers can be tested against the live output of the running binary.
- Full system emulation boots the entire firmware, letting EMBA observe live services, their banners, and package behavior that no static pass can see.
We will extend this section later on :)
All sources are merged into one consolidated software inventory and emitted as a standard CycloneDX SBOM via the F15_cyclonedx_sbom.sh module. This final SBOM is covering component names, versions, vendor/maintainer, licenses, CPE identifiers, PURL identifiers and file hashes. This SBOM can be further analysed and maintained with other 3rd party tools like Dependency-Track. With the module Q20_dependency_track_connector.sh EMBA is able to automatically upload the final SBOM directly to dependency-track. Additionally, EMBA's CVE matching and the internal vulnerability aggregation allow further vulnerability handling mechanisms to trigger. So, the quality of the SBOM directly determines the quality of every vulnerability report that follows.
Here is the uncomfortable truth: more and more firmware includes a package manager — but the majority does not. For all those devices, EMBA depends entirely on the version-identifier arsenal. These identifiers are hand-crafted, and every component needs a dedicated configuration for detection. Apache, OpenSSH, BusyBox, dropbear, lighttpd — one JSON per project.
This is exactly the area where every EMBA user can make a measurable difference. Without community contributions, the detection rate slowly loses accuracy: new versions change their version strings, new projects appear on the market, and components silently fall out of our inventory. This results in vulnerabilities that EMBA is not able to detect as the SBOM is getting more and more incomplete.
The integration workflow is deliberately lightweight. Pull request #2131 is a good showcase of updated, improved and new configurations.
-
Run EMBA with the SBOM scanning profile (
default-sbom.emba). -
Inspect the generated strings in
emba_logs/s09_firmware_base_version_check/strings_bins/— every binary of your firmware is dumped there asstrings_<MD5>_<name>.txt. -
Find the version identifier of your component. Use
cat/grepon the relevant strings file, then verify your regex manually:and afterwards against the complete strings directory to make sure the pattern stays stable across components and no false positives are triggered:grep -a -E "YOUR IDENTIFIER" <strings_file>
grep -a -E "YOUR IDENTIFIER" emba_logs/s09_firmware_base_version_check/strings_bins/*
-
Tune it into a stable identifier — avoid overly broad patterns; prefer the most specific string that reliably appears across versions. Hint: use the start pattern
^and end pattern$ -
Write the
sedcommand that transforms a match into:vendor:product:version. You will find plenty of examples in the existing configs inconfig/bin_version_identifiers/. (Yes, grep pattern plussedextraction is a bit of double work — but for now we have to deal with it. It is already on our Todo list) - If the component is already covered but it is not detected you can just add the identifier to an existing config or create a new JSON config. I recommend to just copy one of the existing configs as a template.
- Re-run your EMBA scan and enjoy the new results. If something goes wrong, re-check the strings and a manual detection run, check the Docker output, and re-test it manually.
A rule is only as good as its test evidence. To keep the project reproducible and reviewable, please collect the matching context from your binary. For doing this your already generated rule needs the following adoptions to work manually on your command line interface:
- remove line start markers
^ - remvoe line end markers
$ - remove double quoting from the json grep command
\\->\
Afterwards check you modified IDENTIFIER against the binary:
grep -A10 -B10 -a -o -E ".{0,300}IDENTIFIER.{0,300}" <your-binary>As an alternative you can also share the complete binary/firmware with us.
IMPORTANT: Submit your PR with the created testing data (or your binaries) attached for reproducibility — just add it to the PR as a zip file, or contact the maintainers directly.
With that, you are now part of EMBA as you have improved the detection rate of EMBA. This allows EMBA to get better, together.
EMBA - firmware security scanning at its best
Sponsor EMBA and EMBArk:
The EMBA environment is free and open source!
We put a lot of time and energy into these tools and related research to make this happen. It's now possible for you to contribute as a sponsor!
If you like EMBA you have the chance to support future development by becoming a Sponsor
Thank You ❤️ Get a Sponsor
You can also buy us some beer here ❤️ Buy me a coffee
To show your love for EMBA with nice shirts or other merch you can check our Spreadshop
EMBA - firmware security scanning at its best
- Home
- The EMBA book
- Feature overview
- Installation
- Usage
- Development
- Sponsoring EMBA
- EMBA Merchandise
- FAQ
- EMBArk enterprise environment