forensic-catalog 0.1.0

Static indicator tables for forensic analysis: suspicious ports, LOLBins, persistence paths, execution artifacts, anti-forensics indicators, and more
Documentation
  • Coverage
  • 66.09%
    267 out of 404 items documented2 out of 56 items with examples
  • Size
  • Source code size: 454.25 kB This is the summed size of all the files inside the crates.io package for this release.
  • Documentation size: 18.4 MB This is the summed size of all files generated by rustdoc for all configured targets
  • Ø build duration
  • this release: 54s Average build duration of successful builds.
  • all releases: 54s Average build duration of successful builds in releases after 2024-10-23.
  • Links
  • Homepage
  • SecurityRonin/forensicnomicon
    0 0 0
  • crates.io
  • Dependencies
  • Versions
  • Owners
  • h4x0r

crates.io docs.rs CI license rust

forensic-catalog

Forensic knowledge as code — zero-dependency, std-only, embeds in any Rust binary.

Quick start

[dependencies]
forensic-catalog = "0.1"
use forensic_catalog::ports::is_suspicious_port;
use forensic_catalog::catalog::{CATALOG, TriagePriority};

// Instant port check — no allocations
assert!(is_suspicious_port(4444)); // Metasploit default

// Pull every Critical-priority artifact, sorted for triage
let critical: Vec<_> = CATALOG
    .for_triage()
    .into_iter()
    .filter(|d| d.triage_priority == TriagePriority::Critical)
    .collect();

What's inside

Module Covers Key function / constant
ports C2 ports, Cobalt Strike, Tor, WinRM, RAT defaults is_suspicious_port(port)
lolbins Windows + Linux LOLBins WINDOWS_LOLBINS, LINUX_LOLBINS
processes Known malware process names MALWARE_PROCESS_NAMES
commands Reverse shells, PowerShell abuse, download cradles pattern slices
paths Suspicious filesystem paths path slices
persistence Windows Run keys, Linux cron/init, macOS LaunchAgents WINDOWS_RUN_KEYS, LINUX_PERSISTENCE_PATHS, MACOS_PERSISTENCE_PATHS
catalog 150+ ArtifactDescriptors with MITRE ATT&CK, triage priority, decode logic CATALOG
antiforensics Anti-forensics indicator paths and patterns indicator slices
encryption FDE artifact paths, credential store locations path slices
remote_access Remote access tool indicators (RMM, RAT, VPN) indicator slices
third_party OneDrive, PuTTY, and other third-party app artifact paths path slices
pca Windows Program Compatibility Assistant artifacts path / key constants
references Queryable authoritative source map for each public module module_references(name)

The ForensicCatalog API

The catalog module is the power feature. Every artifact descriptor is a const-constructible ArtifactDescriptor — MITRE ATT&CK tags, triage priority, retention period, cross-correlation links, and embedded decode logic all in one static struct. No I/O, no allocation until you query.

Query by MITRE technique

use forensic_catalog::catalog::CATALOG;

// All artifacts relevant to process injection
let artifacts = CATALOG.by_mitre("T1055");
for d in &artifacts {
    println!("{}{}", d.id, d.meaning);
}

Triage-ordered collection list

let ordered = CATALOG.for_triage(); // Critical → High → Medium → Low
for d in ordered.iter().take(10) {
    println!("[{:?}] {}{}", d.triage_priority, d.id, d.name);
}

Keyword search

let hits = CATALOG.filter_by_keyword("prefetch");
// matches on name or meaning, case-insensitive

Structured filter

use forensic_catalog::catalog::{ArtifactQuery, DataScope, HiveTarget};

let hits = CATALOG.filter(&ArtifactQuery {
    scope: Some(DataScope::User),
    hive: Some(HiveTarget::NtUser),
    ..Default::default()
});

Decode raw artifact data

use forensic_catalog::catalog::CATALOG;

let descriptor = CATALOG.by_id("userassist").unwrap();
let record = CATALOG.decode(descriptor, value_name, raw_bytes)?;
// record.fields — decoded field name/value pairs
// record.timestamp — ISO 8601 UTC string, if present
// record.mitre_techniques — inherited from the descriptor
Field Type Description
id &'static str Machine-readable identifier (e.g. "userassist")
name &'static str Human-readable display name
artifact_type ArtifactType RegistryKey, RegistryValue, File, Directory, EventLog, MemoryRegion
hive Option<HiveTarget> Registry hive, or None for file/memory artifacts
key_path &'static str Path relative to hive root
scope DataScope User, System, Network, Mixed
os_scope OsScope Win10Plus, Linux, LinuxSystemd, etc.
decoder Decoder Identity, Rot13Name, FiletimeAt, BinaryRecord, Utf16Le, …
meaning &'static str Forensic significance
mitre_techniques &'static [&'static str] ATT&CK technique IDs
fields &'static [FieldSchema] Decoded output field schema
retention Option<&'static str> How long artifact typically persists
triage_priority TriagePriority Critical / High / Medium / Low
related_artifacts &'static [&'static str] Cross-correlation artifact IDs

Design philosophy

  • Zero dependenciesCargo.toml has no [dependencies]. No transitive supply-chain risk.
  • No I/O — every function operates on values passed in. Reading files, registry, or memory is the caller's job.
  • const/static-friendlyArtifactDescriptor and all its enums are constructible in const context. Extend the catalog at compile time.
  • Test-driven — every indicator table has positive and negative test cases. Run cargo test to verify coverage.
  • Additive — each module is independent. Pull in only what you need.

Source provenance

Module-level research provenance is available through forensic_catalog::references.

use forensic_catalog::references::module_references;

let refs = module_references("persistence").unwrap();
assert!(refs.urls.iter().any(|url| url.contains("attack.mitre.org")));

Artifact-level provenance remains embedded directly in the catalog:

use forensic_catalog::catalog::CATALOG;

let desc = CATALOG.by_id("userassist_exe").unwrap();
assert!(!desc.sources.is_empty());

Blog Archive Ingestion

The repo also includes a dependency-free blog scraper for building a local DFIR research corpus from archive pages, sitemaps, or Blogger feeds:

python3 scripts/scrape_blog.py \
  --url https://windowsir.blogspot.com \
  --output research/windowsir

Used by