mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-11 21:54:56 +03:00
c47eed6a64
- Fix 25 shell=True subprocess calls with list-based commands - Fix 49 verify=False in defensive skills (env-var override) - Add timeout to 231 HTTP/subprocess/socket calls - Fix 6 SQL injection patterns with whitelist validation - Replace 8 __import__() with standard imports - Remove 701 unused imports across 442 files - Add authorized-testing disclaimers to all offensive skills - Complete 11 incomplete skill directories - Expand 10 stub SKILL.md files with full content - Fix 2 YAML parse errors in frontmatter - Fix 5 pre-existing syntax errors - Convert 22 hardcoded paths/ports to environment variables - Back up 21 redundant skill pairs to .bak - Fix 2 global declaration errors - 724/724 skills with full folder anatomy (SKILL.md + agent.py + api-reference.md + LICENSE) - 0 compile errors across all 724 agent.py files
216 lines
8.0 KiB
Python
216 lines
8.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Windows Prefetch file analysis agent for program execution history forensics."""
|
|
|
|
import struct
|
|
import os
|
|
import sys
|
|
import datetime
|
|
import json
|
|
import glob
|
|
|
|
|
|
def parse_prefetch_header(filepath):
|
|
"""Parse the Prefetch file header to extract execution metadata."""
|
|
with open(filepath, "rb") as f:
|
|
data = f.read()
|
|
|
|
# Check for compression (Windows 10 prefetch files are MAM compressed)
|
|
if data[:4] == b"MAM\x04":
|
|
# Windows 10 compressed format - need decompression
|
|
return {"error": "Compressed prefetch (Windows 10 MAM format) - use PECmd for full parsing",
|
|
"compressed": True, "raw_size": len(data)}
|
|
|
|
# Standard prefetch header (versions 17, 23, 26, 30)
|
|
if len(data) < 84:
|
|
return {"error": "File too small to be a valid prefetch file"}
|
|
|
|
version = struct.unpack_from("<I", data, 0)[0]
|
|
signature = data[4:8]
|
|
|
|
if signature != b"SCCA":
|
|
return {"error": f"Invalid signature: {signature.hex()} (expected 53434341)"}
|
|
|
|
file_size = struct.unpack_from("<I", data, 12)[0]
|
|
exe_name = data[16:76].decode("utf-16-le", errors="replace").rstrip("\x00")
|
|
hash_value = struct.unpack_from("<I", data, 76)[0]
|
|
|
|
result = {
|
|
"version": version,
|
|
"signature": signature.hex(),
|
|
"file_size": file_size,
|
|
"executable_name": exe_name,
|
|
"prefetch_hash": f"0x{hash_value:08X}",
|
|
}
|
|
|
|
# Version-specific parsing
|
|
if version == 17: # Windows XP
|
|
result["format"] = "Windows XP"
|
|
run_count = struct.unpack_from("<I", data, 144)[0]
|
|
last_run = parse_filetime(struct.unpack_from("<Q", data, 120)[0])
|
|
result["run_count"] = run_count
|
|
result["last_run_time"] = last_run
|
|
elif version == 23: # Windows Vista/7
|
|
result["format"] = "Windows Vista/7"
|
|
run_count = struct.unpack_from("<I", data, 152)[0]
|
|
last_run = parse_filetime(struct.unpack_from("<Q", data, 128)[0])
|
|
result["run_count"] = run_count
|
|
result["last_run_time"] = last_run
|
|
elif version == 26: # Windows 8/8.1
|
|
result["format"] = "Windows 8/8.1"
|
|
run_count = struct.unpack_from("<I", data, 208)[0]
|
|
last_run = parse_filetime(struct.unpack_from("<Q", data, 128)[0])
|
|
result["run_count"] = run_count
|
|
result["last_run_time"] = last_run
|
|
elif version == 30: # Windows 10/11
|
|
result["format"] = "Windows 10/11"
|
|
result["note"] = "Use PECmd.exe for full Windows 10 prefetch parsing"
|
|
else:
|
|
result["format"] = f"Unknown version {version}"
|
|
|
|
return result
|
|
|
|
|
|
def parse_filetime(filetime):
|
|
"""Convert Windows FILETIME (100ns intervals since 1601-01-01) to ISO string."""
|
|
if filetime == 0:
|
|
return "N/A"
|
|
try:
|
|
epoch = datetime.datetime(1601, 1, 1)
|
|
delta = datetime.timedelta(microseconds=filetime // 10)
|
|
dt = epoch + delta
|
|
return dt.isoformat() + "Z"
|
|
except (OverflowError, OSError):
|
|
return "Invalid timestamp"
|
|
|
|
|
|
def parse_prefetch_filename(filename):
|
|
"""Parse executable name and hash from prefetch filename format: APPNAME-HASH.pf."""
|
|
basename = os.path.basename(filename)
|
|
if not basename.upper().endswith(".PF"):
|
|
return None, None
|
|
name_part = basename[:-3] # Remove .pf
|
|
parts = name_part.rsplit("-", 1)
|
|
if len(parts) == 2:
|
|
return parts[0], parts[1]
|
|
return name_part, None
|
|
|
|
|
|
def scan_prefetch_directory(prefetch_dir):
|
|
"""Scan a directory of prefetch files and extract execution history."""
|
|
results = []
|
|
pf_files = glob.glob(os.path.join(prefetch_dir, "*.pf"))
|
|
pf_files.extend(glob.glob(os.path.join(prefetch_dir, "*.PF")))
|
|
|
|
for pf_file in sorted(set(pf_files)):
|
|
exe_name, pf_hash = parse_prefetch_filename(pf_file)
|
|
header = parse_prefetch_header(pf_file)
|
|
results.append({
|
|
"file": os.path.basename(pf_file),
|
|
"parsed_name": exe_name,
|
|
"parsed_hash": pf_hash,
|
|
"file_modified": datetime.datetime.fromtimestamp(
|
|
os.path.getmtime(pf_file)).isoformat(),
|
|
"header": header,
|
|
})
|
|
return results
|
|
|
|
|
|
SUSPICIOUS_EXECUTABLES = [
|
|
"MIMIKATZ", "PSEXEC", "WMIC", "PROCDUMP", "RUBEUS", "SEATBELT",
|
|
"BLOODHOUND", "SHARPHOUND", "LAZAGNE", "SECRETSDUMP", "NTDSUTIL",
|
|
"CERTUTIL", "BITSADMIN", "MSHTA", "REGSVR32", "RUNDLL32",
|
|
"CSCRIPT", "WSCRIPT", "POWERSHELL", "CMD", "MSBUILD",
|
|
"INSTALLUTIL", "REGASM", "REGSVCS", "XWIZARD",
|
|
"NETCAT", "NCAT", "NC", "NMAP", "MASSCAN",
|
|
"RAR", "7Z", "WINRAR", "RCLONE",
|
|
]
|
|
|
|
|
|
def detect_suspicious_execution(prefetch_results):
|
|
"""Flag suspicious or known-attacker-tool prefetch files."""
|
|
findings = []
|
|
for result in prefetch_results:
|
|
name = (result.get("parsed_name") or "").upper()
|
|
for sus in SUSPICIOUS_EXECUTABLES:
|
|
if sus in name:
|
|
findings.append({
|
|
"severity": "HIGH",
|
|
"executable": result.get("parsed_name"),
|
|
"file": result.get("file"),
|
|
"reason": f"Known offensive/dual-use tool: {sus}",
|
|
"run_count": result.get("header", {}).get("run_count"),
|
|
"last_run": result.get("header", {}).get("last_run_time"),
|
|
})
|
|
break
|
|
return findings
|
|
|
|
|
|
def build_execution_timeline(prefetch_results):
|
|
"""Build a chronological timeline of program execution."""
|
|
timeline = []
|
|
for result in prefetch_results:
|
|
header = result.get("header", {})
|
|
last_run = header.get("last_run_time")
|
|
if last_run and last_run not in ("N/A", "Invalid timestamp"):
|
|
timeline.append({
|
|
"timestamp": last_run,
|
|
"executable": result.get("parsed_name"),
|
|
"run_count": header.get("run_count"),
|
|
"prefetch_file": result.get("file"),
|
|
})
|
|
return sorted(timeline, key=lambda x: x["timestamp"])
|
|
|
|
|
|
def run_pecmd(prefetch_path, output_dir=None):
|
|
"""Run Eric Zimmerman's PECmd for comprehensive prefetch parsing."""
|
|
import subprocess
|
|
cmd = ["PECmd.exe", "-f", prefetch_path]
|
|
if output_dir:
|
|
cmd += ["--csv", output_dir]
|
|
result = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
|
return result.stdout, result.returncode
|
|
|
|
|
|
if __name__ == "__main__":
|
|
print("=" * 60)
|
|
print("Windows Prefetch File Analysis Agent")
|
|
print("Execution history, timeline building, suspicious tool detection")
|
|
print("=" * 60)
|
|
|
|
target = sys.argv[1] if len(sys.argv) > 1 else None
|
|
|
|
if target and os.path.exists(target):
|
|
if os.path.isdir(target):
|
|
print(f"\n[*] Scanning prefetch directory: {target}")
|
|
results = scan_prefetch_directory(target)
|
|
print(f"[*] Found {len(results)} prefetch files")
|
|
|
|
print("\n--- Execution History ---")
|
|
for r in results[:20]:
|
|
header = r.get("header", {})
|
|
name = r.get("parsed_name", "?")
|
|
count = header.get("run_count", "?")
|
|
last = header.get("last_run_time", "?")
|
|
print(f" {name:30s} runs={count} last={last}")
|
|
|
|
print("\n--- Suspicious Executables ---")
|
|
suspicious = detect_suspicious_execution(results)
|
|
for s in suspicious:
|
|
print(f" [!] {s['executable']}: {s['reason']} "
|
|
f"(runs={s['run_count']}, last={s['last_run']})")
|
|
|
|
print("\n--- Execution Timeline ---")
|
|
timeline = build_execution_timeline(results)
|
|
for t in timeline[-20:]:
|
|
print(f" {t['timestamp']} | {t['executable']} (x{t['run_count']})")
|
|
else:
|
|
print(f"\n[*] Analyzing: {target}")
|
|
exe_name, pf_hash = parse_prefetch_filename(target)
|
|
print(f" Name: {exe_name}, Hash: {pf_hash}")
|
|
header = parse_prefetch_header(target)
|
|
print(f" {json.dumps(header, indent=2)}")
|
|
else:
|
|
print(f"\n[DEMO] Usage:")
|
|
print(f" python agent.py <prefetch_dir> # Analyze all .pf files")
|
|
print(f" python agent.py <file.pf> # Analyze single prefetch file")
|