npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
Overview
Eric Zimmerman's EZ Tools suite is a collection of open-source forensic utilities that have become the global standard for Windows digital forensics investigations. Originally developed by a former FBI agent and current SANS instructor, these tools parse and analyze critical Windows artifacts including the Master File Table ($MFT), registry hives, prefetch files, event logs, shortcut (LNK) files, and jump lists. The suite integrates with KAPE (Kroll Artifact Parser and Extractor) for automated artifact collection and processing, producing structured CSV output that can be ingested into Timeline Explorer for visual analysis. EZ Tools are widely used by law enforcement, corporate incident responders, and forensic consultants worldwide.
When to Use
- When conducting security assessments that involve performing windows artifact analysis with eric zimmerman tools
- When following incident response procedures for related security events
- When performing scheduled security testing or auditing activities
- When validating security controls through hands-on testing
Prerequisites
- Windows 10/11 or Windows Server 2016+ analysis workstation
- .NET 6 Runtime installed (required for EZ Tools v2.x+)
- Administrative privileges on the analysis workstation
- Forensic disk image or triage collection from target system
- At least 8 GB RAM (16 GB recommended for large datasets)
- Familiarity with NTFS file system structures and Windows internals
Tool Suite Components
KAPE (Kroll Artifact Parser and Extractor)
KAPE is the primary orchestration tool that automates artifact collection (Targets) and processing (Modules). It uses configuration files (.tkape and .mkape) to define what artifacts to collect and which EZ Tools to run against them.
Installation and Setup:
# Download KAPE from https://www.kroll.com/en/services/cyber-risk/incident-response-litigation-support/kroll-artifact-parser-extractor-kape
# Extract to C:\Tools\KAPE
# Update KAPE targets and modules
C:\Tools\KAPE\gkape.exe # GUI version
C:\Tools\KAPE\kape.exe # CLI version
# Sync latest EZ Tools binaries
C:\Tools\KAPE\Get-KAPEUpdate.ps1Running KAPE Collection and Processing:
# Collect artifacts from E: drive (mounted forensic image) and process with EZ Tools
kape.exe --tsource E: --tdest C:\Cases\Case001\Collection --target KapeTriage --mdest C:\Cases\Case001\Processed --module !EZParser
# Collect specific artifact categories
kape.exe --tsource E: --tdest C:\Cases\Case001\Collection --target FileSystem,RegistryHives,EventLogs --mdest C:\Cases\Case001\Processed --module MFTECmd,RECmd,EvtxECmd
# Live system triage collection (run as administrator)
kape.exe --tsource C: --tdest D:\LiveTriage\Collection --target KapeTriage --mdest D:\LiveTriage\Processed --module !EZParser --vhdx LiveTriageImageMFTECmd - Master File Table Parser
MFTECmd parses the NTFS $MFT, $J (USN Journal), $Boot, $SDS, and $LogFile into human-readable CSV format.
# Parse the $MFT file
MFTECmd.exe -f "C:\Cases\Evidence\$MFT" --csv C:\Cases\Output --csvf MFT_output.csv
# Parse the USN Journal ($J)
MFTECmd.exe -f "C:\Cases\Evidence\$J" --csv C:\Cases\Output --csvf USNJournal_output.csv
# Parse $Boot for volume information
MFTECmd.exe -f "C:\Cases\Evidence\$Boot" --csv C:\Cases\Output --csvf Boot_output.csv
# Parse $SDS for security descriptors
MFTECmd.exe -f "C:\Cases\Evidence\$SDS" --csv C:\Cases\Output --csvf SDS_output.csvKey Fields in MFT Output:
| Field | Description |
|---|---|
| EntryNumber | MFT record number |
| ParentEntryNumber | Parent directory MFT record |
| InUse | Whether the record is active or deleted |
| FileName | Name of the file or directory |
| Created0x10 | $STANDARD_INFORMATION creation timestamp |
| Created0x30 | $FILE_NAME creation timestamp |
| LastModified0x10 | $STANDARD_INFORMATION modification timestamp |
| IsDirectory | Boolean indicating directory or file |
| FileSize | Logical file size in bytes |
| Extension | File extension |
PECmd - Prefetch File Parser
PECmd parses Windows Prefetch files (.pf) to provide evidence of program execution, including run counts and timestamps.
# Parse all prefetch files from a directory
PECmd.exe -d "C:\Cases\Evidence\Windows\Prefetch" --csv C:\Cases\Output --csvf Prefetch_output.csv
# Parse a single prefetch file with verbose output
PECmd.exe -f "C:\Cases\Evidence\Windows\Prefetch\CMD.EXE-4A81B364.pf" --json C:\Cases\Output
# Parse prefetch with keyword filtering
PECmd.exe -d "C:\Cases\Evidence\Windows\Prefetch" -k "powershell,cmd,wscript,cscript,mshta" --csv C:\Cases\Output --csvf SuspiciousExec.csvRECmd - Registry Explorer Command Line
RECmd processes Windows registry hives using batch files that define which keys and values to extract.
# Process all registry hives with the default batch file
RECmd.exe --bn C:\Tools\KAPE\Modules\bin\RECmd\BatchExamples\RECmd_Batch_MC.reb -d "C:\Cases\Evidence\Registry" --csv C:\Cases\Output --csvf Registry_output.csv
# Process a single NTUSER.DAT hive
RECmd.exe -f "C:\Cases\Evidence\Users\suspect\NTUSER.DAT" --bn C:\Tools\KAPE\Modules\bin\RECmd\BatchExamples\RECmd_Batch_MC.reb --csv C:\Cases\Output
# Process SYSTEM hive for USB device history
RECmd.exe -f "C:\Cases\Evidence\Registry\SYSTEM" --bn C:\Tools\KAPE\Modules\bin\RECmd\BatchExamples\RECmd_Batch_MC.reb --csv C:\Cases\OutputEvtxECmd - Windows Event Log Parser
EvtxECmd parses Windows Event Log (.evtx) files into structured CSV format with customizable event ID maps.
# Parse all event logs from a directory
EvtxECmd.exe -d "C:\Cases\Evidence\Windows\System32\winevt\Logs" --csv C:\Cases\Output --csvf EventLogs_output.csv
# Parse a single event log
EvtxECmd.exe -f "C:\Cases\Evidence\Security.evtx" --csv C:\Cases\Output --csvf Security_output.csv
# Parse with custom maps for enhanced field extraction
EvtxECmd.exe -d "C:\Cases\Evidence\Logs" --csv C:\Cases\Output --maps C:\Tools\KAPE\Modules\bin\EvtxECmd\MapsLECmd and JLECmd - Shortcut and Jump List Parsers
# Parse LNK files from Recent directory
LECmd.exe -d "C:\Cases\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent" --csv C:\Cases\Output --csvf LNK_output.csv
# Parse Jump Lists (automatic destinations)
JLECmd.exe -d "C:\Cases\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent\AutomaticDestinations" --csv C:\Cases\Output --csvf JumpLists_auto.csv
# Parse Jump Lists (custom destinations)
JLECmd.exe -d "C:\Cases\Evidence\Users\suspect\AppData\Roaming\Microsoft\Windows\Recent\CustomDestinations" --csv C:\Cases\Output --csvf JumpLists_custom.csvSBECmd - Shellbag Explorer Command Line
# Parse shellbags from a directory of registry hives
SBECmd.exe -d "C:\Cases\Evidence\Registry" --csv C:\Cases\Output --csvf Shellbags_output.csv
# Parse shellbags from a live system (requires admin)
SBECmd.exe --live --csv C:\Cases\Output --csvf LiveShellbags_output.csvTimeline Explorer - Visual Analysis
Timeline Explorer is the GUI tool for analyzing CSV output from all EZ Tools. It supports filtering, sorting, column grouping, and conditional formatting.
# Launch Timeline Explorer and open CSV output
TimelineExplorer.exe "C:\Cases\Output\MFT_output.csv"Key Timeline Explorer Features:
- Column-level filtering with regular expressions
- Conditional formatting for timestamp anomalies
- Multi-column sorting for chronological analysis
- Export filtered results to new CSV files
- Bookmarking rows of interest
Investigation Workflow
Step 1: Artifact Collection with KAPE
# Full triage collection from forensic image mounted at E:
kape.exe --tsource E: --tdest C:\Cases\Case001\Collected --target KapeTriage --vhdx TriageImage --zv falseStep 2: Artifact Processing with EZ Tools
# Process all collected artifacts
kape.exe --msource C:\Cases\Case001\Collected --mdest C:\Cases\Case001\Processed --module !EZParserStep 3: Timeline Analysis
- Open processed CSV files in Timeline Explorer
- Sort by timestamp columns to establish chronological order
- Filter for specific file extensions, paths, or event IDs
- Cross-reference MFT timestamps with event log entries
- Identify timestomping by comparing $SI and $FN timestamps
- Document findings with bookmarks and exported filtered views
Step 4: Timestomping Detection
# In Timeline Explorer, compare these columns:
# Created0x10 ($STANDARD_INFORMATION) vs Created0x30 ($FILE_NAME)
# If Created0x10 < Created0x30, timestomping is indicated
# $FILE_NAME timestamps are harder to manipulate than $STANDARD_INFORMATIONForensic Artifacts Reference
| Tool | Artifact | Location |
|---|---|---|
| MFTECmd | $MFT | Root of NTFS volume |
| MFTECmd | $J (USN Journal) | $Extend$UsnJrnl:$J |
| PECmd | Prefetch files | C:\Windows\Prefetch*.pf |
| RECmd | NTUSER.DAT | C:\Users{user}\NTUSER.DAT |
| RECmd | SYSTEM hive | C:\Windows\System32\config\SYSTEM |
| RECmd | SAM hive | C:\Windows\System32\config\SAM |
| RECmd | SOFTWARE hive | C:\Windows\System32\config\SOFTWARE |
| EvtxECmd | Event logs | C:\Windows\System32\winevt\Logs*.evtx |
| LECmd | LNK files | C:\Users{user}\AppData\Roaming\Microsoft\Windows\Recent\ |
| JLECmd | Jump lists | C:\Users{user}\AppData\Roaming\Microsoft\Windows\Recent\AutomaticDestinations\ |
| SBECmd | Shellbags | NTUSER.DAT and UsrClass.dat registry hives |
Common Investigation Scenarios
Malware Execution Evidence
- Parse Prefetch with PECmd to identify executed binaries
- Cross-reference with MFT for file creation timestamps
- Check Amcache.hve with RECmd for SHA1 hashes of executables
- Correlate with Event Log entries for process creation (Event ID 4688)
Data Exfiltration Investigation
- Parse USN Journal with MFTECmd for file rename/delete operations
- Analyze LNK files with LECmd for recently accessed documents
- Review Shellbags with SBECmd for directory browsing activity
- Check for USB device connections in SYSTEM registry with RECmd
Lateral Movement Detection
- Parse Security.evtx with EvtxECmd for logon events (4624, 4625)
- Analyze RDP-related event logs (Microsoft-Windows-TerminalServices)
- Cross-reference with network share access from SMB logs
- Review scheduled tasks and services for persistence mechanisms
Output Format and Integration
All EZ Tools produce CSV output that can be:
- Analyzed in Timeline Explorer for visual investigation
- Imported into Splunk, Elastic, or other SIEM platforms
- Processed by Python/PowerShell scripts for automated analysis
- Combined into super timelines using log2timeline/Plaso
References
- Eric Zimmerman's Tools: https://ericzimmerman.github.io/
- KAPE Documentation: https://ericzimmerman.github.io/KapeDocs/
- SANS EZ Tools Training: https://www.sans.org/tools/ez-tools
- SANS FOR508: Advanced Incident Response and Threat Hunting
- SANS FOR498: Battlefield Forensics & Data Acquisition
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md2.0 KB
API Reference: Windows Artifact Analysis with Eric Zimmerman Tools
EZ Tools Suite
| Tool | Artifact | Description |
|---|---|---|
MFTECmd.exe |
$MFT | Parse Master File Table |
PECmd.exe |
Prefetch | Parse prefetch files for execution history |
LECmd.exe |
LNK | Parse shortcut files |
JLECmd.exe |
Jump Lists | Parse automatic/custom jump lists |
SBECmd.exe |
ShellBags | Parse folder access history from registry |
AmcacheParser.exe |
Amcache | Parse application execution evidence |
AppCompatCacheParser.exe |
Shimcache | Parse application compatibility cache |
EvtxECmd.exe |
EVTX | Parse Windows event logs |
RECmd.exe |
Registry | Parse registry hives |
Common CLI Flags
| Flag | Description |
|---|---|
-f <file> |
Input file path |
-d <directory> |
Input directory |
--csv <dir> |
Output directory for CSV |
--csvf <file> |
CSV output filename |
--json <dir> |
Output directory for JSON |
--body <dir> |
Output bodyfile for timeline |
Key Artifacts and Locations
| Artifact | Path | Evidence |
|---|---|---|
| $MFT | C:\$MFT |
File creation/modification/access |
| Prefetch | C:\Windows\Prefetch\ |
Program execution with timestamps |
| LNK Files | %APPDATA%\Microsoft\Windows\Recent\ |
Recently accessed files |
| Jump Lists | %APPDATA%\Microsoft\Windows\Recent\AutomaticDestinations\ |
Per-app recent files |
| ShellBags | NTUSER.DAT, UsrClass.dat | Folder browsing history |
| Amcache | C:\Windows\AppCompat\Programs\Amcache.hve |
Application execution |
Python Libraries
| Library | Version | Purpose |
|---|---|---|
subprocess |
stdlib | Execute EZ tools |
csv |
stdlib | Parse CSV output |
json |
stdlib | Report generation |
References
- Eric Zimmerman Tools: https://ericzimmerman.github.io/
- SANS Windows Forensic Analysis Poster: https://www.sans.org/posters/windows-forensic-analysis/
- EZ Tools GitHub: https://github.com/EricZimmerman
standards.md2.6 KB
Standards and References - EZ Tools Windows Forensics
Industry Standards
NIST SP 800-86 - Guide to Integrating Forensic Techniques
- Framework for collecting, examining, and analyzing digital evidence
- Defines procedures for forensic acquisition and chain of custody
- EZ Tools align with NIST evidence handling and analysis guidelines
ISO/IEC 27037 - Digital Evidence Collection
- International standard for identification, collection, acquisition, and preservation
- KAPE collection follows ISO 27037 acquisition methodology
- Timeline Explorer output supports ISO-compliant reporting
SWGDE Best Practices for Computer Forensics
- Scientific Working Group on Digital Evidence guidelines
- Defines validation requirements for forensic tools
- EZ Tools undergo community-driven validation testing
Tool References
EZ Tools Suite Components
| Tool | Version | Purpose |
|---|---|---|
| KAPE | 1.3+ | Artifact collection and processing orchestration |
| MFTECmd | 1.2+ | NTFS Master File Table parser |
| PECmd | 1.5+ | Windows Prefetch file parser |
| RECmd | 2.0+ | Registry hive parser with batch processing |
| EvtxECmd | 1.5+ | Windows Event Log parser with maps |
| LECmd | 1.5+ | LNK shortcut file parser |
| JLECmd | 1.5+ | Jump List parser |
| SBECmd | 2.0+ | Shellbag parser |
| Timeline Explorer | 2.0+ | CSV analysis and visualization |
| Registry Explorer | 2.0+ | GUI registry hive viewer |
| ShellBags Explorer | 2.0+ | GUI shellbag viewer |
| AmcacheParser | 1.5+ | Amcache.hve parser |
| AppCompatCacheParser | 1.5+ | ShimCache parser |
| WxTCmd | 1.0+ | Windows Timeline database parser |
| RBCmd | 1.5+ | Recycle Bin artifact parser |
| bstrings | 1.5+ | Binary string extraction |
SANS Training Courses
- FOR500: Windows Forensic Analysis
- FOR508: Advanced Incident Response, Threat Hunting, and Digital Forensics
- FOR498: Battlefield Forensics & Data Acquisition
- FOR610: Reverse-Engineering Malware
MITRE ATT&CK Relevance
- T1070 - Indicator Removal: Timestomping detection via MFT analysis
- T1547 - Boot or Logon Autostart Execution: Registry persistence detection
- T1053 - Scheduled Task/Job: Task scheduler artifact analysis
- T1059 - Command and Scripting Interpreter: Prefetch execution evidence
- T1021 - Remote Services: Lateral movement via event log analysis
Official Resources
- Eric Zimmerman's GitHub: https://ericzimmerman.github.io/
- KAPE GitHub Targets/Modules: https://github.com/EricZimmerman/KapeFiles
- EZ Tools Changelog: https://ericzimmerman.github.io/#!index.md
- SANS DFIR Blog: https://www.sans.org/blog/?focus-area=digital-forensics
workflows.md2.9 KB
Workflows - EZ Tools Windows Forensic Analysis
Workflow 1: Full Triage Collection and Processing
Step 1: Mount forensic image as read-only drive (E:)
|
Step 2: Run KAPE with KapeTriage target
|-- Collects: $MFT, $J, Registry, Event Logs, Prefetch, LNK, Jump Lists
|
Step 3: Run KAPE with !EZParser module
|-- Processes all collected artifacts with appropriate EZ Tools
|
Step 4: Open CSV outputs in Timeline Explorer
|-- Sort by timestamp, filter by artifact type
|
Step 5: Build investigation timeline
|-- Cross-reference MFT, Event Logs, Prefetch, Registry
|
Step 6: Document findings and export filtered resultsWorkflow 2: Timestomping Detection
Step 1: Parse $MFT with MFTECmd
|
Step 2: Open MFT CSV in Timeline Explorer
|
Step 3: Compare $SI timestamps (Created0x10) vs $FN timestamps (Created0x30)
|-- Flag entries where Created0x10 < Created0x30
|-- Flag entries where all four $SI timestamps are identical
|
Step 4: Cross-reference flagged files with USN Journal entries
|
Step 5: Verify with event log correlation (process creation, file access)Workflow 3: Program Execution Timeline
Step 1: Parse Prefetch with PECmd
|
Step 2: Parse Amcache.hve with AmcacheParser
|
Step 3: Parse ShimCache with AppCompatCacheParser
|
Step 4: Parse UserAssist from NTUSER.DAT with RECmd
|
Step 5: Merge and correlate execution timestamps
|-- Prefetch: Run count + last 8 execution times
|-- Amcache: First execution + SHA1 hash
|-- ShimCache: Last modified time (execution indicator)
|-- UserAssist: GUI program execution tracking
|
Step 6: Build execution timeline in Timeline ExplorerWorkflow 4: Lateral Movement Investigation
Step 1: Parse Security.evtx with EvtxECmd
|-- Filter Event ID 4624 (Logon Type 3, 10)
|-- Filter Event ID 4625 (Failed logons)
|
Step 2: Parse TerminalServices event logs
|-- Microsoft-Windows-TerminalServices-LocalSessionManager
|-- Microsoft-Windows-TerminalServices-RDPClient
|
Step 3: Correlate with registry RDP MRU entries
|-- NTUSER.DAT\Software\Microsoft\Terminal Server Client\Servers
|
Step 4: Analyze LNK files for network path access
|
Step 5: Review scheduled task creation from event logs
|
Step 6: Map lateral movement path across systemsWorkflow 5: USB Device Investigation
Step 1: Parse SYSTEM hive with RECmd
|-- SYSTEM\CurrentControlSet\Enum\USBSTOR
|-- SYSTEM\CurrentControlSet\Enum\USB
|-- SYSTEM\MountedDevices
|
Step 2: Parse NTUSER.DAT with RECmd
|-- MountPoints2 for user-level device associations
|
Step 3: Parse setupapi.dev.log for device installation timestamps
|
Step 4: Analyze LNK files referencing removable drive letters
|
Step 5: Check Shellbags for folder browsing on USB devices
|
Step 6: Correlate with Event Logs (Microsoft-Windows-Partition/Diagnostic)Scripts 2
agent.py6.7 KB
#!/usr/bin/env python3
"""Agent for Windows artifact analysis with Eric Zimmerman tools.
Runs EZ tools (MFTECmd, PECmd, LECmd, JLECmd, ShellBags Explorer CLI)
via subprocess, parses CSV output, and builds a forensic timeline
from Windows filesystem and registry artifacts.
"""
import subprocess
import json
import sys
import csv
import io
from datetime import datetime
from pathlib import Path
class EZToolsAgent:
"""Analyzes Windows forensic artifacts using Eric Zimmerman tools."""
def __init__(self, output_dir="./ez_analysis"):
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
self.timeline = []
def _run_tool(self, tool, args, timeout=300):
cmd = [tool] + args
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=timeout)
return {"return_code": result.returncode,
"stdout_lines": len(result.stdout.splitlines()),
"stderr": result.stderr[:300] if result.stderr else ""}
except FileNotFoundError:
return {"error": f"{tool} not found. Download from https://ericzimmerman.github.io/"}
except subprocess.TimeoutExpired:
return {"error": f"{tool} timed out"}
def parse_mft(self, mft_path):
"""Parse $MFT using MFTECmd and extract file creation/modification."""
csv_out = self.output_dir / "mft_output.csv"
result = self._run_tool("MFTECmd.exe", ["-f", mft_path,
"--csv", str(self.output_dir),
"--csvf", "mft_output.csv"])
if "error" in result:
return result
return self._parse_csv(csv_out, "MFT",
time_cols=["Created0x10", "LastModified0x10"])
def parse_prefetch(self, prefetch_dir):
"""Parse Prefetch files using PECmd for program execution evidence."""
csv_out = self.output_dir / "prefetch_output.csv"
result = self._run_tool("PECmd.exe", ["-d", prefetch_dir,
"--csv", str(self.output_dir),
"--csvf", "prefetch_output.csv"])
if "error" in result:
return result
return self._parse_csv(csv_out, "Prefetch",
time_cols=["LastRun", "PreviousRun0"])
def parse_lnk_files(self, lnk_dir):
"""Parse LNK shortcut files using LECmd."""
csv_out = self.output_dir / "lnk_output.csv"
result = self._run_tool("LECmd.exe", ["-d", lnk_dir,
"--csv", str(self.output_dir),
"--csvf", "lnk_output.csv"])
if "error" in result:
return result
return self._parse_csv(csv_out, "LNK",
time_cols=["TargetCreated", "TargetModified"])
def parse_jump_lists(self, jl_dir):
"""Parse Jump Lists using JLECmd for recent file access."""
csv_out = self.output_dir / "jumplist_output.csv"
result = self._run_tool("JLECmd.exe", ["-d", jl_dir,
"--csv", str(self.output_dir),
"--csvf", "jumplist_output.csv"])
if "error" in result:
return result
return self._parse_csv(csv_out, "JumpList",
time_cols=["TargetCreated", "TargetModified"])
def parse_shellbags(self, registry_hive):
"""Parse ShellBags from NTUSER.DAT/UsrClass.dat."""
csv_out = self.output_dir / "shellbags_output.csv"
result = self._run_tool("SBECmd.exe", ["-d", registry_hive,
"--csv", str(self.output_dir),
"--csvf", "shellbags_output.csv"])
if "error" in result:
return result
return self._parse_csv(csv_out, "ShellBag",
time_cols=["LastWriteTime", "FirstExplored"])
def _parse_csv(self, csv_path, artifact_type, time_cols=None):
"""Parse EZ tool CSV output into timeline entries."""
if not csv_path.exists():
return {"error": f"CSV not found: {csv_path}"}
entries = []
try:
with open(csv_path, "r", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
for row in reader:
entry = {"artifact_type": artifact_type}
for key, val in row.items():
if val:
entry[key] = val
if time_cols:
for tc in time_cols:
ts = row.get(tc, "")
if ts:
entry["timestamp"] = ts
self.timeline.append({
"timestamp": ts,
"artifact": artifact_type,
"source": csv_path.name,
"details": {k: v for k, v in row.items()
if v and k != tc}
})
break
entries.append(entry)
except (csv.Error, UnicodeDecodeError) as exc:
return {"error": str(exc)}
return {"artifact": artifact_type, "entries": len(entries)}
def build_timeline(self):
"""Sort all collected entries into a unified forensic timeline."""
self.timeline.sort(key=lambda x: x.get("timestamp", ""))
return self.timeline
def generate_report(self):
self.build_timeline()
report = {
"report_date": datetime.utcnow().isoformat(),
"total_timeline_entries": len(self.timeline),
"timeline_sample": self.timeline[:50],
}
report_path = self.output_dir / "ez_tools_report.json"
with open(report_path, "w") as f:
json.dump(report, f, indent=2, default=str)
print(json.dumps(report, indent=2, default=str))
return report
def main():
if len(sys.argv) < 3:
print("Usage: agent.py <artifact_type> <path>")
print(" artifact_type: mft|prefetch|lnk|jumplist|shellbag")
sys.exit(1)
agent = EZToolsAgent()
atype = sys.argv[1]
path = sys.argv[2]
dispatch = {"mft": agent.parse_mft, "prefetch": agent.parse_prefetch,
"lnk": agent.parse_lnk_files, "jumplist": agent.parse_jump_lists,
"shellbag": agent.parse_shellbags}
fn = dispatch.get(atype)
if fn:
fn(path)
agent.generate_report()
if __name__ == "__main__":
main()
process.py12.2 KB
#!/usr/bin/env python3
"""
EZ Tools Forensic Artifact Processor
Automates the execution of Eric Zimmerman's tools against collected
forensic artifacts and generates consolidated analysis reports.
"""
import subprocess
import csv
import os
import sys
import json
import hashlib
from pathlib import Path
from datetime import datetime
from collections import defaultdict
class EZToolsProcessor:
"""Orchestrates EZ Tools processing against forensic artifact collections."""
def __init__(self, ez_tools_path: str, evidence_path: str, output_path: str):
self.ez_tools_path = Path(ez_tools_path)
self.evidence_path = Path(evidence_path)
self.output_path = Path(output_path)
self.output_path.mkdir(parents=True, exist_ok=True)
self.results = {}
self.tools = {
"MFTECmd": self.ez_tools_path / "MFTECmd.exe",
"PECmd": self.ez_tools_path / "PECmd.exe",
"LECmd": self.ez_tools_path / "LECmd.exe",
"JLECmd": self.ez_tools_path / "JLECmd.exe",
"SBECmd": self.ez_tools_path / "SBECmd.exe",
"EvtxECmd": self.ez_tools_path / "EvtxECmd.exe",
"RECmd": self.ez_tools_path / "RECmd.exe",
"RBCmd": self.ez_tools_path / "RBCmd.exe",
"AmcacheParser": self.ez_tools_path / "AmcacheParser.exe",
"AppCompatCacheParser": self.ez_tools_path / "AppCompatCacheParser.exe",
}
def verify_tools(self) -> dict:
"""Verify which EZ Tools are available on the system."""
availability = {}
for name, path in self.tools.items():
availability[name] = path.exists()
return availability
def run_tool(self, tool_name: str, args: list) -> dict:
"""Execute an EZ Tool with given arguments."""
tool_path = self.tools.get(tool_name)
if not tool_path or not tool_path.exists():
return {"status": "error", "message": f"{tool_name} not found at {tool_path}"}
cmd = [str(tool_path)] + args
try:
result = subprocess.run(
cmd,
capture_output=True,
text=True,
timeout=300
)
return {
"status": "success" if result.returncode == 0 else "error",
"stdout": result.stdout,
"stderr": result.stderr,
"returncode": result.returncode
}
except subprocess.TimeoutExpired:
return {"status": "error", "message": f"{tool_name} timed out after 300 seconds"}
except Exception as e:
return {"status": "error", "message": str(e)}
def process_mft(self, mft_path: str = None) -> dict:
"""Parse the $MFT file with MFTECmd."""
if mft_path is None:
mft_candidates = list(self.evidence_path.rglob("$MFT"))
if not mft_candidates:
return {"status": "skipped", "message": "$MFT not found"}
mft_path = str(mft_candidates[0])
output_file = "MFT_output.csv"
args = ["-f", mft_path, "--csv", str(self.output_path), "--csvf", output_file]
result = self.run_tool("MFTECmd", args)
result["output_file"] = str(self.output_path / output_file)
self.results["MFT"] = result
return result
def process_usn_journal(self, journal_path: str = None) -> dict:
"""Parse the USN Journal ($J) with MFTECmd."""
if journal_path is None:
j_candidates = list(self.evidence_path.rglob("$J"))
if not j_candidates:
return {"status": "skipped", "message": "$J not found"}
journal_path = str(j_candidates[0])
output_file = "USNJournal_output.csv"
args = ["-f", journal_path, "--csv", str(self.output_path), "--csvf", output_file]
result = self.run_tool("MFTECmd", args)
result["output_file"] = str(self.output_path / output_file)
self.results["USNJournal"] = result
return result
def process_prefetch(self, prefetch_dir: str = None) -> dict:
"""Parse Prefetch files with PECmd."""
if prefetch_dir is None:
pf_candidates = list(self.evidence_path.rglob("Prefetch"))
if not pf_candidates:
return {"status": "skipped", "message": "Prefetch directory not found"}
prefetch_dir = str(pf_candidates[0])
output_file = "Prefetch_output.csv"
args = ["-d", prefetch_dir, "--csv", str(self.output_path), "--csvf", output_file]
result = self.run_tool("PECmd", args)
result["output_file"] = str(self.output_path / output_file)
self.results["Prefetch"] = result
return result
def process_lnk_files(self, lnk_dir: str = None) -> dict:
"""Parse LNK shortcut files with LECmd."""
if lnk_dir is None:
recent_candidates = list(self.evidence_path.rglob("Recent"))
if not recent_candidates:
return {"status": "skipped", "message": "Recent directory not found"}
lnk_dir = str(recent_candidates[0])
output_file = "LNK_output.csv"
args = ["-d", lnk_dir, "--csv", str(self.output_path), "--csvf", output_file]
result = self.run_tool("LECmd", args)
result["output_file"] = str(self.output_path / output_file)
self.results["LNK"] = result
return result
def process_jump_lists(self, jl_dir: str = None) -> dict:
"""Parse Jump List files with JLECmd."""
if jl_dir is None:
auto_dest = list(self.evidence_path.rglob("AutomaticDestinations"))
if not auto_dest:
return {"status": "skipped", "message": "AutomaticDestinations not found"}
jl_dir = str(auto_dest[0])
output_file = "JumpLists_output.csv"
args = ["-d", jl_dir, "--csv", str(self.output_path), "--csvf", output_file]
result = self.run_tool("JLECmd", args)
result["output_file"] = str(self.output_path / output_file)
self.results["JumpLists"] = result
return result
def process_event_logs(self, evtx_dir: str = None) -> dict:
"""Parse Windows Event Logs with EvtxECmd."""
if evtx_dir is None:
logs_candidates = list(self.evidence_path.rglob("winevt"))
if logs_candidates:
evtx_dir = str(logs_candidates[0] / "Logs")
else:
evtx_files = list(self.evidence_path.rglob("*.evtx"))
if not evtx_files:
return {"status": "skipped", "message": "Event logs not found"}
evtx_dir = str(evtx_files[0].parent)
output_file = "EventLogs_output.csv"
args = ["-d", evtx_dir, "--csv", str(self.output_path), "--csvf", output_file]
result = self.run_tool("EvtxECmd", args)
result["output_file"] = str(self.output_path / output_file)
self.results["EventLogs"] = result
return result
def process_shellbags(self, registry_dir: str = None) -> dict:
"""Parse Shellbag artifacts with SBECmd."""
if registry_dir is None:
registry_dir = str(self.evidence_path)
output_file = "Shellbags_output.csv"
args = ["-d", registry_dir, "--csv", str(self.output_path), "--csvf", output_file]
result = self.run_tool("SBECmd", args)
result["output_file"] = str(self.output_path / output_file)
self.results["Shellbags"] = result
return result
def process_recycle_bin(self, recycle_dir: str = None) -> dict:
"""Parse Recycle Bin artifacts with RBCmd."""
if recycle_dir is None:
rb_candidates = list(self.evidence_path.rglob("$Recycle.Bin"))
if not rb_candidates:
return {"status": "skipped", "message": "$Recycle.Bin not found"}
recycle_dir = str(rb_candidates[0])
output_file = "RecycleBin_output.csv"
args = ["-d", recycle_dir, "--csv", str(self.output_path), "--csvf", output_file]
result = self.run_tool("RBCmd", args)
result["output_file"] = str(self.output_path / output_file)
self.results["RecycleBin"] = result
return result
def detect_timestomping(self, mft_csv_path: str) -> list:
"""Analyze MFT CSV output to detect timestomping indicators."""
timestomped = []
try:
with open(mft_csv_path, "r", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
for row in reader:
si_created = row.get("Created0x10", "")
fn_created = row.get("Created0x30", "")
if si_created and fn_created:
try:
si_dt = datetime.fromisoformat(si_created.replace("Z", "+00:00"))
fn_dt = datetime.fromisoformat(fn_created.replace("Z", "+00:00"))
if si_dt < fn_dt:
timestomped.append({
"file": row.get("FileName", "Unknown"),
"entry_number": row.get("EntryNumber", ""),
"si_created": si_created,
"fn_created": fn_created,
"indicator": "$SI Created before $FN Created"
})
except (ValueError, TypeError):
continue
except FileNotFoundError:
return [{"error": f"MFT CSV not found: {mft_csv_path}"}]
return timestomped
def process_all(self) -> dict:
"""Run all available EZ Tools processors against evidence."""
print("[*] Starting comprehensive EZ Tools processing...")
print(f"[*] Evidence path: {self.evidence_path}")
print(f"[*] Output path: {self.output_path}")
available = self.verify_tools()
print(f"[*] Available tools: {sum(v for v in available.values())}/{len(available)}")
processors = [
("MFT", self.process_mft),
("USN Journal", self.process_usn_journal),
("Prefetch", self.process_prefetch),
("LNK Files", self.process_lnk_files),
("Jump Lists", self.process_jump_lists),
("Event Logs", self.process_event_logs),
("Shellbags", self.process_shellbags),
("Recycle Bin", self.process_recycle_bin),
]
for name, processor in processors:
print(f"[*] Processing {name}...")
result = processor()
status = result.get("status", "unknown")
print(f" [{status.upper()}] {name}")
return self.results
def generate_report(self) -> str:
"""Generate a summary report of all processing results."""
report = {
"timestamp": datetime.now().isoformat(),
"evidence_path": str(self.evidence_path),
"output_path": str(self.output_path),
"results": {}
}
for artifact, result in self.results.items():
report["results"][artifact] = {
"status": result.get("status", "unknown"),
"output_file": result.get("output_file", ""),
}
output_file = result.get("output_file", "")
if output_file and os.path.exists(output_file):
file_size = os.path.getsize(output_file)
report["results"][artifact]["output_size_bytes"] = file_size
with open(output_file, "rb") as f:
report["results"][artifact]["sha256"] = hashlib.sha256(f.read()).hexdigest()
report_path = self.output_path / "processing_report.json"
with open(report_path, "w") as f:
json.dump(report, f, indent=2)
print(f"\n[*] Report saved to: {report_path}")
return str(report_path)
def main():
if len(sys.argv) < 4:
print("Usage: python process.py <ez_tools_path> <evidence_path> <output_path>")
print("Example: python process.py C:\\Tools\\EZTools C:\\Cases\\Evidence C:\\Cases\\Output")
sys.exit(1)
ez_tools_path = sys.argv[1]
evidence_path = sys.argv[2]
output_path = sys.argv[3]
processor = EZToolsProcessor(ez_tools_path, evidence_path, output_path)
processor.process_all()
processor.generate_report()
if __name__ == "__main__":
main()