threat hunting

Hunting EVTX with Chainsaw

Perform rapid Sigma and keyword hunting across Windows event logs with Chainsaw.

chainsawdetectiondfirevtxshimcachesigmathreat-huntingwindows-event-logs
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

Overview

Chainsaw is a fast, Rust-based forensic artifact search and hunting tool from WithSecure Labs. It provides first-response capability to rapidly identify threats within Windows Event Logs (.evtx) and other artifacts. Chainsaw can hunt with the full SigmaHQ rule corpus (translating Sigma to its internal Tau engine), run its own built-in detection rules, perform high-speed keyword/regex search across logs, and analyse specialized artifacts such as the AppCompatCache (shimcache), SRUM database, and event-log gaps. Output can be a colorized table, CSV, or JSON for downstream tooling.

Chainsaw's strength is speed and flexibility during initial triage: an analyst can drop a folder of collected EVTX onto the tool and get back a prioritized set of detections in seconds, then pivot with targeted search queries to confirm a hypothesis. Unlike a SIEM, it needs no ingestion pipeline, runs as a single binary, and works fully offline against acquired evidence — ideal for the field or an air-gapped analysis VM. The --mapping file tells Chainsaw how Sigma fields translate to Windows event fields, which is what enables broad Sigma coverage over EVTX.

A common hunt outcome is detecting suspicious PowerShell — MITRE ATT&CK T1059.001 (Command and Scripting Interpreter: PowerShell) — by running Sigma rules against PowerShell operational logs (Event ID 4104 script-block logging) or searching for encoded-command patterns. This skill maps to NIST CSF DE.AE-02 (potentially adverse events are analyzed to better understand associated activities).

When to Use

  • During first-response triage to rapidly hunt threats across collected Windows event logs.
  • When you need offline Sigma-based detection over .evtx without standing up a SIEM.
  • To run fast keyword/regex searches confirming or refuting a hunt hypothesis.
  • To analyse shimcache, SRUM, or event-log time gaps for execution evidence and tampering.
  • To produce CSV/JSON detection output for reporting or pipeline ingestion.

Prerequisites

  • Chainsaw binary. Download a release from GitHub or build from source:
    # Build from source (Rust toolchain required)
    git clone https://github.com/WithSecureLabs/chainsaw.git
    cd chainsaw && cargo build --release
    ./target/release/chainsaw --version
    # or: nix profile install github:WithSecureLabs/chainsaw
  • The Chainsaw repo ships mappings/ (Sigma field mappings) and rules/ (Chainsaw rules).
  • A copy of the SigmaHQ rules for full Sigma coverage:
    git clone https://github.com/SigmaHQ/sigma.git
  • Collected Windows .evtx files (and registry hives like SYSTEM/Amcache.hve for shimcache analysis).

Objectives

  • Hunt collected EVTX with Sigma rules using the correct mapping file.
  • Filter detections by rule level, status, and kind to reduce noise.
  • Search logs by keyword, regex, and Tau expression for targeted confirmation.
  • Output detections as table, CSV, and JSON.
  • Analyse shimcache (with Amcache timestamp pairing), SRUM, and event-log gaps.

MITRE ATT&CK Mapping

Technique ID Official Name Why Chainsaw Detects It
T1059.001 Command and Scripting Interpreter: PowerShell Sigma rules over EID 4104/4103 and search flag malicious PowerShell
T1059.003 Command and Scripting Interpreter: Windows Command Shell Process-creation Sigma rules surface suspicious cmd usage
T1547.001 Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder Sigma rules over registry events flag persistence
T1053.005 Scheduled Task/Job: Scheduled Task Rules over EID 4698/106 detect task creation
T1070.006 Indicator Removal: Timestomp analyse gaps and shimcache analysis reveal tampering/time gaps
T1204.002 User Execution: Malicious File Shimcache analysis shows executed binaries

Workflow

1. Hunt EVTX with Sigma rules

Run the SigmaHQ corpus against collected logs using the bundled mapping file. The mapping translates Sigma fields to EVTX fields.

