Profile
Back to NewsBack
GitHub Trending 6 min
Reader Mode
sroberts/malwarehouse: A warehouse for your malware

sroberts/malwarehouse: A warehouse for your malware

7 hours ago

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:

  1. --config PATH (anywhere on the command line)
  2. the MALWAREHOUSE_CONFIG environment variable
  3. malwarehouse.cfg in your user config directory
  4. ./malwarehouse.cfg in the directory you run it from
Relative paths in the file (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, run malwarehouse 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 with pip 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 information

Thanks

  • Jonathan Hencinski
  • Chris St.Myers
  • @Xen0ph0n
Chat with me