npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
Use this skill when:
- Investigating a confirmed or suspected endpoint compromise requiring forensic analysis
- Collecting volatile and non-volatile evidence for incident response or legal proceedings
- Analyzing memory dumps for malware, injected code, or credential theft artifacts
- Reconstructing attacker timelines from endpoint artifacts (prefetch, shimcache, amcache)
Do not use this skill for live threat hunting (use EDR/SIEM) or network forensics.
Prerequisites
- Forensic workstation with analysis tools (Volatility 3, KAPE, Autopsy, Eric Zimmerman tools)
- Write-blocker for disk imaging (hardware or software)
- Secure evidence storage with chain-of-custody documentation
- Memory acquisition tool (WinPMEM, FTK Imager, Magnet RAM Capture)
- Administrative access to the target endpoint (or physical access)
Workflow
Step 1: Evidence Preservation (Order of Volatility)
Collect evidence from most volatile to least volatile:
1. System memory (RAM) - Most volatile
2. Network connections and routing tables
3. Running processes and open files
4. Disk contents (file system)
5. Removable media
6. Logs and backup data - Least volatileMemory Acquisition:
# WinPMEM (Windows)
winpmem_mini_x64.exe memdump.raw
# FTK Imager - Create memory capture via GUI
# File → Capture Memory → Destination path → Capture Memory
# Linux (LiME kernel module)
sudo insmod lime.ko "path=/evidence/memory.lime format=lime"Volatile Data Collection:
# Capture running processes
Get-Process | Export-Csv "evidence\processes.csv" -NoTypeInformation
tasklist /v > "evidence\tasklist.txt"
# Capture network connections
netstat -anob > "evidence\netstat.txt"
Get-NetTCPConnection | Export-Csv "evidence\tcp_connections.csv"
# Capture logged-on users
query user > "evidence\logged_users.txt"
# Capture scheduled tasks
schtasks /query /fo CSV /v > "evidence\scheduled_tasks.csv"
# Capture services
Get-Service | Export-Csv "evidence\services.csv"
# Capture DNS cache
ipconfig /displaydns > "evidence\dns_cache.txt"Step 2: Disk Imaging
# FTK Imager - Create forensic disk image
# File → Create Disk Image → Physical Drive → E01 format
# Always verify image hash (MD5/SHA1) matches source
# dd (Linux)
sudo dc3dd if=/dev/sda of=/evidence/disk.dd hash=sha256 log=/evidence/imaging.log
# Verify image integrity
sha256sum /evidence/disk.dd
# Compare with hash generated during imagingStep 3: Memory Analysis with Volatility 3
# Identify OS profile
vol -f memdump.raw windows.info
# List running processes
vol -f memdump.raw windows.pslist
vol -f memdump.raw windows.pstree
# Find hidden processes
vol -f memdump.raw windows.psscan
# Analyze network connections
vol -f memdump.raw windows.netscan
# Detect process injection
vol -f memdump.raw windows.malfind
# Extract command line arguments
vol -f memdump.raw windows.cmdline
# Analyze DLLs loaded by processes
vol -f memdump.raw windows.dlllist --pid 1234
# Extract files from memory
vol -f memdump.raw windows.filescan | grep -i "suspicious"
vol -f memdump.raw windows.dumpfiles --pid 1234
# Detect credential theft
vol -f memdump.raw windows.hashdump
vol -f memdump.raw windows.lsadump
# Registry analysis from memory
vol -f memdump.raw windows.registry.printkey --key "Software\Microsoft\Windows\CurrentVersion\Run"Step 4: Windows Artifact Analysis
Key forensic artifacts and their tools:
Prefetch Files (C:\Windows\Prefetch\):
Tool: PECmd.exe (Eric Zimmerman)
Shows: Program execution history with timestamps and run counts
Command: PECmd.exe -d "C:\Windows\Prefetch" --csv output\
ShimCache (AppCompatCache):
Tool: AppCompatCacheParser.exe
Shows: Programs that existed on system (even if deleted)
Command: AppCompatCacheParser.exe -f SYSTEM --csv output\
AmCache (C:\Windows\appcompat\Programs\Amcache.hve):
Tool: AmcacheParser.exe
Shows: Program execution with SHA1 hashes and install timestamps
Command: AmcacheParser.exe -f Amcache.hve --csv output\
NTFS artifacts ($MFT, $UsnJrnl, $LogFile):
Tool: MFTECmd.exe
Shows: Complete file system timeline including deleted files
Command: MFTECmd.exe -f "$MFT" --csv output\
Event Logs:
Tool: EvtxECmd.exe
Shows: Security, System, PowerShell, Sysmon events
Command: EvtxECmd.exe -d "C:\Windows\System32\winevt\Logs" --csv output\
Registry Hives (SAM, SYSTEM, SOFTWARE, NTUSER.DAT):
Tool: RECmd.exe with batch files
Shows: User accounts, services, installed software, USB history
Command: RECmd.exe -d "C:\Windows\System32\config" --bn BatchExamples\RECmd_Batch_MC.reb --csv output\Step 5: Timeline Reconstruction
# Use KAPE for automated artifact collection
kape.exe --tsource C: --tdest C:\evidence\kape_output \
--target KapeTriage --module !EZParser
# Create super timeline with plaso/log2timeline
log2timeline.py timeline.plaso disk_image.E01
psort.py -o l2tcsv timeline.plaso -w timeline.csv
# Filter timeline around incident timeframe
psort.py -o l2tcsv timeline.plaso "date > '2026-02-20' AND date < '2026-02-22'" -w filtered_timeline.csvStep 6: Document Findings
Structure forensic report:
1. Executive Summary
2. Scope and Methodology
3. Evidence Inventory (with chain of custody)
4. Timeline of Events
5. Findings and Analysis
- Initial access vector
- Persistence mechanisms
- Lateral movement
- Data access/exfiltration
6. Indicators of Compromise (IOCs)
7. Recommendations
8. Appendices (tool output, hashes, raw evidence)Key Concepts
| Term | Definition |
|---|---|
| Order of Volatility | Evidence collection priority from most volatile (RAM) to least volatile (backups) |
| Chain of Custody | Documented record of evidence handling from collection to presentation |
| Write Blocker | Hardware or software device that prevents modification of source evidence |
| Super Timeline | Consolidated chronological view of all artifact timestamps for incident reconstruction |
| Prefetch | Windows artifact recording program execution history |
| ShimCache | Application compatibility artifact tracking program existence on endpoint |
Tools & Systems
- Volatility 3: Memory forensics framework for analyzing RAM dumps
- KAPE (Kroll Artifact Parser and Extractor): Automated triage collection and parsing
- Eric Zimmerman Tools: Suite of Windows artifact parsers (PECmd, MFTECmd, RECmd, etc.)
- Autopsy/Sleuth Kit: Disk forensics platform for file system analysis
- FTK Imager: Forensic imaging and memory acquisition tool
- Plaso/log2timeline: Super timeline creation framework
Common Pitfalls
- Modifying evidence on live system: Always image before analysis. Running tools on a live system alters timestamps and memory state.
- Forgetting chain of custody: Evidence without documented chain of custody is inadmissible in legal proceedings.
- Analyzing only disk, ignoring memory: In-memory-only malware (fileless attacks) leaves no disk artifacts. Always capture memory first.
- Not hashing evidence: All evidence must be cryptographically hashed at collection time to prove integrity.
- Tunnel vision: Focusing on one artifact when the timeline tells a broader story. Always build a comprehensive timeline.
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md6.6 KB
API Reference — Performing Endpoint Forensics Investigation
Libraries Used
| Library | Purpose |
|---|---|
subprocess |
Execute Windows forensic commands (wmic, netstat, reg, schtasks) |
hashlib |
Calculate MD5, SHA1, SHA256 hashes for evidence integrity |
csv |
Parse WMIC CSV output |
json |
Structure and export forensic triage results |
datetime |
Timestamp evidence collection |
argparse |
CLI argument parsing for triage modes |
CLI Interface
python agent.py triage # Full forensic triage
python agent.py processes # Running processes with PIDs and command lines
python agent.py network # Active network connections
python agent.py autoruns # Persistence entries
python agent.py hash --file <filepath> # Hash file for evidenceCore Functions
full_triage() — Run all collection functions
def full_triage():
"""Execute full forensic triage and return combined results."""
return {
"timestamp": datetime.now().isoformat(),
"hostname": collect_system_info()["hostname"],
"system_info": collect_system_info(),
"processes": collect_running_processes(),
"network": collect_network_connections(),
"autoruns": collect_autoruns(),
"users": collect_user_accounts(),
}collect_system_info() — Hostname, OS version, network config, uptime
def collect_system_info():
result = subprocess.run(
["systeminfo"], capture_output=True, text=True, timeout=60,
)
info = {}
for line in result.stdout.split("\n"):
if ":" in line:
key, _, val = line.partition(":")
info[key.strip()] = val.strip()
return {
"hostname": info.get("Host Name", ""),
"os_name": info.get("OS Name", ""),
"os_version": info.get("OS Version", ""),
"system_boot_time": info.get("System Boot Time", ""),
"total_physical_memory": info.get("Total Physical Memory", ""),
"domain": info.get("Domain", ""),
}collect_running_processes() — Process list via wmic process get
def collect_running_processes():
result = subprocess.run(
["wmic", "process", "get",
"ProcessId,Name,ExecutablePath,CommandLine,ParentProcessId",
"/format:csv"],
capture_output=True, text=True, timeout=30,
)
processes = []
reader = csv.DictReader(result.stdout.strip().split("\n"))
for row in reader:
if row.get("Name"):
processes.append({
"pid": row.get("ProcessId"),
"name": row.get("Name"),
"path": row.get("ExecutablePath", ""),
"cmdline": row.get("CommandLine", ""),
"ppid": row.get("ParentProcessId"),
})
return processescollect_network_connections() — Active connections via netstat -ano
def collect_network_connections():
result = subprocess.run(
["netstat", "-ano"], capture_output=True, text=True, timeout=15,
)
connections = []
for line in result.stdout.strip().split("\n")[4:]:
parts = line.split()
if len(parts) >= 5:
connections.append({
"proto": parts[0],
"local_address": parts[1],
"remote_address": parts[2],
"state": parts[3] if parts[3] != parts[-1] else "",
"pid": parts[-1],
})
return connectionscollect_autoruns() — Registry Run keys and scheduled tasks
RUN_KEYS = [
r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
r"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
r"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce",
]
def collect_autoruns():
autoruns = {"registry_run_keys": [], "scheduled_tasks": []}
for key in RUN_KEYS:
result = subprocess.run(
["reg", "query", key], capture_output=True, text=True, timeout=10,
)
for line in result.stdout.strip().split("\n"):
parts = line.strip().split(" ")
if len(parts) >= 3:
autoruns["registry_run_keys"].append({
"key": key,
"name": parts[0].strip(),
"value": parts[-1].strip(),
})
result = subprocess.run(
["schtasks", "/query", "/fo", "csv", "/v"],
capture_output=True, text=True, timeout=30,
)
reader = csv.DictReader(result.stdout.strip().split("\n"))
for row in reader:
if row.get("TaskName") and row.get("Status") == "Ready":
autoruns["scheduled_tasks"].append({
"name": row.get("TaskName"),
"next_run": row.get("Next Run Time"),
"task_to_run": row.get("Task To Run"),
"run_as_user": row.get("Run As User"),
})
return autorunscollect_user_accounts() — Local user enumeration
def collect_user_accounts():
result = subprocess.run(
["net", "user"], capture_output=True, text=True, timeout=10,
)
users = []
for line in result.stdout.strip().split("\n")[4:]:
for name in line.split():
if name and not name.startswith("-"):
users.append(name)
return usershash_file(filepath) — MD5/SHA1/SHA256 hash calculation
def hash_file(filepath):
"""Calculate cryptographic hashes for evidence integrity."""
md5 = hashlib.md5()
sha1 = hashlib.sha1()
sha256 = hashlib.sha256()
with open(filepath, "rb") as f:
while chunk := f.read(8192):
md5.update(chunk)
sha1.update(chunk)
sha256.update(chunk)
return {
"file": filepath,
"md5": md5.hexdigest(),
"sha1": sha1.hexdigest(),
"sha256": sha256.hexdigest(),
}Output Format
{
"timestamp": "2025-01-15T10:30:00",
"hostname": "WORKSTATION-01",
"system_info": {
"os_name": "Microsoft Windows 10 Pro",
"os_version": "10.0.19045",
"domain": "CORP"
},
"processes": [
{"pid": "4532", "name": "powershell.exe", "cmdline": "powershell -enc ..."}
],
"network": [
{"proto": "TCP", "local_address": "10.0.0.5:49721", "remote_address": "198.51.100.42:443", "state": "ESTABLISHED", "pid": "4532"}
],
"autoruns": {
"registry_run_keys": [
{"key": "HKCU\\...\\Run", "name": "WindowsUpdate", "value": "C:\\Users\\Public\\update.exe"}
],
"scheduled_tasks": 45
}
}Dependencies
No external packages — uses Windows built-in commands and Python standard library.
standards.md1.4 KB
Standards & References
Primary Standards
NIST SP 800-86 - Guide to Integrating Forensic Techniques
- Publisher: NIST
- Scope: Forensic process for digital evidence collection, examination, and analysis
ISO/IEC 27037 - Guidelines for Digital Evidence
- Publisher: ISO
- Scope: Identification, collection, acquisition, and preservation of digital evidence
RFC 3227 - Guidelines for Evidence Collection and Archiving
- Publisher: IETF
- Scope: Best practices for evidence collection including order of volatility
Compliance Mappings
| Framework | Requirement | Forensics Coverage |
|---|---|---|
| NIST 800-53 | IR-4 Incident Handling | Forensic investigation procedures |
| NIST 800-53 | AU-10 Non-repudiation | Evidence integrity via hashing |
| PCI DSS 4.0 | 12.10.5 - Incident response with forensics | Post-incident forensic analysis |
| HIPAA | 164.308(a)(6)(ii) - Response and Reporting | Forensic investigation of breaches |
Tool References
- Volatility 3: https://github.com/volatilityfoundation/volatility3
- KAPE: https://www.kroll.com/en/insights/publications/cyber/kroll-artifact-parser-extractor-kape
- Eric Zimmerman Tools: https://ericzimmerman.github.io/
- Autopsy: https://www.autopsy.com/
- SANS Windows Forensic Analysis Poster: https://www.sans.org/posters/
workflows.md1.5 KB
Workflows
Workflow 1: Endpoint Forensic Investigation
[Incident Detected / Investigation Authorized]
│
▼
[Preserve Evidence (Order of Volatility)]
│
├── 1. Capture memory (WinPMEM/FTK Imager)
├── 2. Capture volatile data (processes, network, users)
├── 3. Create forensic disk image (E01/dd)
├── 4. Hash all evidence, document chain of custody
│
▼
[Analysis Phase]
│
├── Memory analysis (Volatility 3)
├── Artifact parsing (KAPE + EZ tools)
├── Timeline reconstruction (plaso)
├── Malware analysis (if samples found)
│
▼
[Correlate Findings]
│
├── Initial access vector identified
├── Persistence mechanisms documented
├── Scope of compromise determined
│
▼
[Generate IOCs and Report]
│
▼
[Handoff to Remediation Team]Workflow 2: Memory Analysis
[Memory dump acquired]
│
▼
[Identify OS profile: vol windows.info]
│
▼
[Process analysis: pslist → pstree → psscan]
│
├── Hidden processes found ──► [Analyze with malfind, dlllist]
│
▼
[Network analysis: netscan]
│
├── Suspicious connections ──► [Extract IOCs (IPs, domains)]
│
▼
[Injection detection: malfind]
│
├── Injected code found ──► [Dump and analyze with YARA]
│
▼
[Credential analysis: hashdump, lsadump]
│
▼
[Document all findings with screenshots and hashes]Scripts 2
agent.py5.6 KB
#!/usr/bin/env python3
"""Agent for performing endpoint forensics investigation on Windows systems."""
import json
import argparse
import subprocess
import os
import hashlib
from datetime import datetime
def collect_system_info():
"""Collect basic system information for forensic context."""
info = {}
commands = {
"hostname": ["hostname"],
"os_version": ["wmic", "os", "get", "Caption,Version,BuildNumber", "/format:list"],
"network_config": ["ipconfig", "/all"],
"logged_users": ["query", "user"],
"uptime": ["wmic", "os", "get", "LastBootUpTime", "/format:list"],
}
for key, cmd in commands.items():
try:
result = subprocess.run(cmd, capture_output=True, text=True, timeout=10)
info[key] = result.stdout.strip()[:1000]
except Exception as e:
info[key] = f"Error: {e}"
return {"timestamp": datetime.utcnow().isoformat(), "system_info": info}
def collect_running_processes():
"""Collect running processes with parent PIDs and command lines."""
try:
result = subprocess.run(
["wmic", "process", "get", "Name,ProcessId,ParentProcessId,CommandLine,ExecutablePath", "/format:csv"],
capture_output=True, text=True, timeout=30
)
except Exception as e:
return {"error": str(e)}
import csv
from io import StringIO
processes = []
reader = csv.DictReader(StringIO(result.stdout))
for row in reader:
if row.get("Name"):
processes.append({
"name": row.get("Name", ""),
"pid": row.get("ProcessId", ""),
"ppid": row.get("ParentProcessId", ""),
"path": row.get("ExecutablePath", ""),
"cmdline": row.get("CommandLine", "")[:500],
})
return {"total": len(processes), "processes": processes}
def collect_network_connections():
"""Collect active network connections."""
try:
result = subprocess.run(
["netstat", "-ano"], capture_output=True, text=True, timeout=15
)
except Exception as e:
return {"error": str(e)}
connections = []
for line in result.stdout.split("\n")[4:]:
parts = line.split()
if len(parts) >= 5:
connections.append({
"protocol": parts[0],
"local_addr": parts[1],
"remote_addr": parts[2],
"state": parts[3] if len(parts) > 4 else "",
"pid": parts[-1],
})
established = [c for c in connections if c.get("state") == "ESTABLISHED"]
listening = [c for c in connections if c.get("state") == "LISTENING"]
return {
"total": len(connections),
"established": len(established),
"listening": len(listening),
"connections": connections,
}
def collect_autoruns():
"""Collect common persistence locations."""
autoruns = {}
reg_keys = [
r"HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
r"HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Run",
]
for key in reg_keys:
try:
result = subprocess.run(["reg", "query", key], capture_output=True, text=True, timeout=10)
autoruns[key] = result.stdout.strip()[:1000]
except Exception:
continue
try:
result = subprocess.run(["schtasks", "/query", "/fo", "CSV"], capture_output=True, text=True, timeout=30)
autoruns["scheduled_tasks_count"] = result.stdout.count("\n") - 1
except Exception:
pass
return autoruns
def hash_file(filepath):
"""Calculate MD5, SHA1, SHA256 hashes of a file for evidence integrity."""
hashes = {}
algos = {"md5": hashlib.md5(), "sha1": hashlib.sha1(), "sha256": hashlib.sha256()}
try:
with open(filepath, "rb") as f:
while True:
chunk = f.read(8192)
if not chunk:
break
for algo in algos.values():
algo.update(chunk)
for name, algo in algos.items():
hashes[name] = algo.hexdigest()
hashes["file"] = str(filepath)
hashes["size"] = os.path.getsize(filepath)
except Exception as e:
hashes["error"] = str(e)
return hashes
def full_triage():
"""Run full endpoint forensic triage collection."""
return {
"timestamp": datetime.utcnow().isoformat(),
"system_info": collect_system_info(),
"processes": collect_running_processes(),
"network": collect_network_connections(),
"autoruns": collect_autoruns(),
}
def main():
parser = argparse.ArgumentParser(description="Endpoint Forensics Investigation Agent")
sub = parser.add_subparsers(dest="command")
sub.add_parser("triage", help="Full forensic triage collection")
sub.add_parser("processes", help="Collect running processes")
sub.add_parser("network", help="Collect network connections")
sub.add_parser("autoruns", help="Collect autorun/persistence entries")
h = sub.add_parser("hash", help="Hash a file for evidence")
h.add_argument("--file", required=True)
args = parser.parse_args()
if args.command == "triage":
result = full_triage()
elif args.command == "processes":
result = collect_running_processes()
elif args.command == "network":
result = collect_network_connections()
elif args.command == "autoruns":
result = collect_autoruns()
elif args.command == "hash":
result = hash_file(args.file)
else:
parser.print_help()
return
print(json.dumps(result, indent=2, default=str))
if __name__ == "__main__":
main()
process.py7.0 KB
#!/usr/bin/env python3
"""
Forensic Evidence Processor
Parses and correlates forensic artifacts from KAPE/EZ tool output
to generate consolidated timeline and IOC reports.
"""
import json
import csv
import sys
import os
from datetime import datetime
from collections import defaultdict
def parse_prefetch_csv(csv_path: str) -> list:
"""Parse PECmd output for program execution history."""
entries = []
with open(csv_path, "r", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
for row in reader:
entries.append({
"artifact": "prefetch",
"timestamp": row.get("LastRun", ""),
"executable": row.get("ExecutableName", ""),
"run_count": row.get("RunCount", ""),
"path": row.get("SourceFilename", ""),
"hash": row.get("Hash", ""),
"volume": row.get("Volume0Name", ""),
})
return entries
def parse_shimcache_csv(csv_path: str) -> list:
"""Parse AppCompatCacheParser output."""
entries = []
with open(csv_path, "r", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
for row in reader:
entries.append({
"artifact": "shimcache",
"timestamp": row.get("LastModifiedTimeUTC", ""),
"path": row.get("Path", ""),
"executed": row.get("Executed", ""),
})
return entries
def parse_amcache_csv(csv_path: str) -> list:
"""Parse AmcacheParser output for installed programs."""
entries = []
with open(csv_path, "r", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
for row in reader:
entries.append({
"artifact": "amcache",
"timestamp": row.get("FileKeyLastWriteTimestamp", ""),
"path": row.get("FullPath", row.get("Name", "")),
"sha1": row.get("SHA1", ""),
"publisher": row.get("Publisher", ""),
"product": row.get("ProductName", ""),
})
return entries
def parse_mft_csv(csv_path: str) -> list:
"""Parse MFTECmd output for file system timeline."""
entries = []
with open(csv_path, "r", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
for row in reader:
entries.append({
"artifact": "mft",
"timestamp_created": row.get("Created0x10", ""),
"timestamp_modified": row.get("LastModified0x10", ""),
"path": row.get("ParentPath", "") + "\\" + row.get("FileName", ""),
"size": row.get("FileSize", ""),
"in_use": row.get("InUse", ""),
"is_directory": row.get("IsDirectory", ""),
})
return entries
def build_timeline(all_entries: list) -> list:
"""Build consolidated timeline from all artifact sources."""
timeline = []
for entry in all_entries:
ts = ""
for key in ["timestamp", "timestamp_created", "timestamp_modified"]:
if entry.get(key):
ts = entry[key]
break
if ts:
timeline.append({
"timestamp": ts,
"artifact": entry.get("artifact", "unknown"),
"description": entry.get("path", entry.get("executable", "")),
"details": {k: v for k, v in entry.items()
if k not in ("timestamp", "artifact")},
})
timeline.sort(key=lambda x: x["timestamp"])
return timeline
def extract_iocs(all_entries: list) -> dict:
"""Extract potential IOCs from forensic artifacts."""
iocs = {
"file_hashes": set(),
"suspicious_paths": [],
"executables": set(),
}
suspicious_dirs = [
"\\temp\\", "\\tmp\\", "\\appdata\\local\\temp\\",
"\\users\\public\\", "\\programdata\\",
"\\recycle", "\\windows\\debug\\",
]
for entry in all_entries:
for hash_key in ["hash", "sha1", "md5"]:
h = entry.get(hash_key, "")
if h and len(h) >= 32:
iocs["file_hashes"].add(h)
path = entry.get("path", "").lower()
if any(d in path for d in suspicious_dirs):
if path.endswith((".exe", ".dll", ".ps1", ".bat", ".vbs", ".js")):
iocs["suspicious_paths"].append({
"path": entry.get("path", ""),
"artifact": entry.get("artifact", ""),
"timestamp": entry.get("timestamp", ""),
})
exe = entry.get("executable", "")
if exe:
iocs["executables"].add(exe)
iocs["file_hashes"] = sorted(iocs["file_hashes"])
iocs["executables"] = sorted(iocs["executables"])
return iocs
def generate_report(timeline: list, iocs: dict, output_path: str) -> None:
"""Generate forensic analysis report."""
report = {
"report_generated": datetime.utcnow().isoformat() + "Z",
"timeline_entries": len(timeline),
"iocs": {
"file_hashes": iocs["file_hashes"][:100],
"suspicious_files": iocs["suspicious_paths"][:50],
"unique_executables": len(iocs["executables"]),
},
"timeline_sample": timeline[:100],
}
with open(output_path, "w", encoding="utf-8") as f:
json.dump(report, f, indent=2)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: python process.py <kape_output_directory>")
print()
print("Parses KAPE/EZ tool CSV output and generates timeline + IOC report.")
sys.exit(1)
kape_dir = sys.argv[1]
if not os.path.isdir(kape_dir):
print(f"Error: Directory not found: {kape_dir}")
sys.exit(1)
all_entries = []
for root, dirs, files in os.walk(kape_dir):
for f in files:
if not f.endswith(".csv"):
continue
path = os.path.join(root, f)
fl = f.lower()
try:
if "prefetch" in fl or "pecmd" in fl:
all_entries.extend(parse_prefetch_csv(path))
elif "shimcache" in fl or "appcompat" in fl:
all_entries.extend(parse_shimcache_csv(path))
elif "amcache" in fl:
all_entries.extend(parse_amcache_csv(path))
elif "mft" in fl:
all_entries.extend(parse_mft_csv(path))
except Exception as e:
print(f"Warning: Could not parse {path}: {e}")
print(f"Parsed {len(all_entries)} artifact entries")
timeline = build_timeline(all_entries)
iocs = extract_iocs(all_entries)
report_path = os.path.join(kape_dir, "forensic_analysis.json")
generate_report(timeline, iocs, report_path)
print(f"Forensic report: {report_path}")
print(f"\n--- Forensic Summary ---")
print(f"Timeline entries: {len(timeline)}")
print(f"Unique file hashes: {len(iocs['file_hashes'])}")
print(f"Suspicious file paths: {len(iocs['suspicious_paths'])}")
print(f"Unique executables: {len(iocs['executables'])}")