endpoint security

Performing Endpoint Forensics Investigation

Performs digital forensics investigation on compromised endpoints including memory acquisition, disk imaging, artifact analysis, and timeline reconstruction. Use when investigating security incidents, collecting evidence for legal proceedings, or analyzing endpoint compromise scope. Activates for requests involving endpoint forensics, memory analysis, disk forensics, or incident investigation.

disk-imagingendpointforensicsincident-investigationmemory-analysisvolatility
Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-Skills
Framework mappings

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 volatile

Memory 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 imaging

Step 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.csv

Step 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.
Source materials

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 evidence

Core 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 processes

collect_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 connections

collect_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 autoruns

collect_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 users

hash_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

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
Display-only source. This catalog never executes bundled scripts.
#!/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
Display-only source. This catalog never executes bundled scripts.
#!/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'])}")

Assets 1

template.mdtext/markdown · 1.1 KB
Keep exploring