mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-15 23:44:56 +03:00
feat: add 5 new cybersecurity skills - yara hunting, devsecops scanning, amcache, LOtL, privileged session monitoring
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Windows Amcache.hve forensic analysis agent.
|
||||
|
||||
Parses Amcache.hve registry hive to extract program execution history,
|
||||
file metadata, and device information using the regipy library.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import datetime
|
||||
import struct
|
||||
|
||||
try:
|
||||
from regipy.registry import RegistryHive
|
||||
HAS_REGIPY = True
|
||||
except ImportError:
|
||||
HAS_REGIPY = False
|
||||
|
||||
|
||||
AMCACHE_FILE_KEY = "Root\InventoryApplicationFile"
|
||||
AMCACHE_APP_KEY = "Root\InventoryApplication"
|
||||
AMCACHE_DEVICE_KEY = "Root\InventoryDevicePnp"
|
||||
AMCACHE_DRIVER_KEY = "Root\InventoryDriverBinary"
|
||||
|
||||
SUSPICIOUS_PATHS = [
|
||||
"\\temp\\", "\\tmp\\", "\\appdata\\local\\temp",
|
||||
"\\downloads\\", "\\public\\", "\\programdata\\",
|
||||
"\\recycle", "\\users\\public",
|
||||
]
|
||||
|
||||
SUSPICIOUS_NAMES = [
|
||||
"mimikatz", "psexec", "lazagne", "procdump", "rubeus",
|
||||
"sharphound", "bloodhound", "cobalt", "beacon",
|
||||
"powershell_ise", "certutil", "mshta",
|
||||
]
|
||||
|
||||
|
||||
def parse_amcache_files(hive_path):
|
||||
"""Parse InventoryApplicationFile entries from Amcache.hve."""
|
||||
if not HAS_REGIPY:
|
||||
return {"error": "regipy not installed. pip install regipy"}
|
||||
try:
|
||||
reg = RegistryHive(hive_path)
|
||||
entries = []
|
||||
for subkey in reg.get_key(AMCACHE_FILE_KEY).iter_subkeys():
|
||||
values = {v.name: v.value for v in subkey.iter_values()}
|
||||
entries.append({
|
||||
"name": values.get("Name", ""),
|
||||
"lower_case_path": values.get("LowerCaseLongPath", ""),
|
||||
"publisher": values.get("Publisher", ""),
|
||||
"version": values.get("Version", ""),
|
||||
"sha1": values.get("FileId", "").lstrip("0000").lower() if values.get("FileId") else "",
|
||||
"size": values.get("Size", 0),
|
||||
"link_date": values.get("LinkDate", ""),
|
||||
"program_id": values.get("ProgramId", ""),
|
||||
"last_modified": subkey.header.last_modified.isoformat() if subkey.header.last_modified else "",
|
||||
})
|
||||
return entries
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
def parse_amcache_apps(hive_path):
|
||||
"""Parse InventoryApplication entries."""
|
||||
if not HAS_REGIPY:
|
||||
return {"error": "regipy not installed"}
|
||||
try:
|
||||
reg = RegistryHive(hive_path)
|
||||
apps = []
|
||||
for subkey in reg.get_key(AMCACHE_APP_KEY).iter_subkeys():
|
||||
values = {v.name: v.value for v in subkey.iter_values()}
|
||||
apps.append({
|
||||
"name": values.get("Name", ""),
|
||||
"version": values.get("Version", ""),
|
||||
"publisher": values.get("Publisher", ""),
|
||||
"install_date": values.get("InstallDate", ""),
|
||||
"source": values.get("Source", ""),
|
||||
"uninstall_string": values.get("UninstallString", ""),
|
||||
"registry_key_path": values.get("RegistryKeyPath", ""),
|
||||
})
|
||||
return apps
|
||||
except Exception as e:
|
||||
return {"error": str(e)}
|
||||
|
||||
|
||||
def detect_suspicious(entries):
|
||||
"""Flag suspicious entries based on path and name patterns."""
|
||||
findings = []
|
||||
for entry in entries:
|
||||
if isinstance(entry, dict) and "error" not in entry:
|
||||
path = entry.get("lower_case_path", "").lower()
|
||||
name = entry.get("name", "").lower()
|
||||
reasons = []
|
||||
for sp in SUSPICIOUS_PATHS:
|
||||
if sp in path:
|
||||
reasons.append(f"Suspicious path: {sp}")
|
||||
for sn in SUSPICIOUS_NAMES:
|
||||
if sn in name:
|
||||
reasons.append(f"Suspicious name: {sn}")
|
||||
if not entry.get("publisher"):
|
||||
reasons.append("Missing publisher metadata")
|
||||
if reasons:
|
||||
findings.append({
|
||||
"name": entry.get("name", ""),
|
||||
"path": entry.get("lower_case_path", ""),
|
||||
"sha1": entry.get("sha1", ""),
|
||||
"reasons": reasons,
|
||||
})
|
||||
return findings
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="Amcache.hve forensic analysis agent")
|
||||
parser.add_argument("hive", nargs="?", help="Path to Amcache.hve file")
|
||||
parser.add_argument("--apps", action="store_true", help="Parse InventoryApplication entries")
|
||||
parser.add_argument("--suspicious-only", action="store_true", help="Show only suspicious entries")
|
||||
parser.add_argument("--output", "-o", help="Output JSON report path")
|
||||
args = parser.parse_args()
|
||||
|
||||
print("[*] Amcache.hve Forensic Analysis Agent")
|
||||
print(f" regipy available: {HAS_REGIPY}")
|
||||
|
||||
if not args.hive:
|
||||
print("\n[DEMO] Amcache.hve location: C:\\Windows\\AppCompat\\Programs\\Amcache.hve")
|
||||
print(" Usage: python agent.py Amcache.hve [--apps] [--suspicious-only]")
|
||||
print(" Extracts: file paths, SHA-1 hashes, publisher, timestamps, install info")
|
||||
print(json.dumps({"demo": True, "regipy_available": HAS_REGIPY}, indent=2))
|
||||
sys.exit(0)
|
||||
|
||||
report = {"timestamp": datetime.datetime.utcnow().isoformat() + "Z", "hive": args.hive}
|
||||
|
||||
files = parse_amcache_files(args.hive)
|
||||
if isinstance(files, list):
|
||||
report["file_entries"] = len(files)
|
||||
suspicious = detect_suspicious(files)
|
||||
report["suspicious_count"] = len(suspicious)
|
||||
if args.suspicious_only:
|
||||
report["findings"] = suspicious
|
||||
else:
|
||||
report["entries"] = files[:100]
|
||||
report["suspicious"] = suspicious
|
||||
print(f"[*] File entries: {len(files)}")
|
||||
print(f"[*] Suspicious: {len(suspicious)}")
|
||||
for s in suspicious[:10]:
|
||||
print(f" [!] {s['name']}: {', '.join(s['reasons'])}")
|
||||
else:
|
||||
report["error"] = files
|
||||
|
||||
if args.apps:
|
||||
apps = parse_amcache_apps(args.hive)
|
||||
if isinstance(apps, list):
|
||||
report["app_entries"] = len(apps)
|
||||
print(f"[*] Application entries: {len(apps)}")
|
||||
|
||||
if args.output:
|
||||
with open(args.output, "w") as f:
|
||||
json.dump(report, f, indent=2, default=str)
|
||||
|
||||
print(json.dumps({"file_entries": report.get("file_entries", 0),
|
||||
"suspicious": report.get("suspicious_count", 0)}, indent=2))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user