Malwarehouse is a warehouse for your malware. Malwarehouse is a useful command line utility for storing, tagging, storing, and searching for malware. This is intended to help analyst manage their workflow by conducting basic triage and making it easy to look up past samples.
Requirements
- Python 3.9+
Installation
Install with pip (libmagic must be installed on the system first, e.g. apt-get install libmagic1 or brew install libmagic):
pip install . # installs the malwarehouse command (also runnable as python -m malwarehouse)
pip install .[yara] # with optional YARA rule matching
pip install -e .[dev] # editable install with test tooling, for development
For development, uv sync --extra dev builds .venv from the committed uv.lock, the same versions CI tests;
uv run pytest then runs the tests (see uv).
Configuration
malwarehouse init writes a starter malwarehouse.cfg to your user config directory (~/.config/malwarehouse/ on
Linux, ~/Library/Application Support/malwarehouse/ on macOS). With it, samples and the index live in your user
data directory, and malwarehouse works from any directory. Then create the database with malwarehouse init-db.
Malwarehouse uses the first configuration it finds:
--config PATH(anywhere on the command line)- the
MALWAREHOUSE_CONFIGenvironment variable malwarehouse.cfgin your user config directory./malwarehouse.cfgin the directory you run it from
basedir, yararules and the SQLite database) are relative to the file's own
directory. The whole file is checked when a command starts, so a missing setting or a mistyped plugin: On/Off
switch (any case, or yes/no) is reported straight away. malwarehouse init --config PATH writes a starter config
somewhere else, keeping the data next to it; --force replaces an existing file.
Libraries
- SQLAlchemy - Database ORM
- Typer - Command line interface
- python-magic - File type identification (requires libmagic)
- ppdeep - Fuzzy hashing
- vt-py (optional) - VirusTotal API v3 client for the virustotal plugin
- pefile (optional) - PE parsing for the pe_analyzer plugin
- yara-python (optional) - YARA rule matching
Authors
Setup - Databases
Malwarehouse keeps its index in a SQLite database file, set with[database] uri in malwarehouse.cfg
(e.g. sqlite:///data/malwarehouse.db, relative to the config file, or sqlite:////absolute/path/malwarehouse.db).
Other database servers are not supported.
For initial DB setup, run malwarehouse init-db. It creates the file and its directory, is safe to re-run, exits 1
on failure, and shows the migrations and SQL it runs with -v. malwarehouse-setup-db, its older name, still works.
Upgrading
The schema is managed with Alembic migrations. After upgrading malwarehouse, runmalwarehouse init-db again: it upgrades the existing database in place and keeps its samples. Until then,
load, find and recent stop with an error asking you to run it. A database created before migrations were
added is recognised and upgraded the same way. The upgrade runs as one SQLite transaction, so a failure leaves the
database as it was; copying the database file first is still a good idea.
Usage
Every command has --help (or -h). Add -v/--verbose for progress output or -q/--quiet for errors only,
anywhere on the line. Exit status is 0 on success, 1 on an error and 2 for bad arguments.
Basic Commands
# Display help
malwarehouse --help
Create the database, or upgrade it after upgrading malwarehouse
malwarehouse init-db
Display the 5 most recent samples (default)
malwarehouse recent
Display the 10 most recent samples
malwarehouse recent 10
Find a sample by name, md5, or sha256
malwarehouse find <hash_or_name>
Load a new sample for analysis
malwarehouse load <file_path>
Load a sample with metadata
malwarehouse load <file_path> --source="malware_bazaar" --notes="Suspicious dropper" --tags="trojan,dropper"
Delete a sample (not yet implemented)
malwarehouse delete <hash_or_name>
Each piece of content is stored once. Loading a file whose SHA256 is already in the warehouse merges into that
sample: its filename is added to the sample's names (so find works with any of them), tags, sources and notes are
combined without duplicates (each source or note is kept whole, whatever it contains), the "last seen" time is updated
and the analysis report is regenerated. Loads of the same file from several processes at once are merged one
after another, so none of their names, tags, sources or notes are lost. recent
lists samples by when they were last loaded; times are stored and shown in UTC.
Output and exit status
Results (sample summaries and the load confirmation) go to stdout; warnings and errors go to stderr.
Add -v/--verbose for progress and debug output, or -q/--quiet to show errors only. Malwarehouse exits
with status 0 on success and 1 on any error, so it can be used in scripts.
Examples
# Load a sample from a file
malwarehouse load /path/to/malware.exe
Load with additional context
malwarehouse load /path/to/malware.exe --source="email_attachment" --notes="Phishing campaign 2024-01" --tags="phishing,ransomware"
Find a specific sample
malwarehouse find d41d8cd98f00b204e9800998ecf8427e
View recent 20 samples
malwarehouse recent 20
Plugins
The VirusTotal plugin looks every loaded sample up through VirusTotal's API v3. Install it withpip install 'malwarehouse[virustotal]', set plugin: On under [virustotal] in malwarehouse.cfg, and provide your
API key in the MALWAREHOUSE_VT_APIKEY environment variable (or as apikey, though keeping it out of the config file
is safer). Each sample's report directory gets virustotal/summary.json (detections, first seen, threat label) and,
when VirusTotal knows the file, the full virustotal_details.json. A file VirusTotal has never seen is reported as
not_found, not as an error.
Samples are never uploaded unless you set submit_samples: On under [virustotal]: an upload shares the file
with VirusTotal's customers. With it on, only files VirusTotal does not already know are uploaded, under their SHA256
as the filename (no original name or local path).
The pe_analyzer plugin parses Windows executables with pefile: install it
with pip install 'malwarehouse[pe]' and set plugin: On under [pe_analyzer]. For each PE sample it writes
pe_analyzer.rpt and pe_analyzer.json to the report directory: type and machine, compile time, subsystem, entry
point, sections with their entropy (high entropy suggests packing), imports and the imphash, exports, the overlay
size (data appended after the sections, not counting the signature's certificate) and whether an Authenticode
signature is present, with its certificate size (the signature is not verified). Other files are simply recorded as not PE. Samples are only
parsed, never run; samples larger than max_mb (default 256) are skipped.
Plugins can come from separately installed packages: a package that declares a malwarehouse.plugins entry point
is found automatically and runs on every load while plugin: On is set in its config section.
examples/example_plugin/ is a complete, minimal example (pip install examples/example_plugin, then add
[example] with plugin: On). malwarehouse plugins lists the installed plugins, whether each is enabled, and any
that failed to load; a plugin that fails to import is skipped with a warning and never stops malwarehouse.
License
See LICENSE for more informationThanks
- Jonathan Hencinski
- Chris St.Myers
- @Xen0ph0n