chainsaw hunt ./collected_evtx \
  -s ./sigma/rules \
  --mapping ./mappings/sigma-event-logs-all.yml

2. Hunt with Chainsaw built-in rules plus Sigma

Combine Chainsaw's own rules (-r) with Sigma (-s) for broader coverage.

chainsaw hunt ./collected_evtx \
  -r ./rules \
  -s ./sigma/rules \
  --mapping ./mappings/sigma-event-logs-all.yml

3. Filter to reduce noise

Limit results by Sigma rule level, status, and detection kind.

chainsaw hunt ./collected_evtx -s ./sigma/rules \
  --mapping ./mappings/sigma-event-logs-all.yml \
  --level high --status stable --kind evtx

4. Output to CSV and JSON

Write structured output for reporting and pipelines.

# JSON to stdout/file
chainsaw hunt ./collected_evtx -s ./sigma/rules \
  --mapping ./mappings/sigma-event-logs-all.yml --json > detections.json
 
# CSV into a directory (one file per detection group)
chainsaw hunt ./collected_evtx -s ./sigma/rules \
  --mapping ./mappings/sigma-event-logs-all.yml --csv --output ./csv_out

5. Targeted keyword and regex search

Confirm a hypothesis by searching raw events independent of rules.

# Case-insensitive keyword search
chainsaw search "mimikatz" -i ./collected_evtx
 
# Regex for base64-encoded PowerShell commands, as JSON
chainsaw search -e "-[Ee]nc(odedCommand)?\s+[A-Za-z0-9+/=]{20,}" ./collected_evtx --json
 
# Time-bounded search using a Tau expression
chainsaw search ./collected_evtx -t 'Event.System.EventID: =4624' \
  --from "2026-06-01T00:00:00" --to "2026-06-20T00:00:00"

6. Analyse shimcache for execution evidence

Parse the AppCompatCache from the SYSTEM hive, pair it with Amcache timestamps, and pattern-match suspicious entries.

chainsaw analyse shimcache ./SYSTEM \
  --regexfile ./shimcache_patterns.txt \
  --amcache ./Amcache.hve --tspair \
  --output ./shimcache_analysis.csv

7. Analyse SRUM and event-log gaps

Detect program/network usage and identify suspicious logging gaps (possible log clearing or timestomp).

# SRUM database analysis
chainsaw analyse srum --software ./SOFTWARE ./SRUDB.dat -o srum.json
 
# Event-log gaps that may indicate cleared/tampered logs
chainsaw analyse gaps ./collected_evtx --min-time-gap-minutes 30 --json

8. Dump and lint

Inspect raw artifact content and validate custom rules before a hunt.

chainsaw dump ./SOFTWARE --json --output dump.json
chainsaw lint -r ./rules --kind sigma

Tools and Resources

Tool Purpose Source
Chainsaw Fast EVTX/artifact hunting and search https://github.com/WithSecureLabs/chainsaw
SigmaHQ rules Community detection rules https://github.com/SigmaHQ/sigma
Chainsaw mappings Sigma-to-EVTX field mappings https://github.com/WithSecureLabs/chainsaw/tree/master/mappings
Hayabusa Alternative Sigma EVTX timeline tool https://github.com/Yamato-Security/hayabusa
Timeline Explorer Review CSV output https://ericzimmerman.github.io/

Validation Criteria

  • Chainsaw binary installed and --version confirmed.
  • SigmaHQ rules and the correct mapping file available.
  • Sigma hunt run against the collected EVTX directory.
  • Chainsaw built-in rules combined with Sigma where appropriate.
  • Detections filtered by level/status/kind to reduce noise.
  • CSV and/or JSON output produced for reporting.
  • Targeted keyword/regex/Tau searches run to confirm findings.
  • Shimcache analysed with Amcache timestamp pairing.
  • SRUM and event-log-gap analysis performed where artifacts exist.
  • Findings (e.g., PowerShell T1059.001) documented for the hunt report.
Source materials

References and resources

Everything below is rendered for inspection. Script files are read-only and never run.

References 2

api-reference.md2.2 KB

Chainsaw — Command & Flag Reference

Subcommands

