Skip to content

Repository files navigation

Masstin

Masstin logo

Lateral movement tracker for anything.
One timeline from every log you have. One statistical hunt over it. No SIEM, no plugins, one binary.

Release crates.io License: AGPL v3 Platform

masstin parse-windows over a folder of EVTX samples: banner, discovery, per-folder breakdown and the 14-column CSV
parse-windows over 293 EVTX samples from twelve providers: discovery, per-folder breakdown, duplicates removed, and the 14-column timeline at the end.

What it does

An incident leaves logins in a dozen places: Security.evtx on fifty Windows hosts, wtmp and auth.log on the Linux side, UAL databases nobody remembers, EDR exports, a VPN concentrator. Masstin reads all of them and answers one question: who logged in where, with what, and when.

  • Parse anything into one timeline. Forensic images (E01, VMDK, dd) with VSS recovery and EVTX carving, KAPE / Velociraptor / UAC / Cortex triages, loose EVTX, Linux logs including binary journald, Winlogbeat JSON, Cortex XDR, and any text or JSON log through a YAML rule. Every source lands in the same 14-column CSV. Parsing →
  • Hunt with statistics, not thresholds. graph-hunt splits the timeline at a cutoff, measures every window connection against the network's own baseline and reports what survives a false-discovery-rate test. The only number you choose is the FDR. It explains each finding in words, classes it the way the Hopper paper does, reconstructs chains from a seed and writes an analyst report. graph-hunt →
  • See it as a graph. Load the timeline into Neo4j or Memgraph in seconds, with IP ↔ hostname unification, session pairing and a Cypher catalogue for temporal path reconstruction. Graph databases →
Memgraph Lab on a masstin timeline: the hour of the intrusion, then the temporal path query between the attacker's IP and the workstation
The same timeline in Memgraph Lab: every login of the hour the attacker came in, then one Cypher query from the catalogue returns the chronologically valid path from the attacker's IP to the workstation it reached. DFIR Madness "Szechuan sauce" case.

Quick start

Download the binary for your platform from the Releases page, or cargo install masstin. No runtime dependencies.

# 1. Everything under the evidence folder (images, zips, triages, loose files) -> one timeline
masstin -a parse-massive -d /evidence/case-2026-03 -o timeline.csv

# 2. Hunt: what happened after the cutoff that this network had never done before?
masstin -a graph-hunt-csv -f timeline.csv --investigation-from "2026-03-15 00:00:00" \
        --report hunt.md -o hunt.csv

# 3. Known-bad host or account? Reconstruct the chain from it
masstin -a graph-hunt-csv -f timeline.csv --investigation-from "2026-03-15 00:00:00" \
        --seed 10.10.1.50 --report hunt.md -o hunt.csv

# 4. Optional: load the graph and look at it
masstin -a load-memgraph -f timeline.csv --database bolt://localhost:7687 --ungrouped

macOS first run: if Gatekeeper blocks the binary, run xattr -d com.apple.quarantine masstin-* once.

What it reads

Source What masstin extracts
Windows EVTX 33+ Event IDs across 12 providers: Security (4624/4625/4634/4647/4648/4768/4769/4771/4776/4778/4779/5140…), Terminal Services, RDP client and core, SMB server and client, WinRM, WMI-Activity, Sysmon Event 3, Scheduled Tasks. Archived and renamed EVTX are routed by provider name.
Windows beyond EVTX UAL (User Access Logging) ESE databases, MountPoints2 from NTUSER.DAT, Volume Shadow Copies, EVTX chunks carved from unallocated space.
Forensic images E01 (multi-segment), VMDK (flat, sparse, streamOptimized), dd/raw, mounted volumes, images packed inside zips. OS detected per partition; NTFS and ext4 both walked. BitLocker detected and reported.
Linux auth.log, secure, messages, wtmp/btmp/lastlog, audit.log, binary journald. Session ends paired to their login, syslog times converted to UTC, OpenSSH 9.8 sshd-session understood.
Triage packages KAPE, Velociraptor offline collector, UAC, Cortex XDR, plain zips and tarballs, nested in each other.
Feeds Winlogbeat JSON, Cortex XDR network connections and forensic EVTX, Mordor / OTRF Security-Datasets.
Anything else parse-custom with a YAML rule: csv, regex, key=value and JSON extractors. Ships with rules for Palo Alto, Cisco, Fortinet, OpenVPN, Squid and Mordor. Custom parsers →

The full artifact list with the fields taken from each event is in ARTIFACTS.md. The 14 columns are described in docs/csv-format.md.

How graph-hunt decides

A connection is one origin logging in to one destination with one account on one day. Connections that already happened on another baseline day are habitual and never reported. For the new ones, ten facts are measured against the baseline (first-time destination, account the origin never used, account that belongs to another machine, failed sweeps, pre-auth touches, logon type, graph centrality, community crossing, chain speed, Sigma hits from Hayabusa / Chainsaw when given) and combined into one empirical p-value per origin-day. Benjamini-Hochberg across all of them controls the false discovery rate you asked for.

graph-hunt-csv on the Szechuan timeline: the run, then the ranked connections with their Hopper class and their place in the chain from the seed
graph-hunt-csv on the Szechuan timeline with the attacker's IP as seed: what the engine measured, then the ranked connections. Each row says why it is there (a credential switch with a new access, a causal path) and where it sits in the chain.

Measured on a real 45-host incident and on the public Los Alamos (LANL) authentication set:

45-host incident (10.5 M rows) LANL (21.3 M rows)
Significant connections at FDR 5 % 65, all the attacker's 204, 185 red team
Precision of the first 100 rows 100 % 99 %
Incident-free period – 0 significant

The design, the assumptions and the limits are in docs/graph-hunt-statistics.md. The hunt runs straight from the CSV (graph-hunt-csv), on Memgraph (graph-hunt) or on Neo4j (graph-hunt-neo4j), with no server-side plugin.

Documentation

Topic Where
Every parse-* action, noise filtering, triage detection, carving, merge docs/parsing.md
graph-hunt: options, output columns, report, seeds, Sigma corroboration, detection quality docs/graph-hunt.md
Statistics behind the hunt docs/graph-hunt-statistics.md
Loading into Neo4j / Memgraph, visualisation, query catalogue docs/graph-databases.md · Cypher queries
Custom parsers (YAML rules) docs/custom-parsers.md
Every command-line option docs/cli-options.md
Artifacts and fields ARTIFACTS.md
Articles, in English and Spanish weinvestigateanything.com

masstin --help lists every action and flag.

Roadmap

  • Loaders unify IP and hostname with the same binomial test graph-hunt uses (today: frequency map, see docs/graph-databases.md)
  • VHD/VHDX images; macOS (parse-mac, APFS images)
  • EVTX carving Tier 3 (template matching) and unallocated-only scan
  • EVTX header tampering detection; Linux log carving
  • More custom-parser rules (Checkpoint, ZScaler, Cloudflare Access, Juniper, SonicWall); conditional map and per-rule --validate
  • Official Velociraptor plugin

About

Masstin is the Rust rewrite of Sabonis, named after the Mastín Leonés, the guardian dog of the mountains of León. It builds on stable Rust with a plain cargo build --release. If you use it in research, CITATION.cff has the reference.

Licensed under the GNU Affero General Public License v3.0 (LICENSE).

Toño Díaz (@jupyterj0nes) · LinkedIn · weinvestigateanything.com

Releases

Packages

Used by

Contributors

Languages