Command Purpose
hunt Detect threats using Sigma and Chainsaw rules
search Keyword/regex/Tau search across artifacts
analyse shimcache / srum / gaps artifact analysis
dump Dump raw artifact content
lint Validate rule files

hunt Flags

Flag Description
-s, --sigma <DIR> SigmaHQ rules directory
-r, --rule <DIR> Chainsaw rules directory
-m, --mapping <FILE> Sigma->event field mapping (e.g. mappings/sigma-event-logs-all.yml)
--level <LEVEL> Filter by Sigma rule level
--status <STATUS> Filter by rule status (e.g. stable)
--kind <KIND> Filter by detection kind (e.g. evtx)
--json / --csv Output format
-o, --output <PATH> Output file/directory
chainsaw hunt ./evtx -s ./sigma/rules \
  --mapping ./mappings/sigma-event-logs-all.yml --level high --json

search Flags

Flag Description
-e, --regex <RE> Regex pattern
-i, --ignore-case Case-insensitive
-t, --tau <EXPR> Tau expression query
--from / --to Timestamp bounds
--json JSON output
chainsaw search "mimikatz" -i ./evtx
chainsaw search -e "-enc\s+[A-Za-z0-9+/=]{20,}" ./evtx --json
chainsaw search ./evtx -t 'Event.System.EventID: =4624'

analyse Subcommands

# Shimcache with Amcache timestamp pairing
chainsaw analyse shimcache ./SYSTEM --regexfile ./patterns.txt \
  --amcache ./Amcache.hve --tspair --output ./out.csv
 
# SRUM database
chainsaw analyse srum --software ./SOFTWARE ./SRUDB.dat -o srum.json
 
# Event-log gaps
chainsaw analyse gaps ./Logs/ --min-time-gap-minutes 30 --json

dump / lint

chainsaw dump ./SOFTWARE --json --output dump.json
chainsaw lint -r ./rules --kind sigma

Install

git clone https://github.com/WithSecureLabs/chainsaw.git
cd chainsaw && cargo build --release
# or: nix profile install github:WithSecureLabs/chainsaw

External References

standards.md1.7 KB

Standards and References — Hunting EVTX with Chainsaw

MITRE ATT&CK References

Technique ID Name Tactic Rationale
T1059.001 Command and Scripting Interpreter: PowerShell Execution Sigma rules over EID 4104/4103 and search flag malicious PowerShell
T1059.003 Command and Scripting Interpreter: Windows Command Shell Execution Process-creation Sigma rules surface suspicious cmd usage
T1547.001 Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder Persistence Registry-event Sigma rules flag persistence
T1053.005 Scheduled Task/Job: Scheduled Task Execution / Persistence Rules over EID 4698/106 detect task creation
T1070.006 Indicator Removal: Timestomp Defense Evasion analyse gaps and shimcache reveal time tampering
T1204.002 User Execution: Malicious File Execution Shimcache analysis shows executed binaries

NIST Cybersecurity Framework 2.0

ID Name Rationale
DE.AE-02 Potentially adverse events are analyzed to better understand associated activities Chainsaw hunts/searches analyze event-log activity to characterize threats

Detection Standards

Official Resources

Key Research

  • WithSecure Labs: Chainsaw release announcements (shimcache, SRUM, gaps analysers)
  • SigmaHQ community detection rule corpus

Scripts 1

agent.py4.7 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Chainsaw EVTX hunting helper.

Drives the Chainsaw binary to run a Sigma+Chainsaw hunt over a directory of
.evtx files, emits JSON, and summarizes detections by rule and level. Can also
run a targeted keyword/regex search to confirm a hypothesis.
"""

import argparse
import json
import os
import shutil
import subprocess
import sys
from collections import Counter
from datetime import datetime, timezone


def find_binary(explicit):
    """Locate the chainsaw binary."""
    if explicit:
        if os.path.isfile(explicit):
            return explicit
        sys.exit(f"[!] Binary not found: {explicit}")
    for name in ("chainsaw", "chainsaw.exe"):
        path = shutil.which(name)
        if path:
            return path
    # common build location
    local = os.path.join("target", "release", "chainsaw")
    if os.path.isfile(local):
        return local
    sys.exit("[!] chainsaw not found; pass --bin /path/to/chainsaw")


def run_json(cmd):
    """Run a chainsaw command expected to emit JSON on stdout."""
    print(f"[*] {' '.join(cmd)}", file=sys.stderr)
    proc = subprocess.run(cmd, capture_output=True, text=True)
    if proc.returncode != 0 and not proc.stdout.strip():
        print(proc.stderr[-1500:], file=sys.stderr)
        sys.exit(f"[!] chainsaw exited {proc.returncode}")
    try:
        return json.loads(proc.stdout)
    except json.JSONDecodeError:
        return []


def hunt(binary, evtx, sigma, mapping, rules, level, status):
    cmd = [binary, "hunt", evtx, "-s", sigma, "--mapping", mapping, "--json"]
    if rules:
        cmd += ["-r", rules]
    if level:
        cmd += ["--level", level]
    if status:
        cmd += ["--status", status]
    return run_json(cmd)


def search(binary, evtx, pattern, regex, ignore_case):
    cmd = [binary, "search"]
    if regex:
        cmd += ["-e", pattern]
    else:
        cmd += [pattern]
    if ignore_case:
        cmd += ["-i"]
    cmd += [evtx, "--json"]
    return run_json(cmd)


def summarize(detections):
    """Summarize Chainsaw hunt JSON by rule name and level."""
    rules, levels = Counter(), Counter()
    total = 0
    for group in detections:
        # Chainsaw JSON groups detections; each carries name/level metadata
        name = group.get("name") or group.get("group") or "unknown"
        level = group.get("level", "unknown")
        docs = group.get("document") or group.get("documents") or [group]
        n = len(docs) if isinstance(docs, list) else 1
        total += n
        rules[name] += n
        levels[level] += n
    return {"total_hits": total,
            "by_level": dict(levels),
            "top_rules": rules.most_common(15)}


def main():
    p = argparse.ArgumentParser(description="Chainsaw EVTX hunting helper")
    p.add_argument("evtx", help="Directory or file of .evtx logs")
    p.add_argument("--bin", help="Path to chainsaw binary")
    p.add_argument("-s", "--sigma", help="SigmaHQ rules directory (for hunt)")
    p.add_argument("--mapping", help="Sigma->event mapping yml (for hunt)")
    p.add_argument("-r", "--rules", help="Chainsaw rules directory")
    p.add_argument("--level", help="Filter by Sigma level (e.g. high)")
    p.add_argument("--status", help="Filter by rule status (e.g. stable)")
    p.add_argument("--search", dest="search_pattern", help="Run a search instead of a hunt")
    p.add_argument("--regex", action="store_true", help="Treat --search as a regex")
    p.add_argument("-i", "--ignore-case", action="store_true")
    p.add_argument("--report", help="Write JSON output to this path")
    args = p.parse_args()

    binary = find_binary(args.bin)

    if args.search_pattern:
        results = search(binary, args.evtx, args.search_pattern,
                         args.regex, args.ignore_case)
        out = {"mode": "search", "pattern": args.search_pattern,
               "hits": len(results) if isinstance(results, list) else 0}
        print(f"[+] search hits: {out['hits']}")
    else:
        if not (args.sigma and args.mapping):
            p.error("hunt mode requires --sigma and --mapping")
        results = hunt(binary, args.evtx, args.sigma, args.mapping,
                       args.rules, args.level, args.status)
        out = summarize(results)
        out["mode"] = "hunt"
        print(f"[+] {out['total_hits']} hits across {len(out['top_rules'])} rules")
        print(f"[+] By level: {out['by_level']}")
        for name, count in out["top_rules"]:
            print(f"    {count:5d}  {name}")

    out["generated"] = datetime.now(timezone.utc).isoformat()
    if args.report:
        with open(args.report, "w") as f:
            json.dump({"summary": out, "raw": results}, f, indent=2)
        print(f"[+] Report written to {args.report}")


if __name__ == "__main__":
    main()
Keep exploring