mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-06-12 22:24: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
166 lines
5.6 KiB
Python
166 lines
5.6 KiB
Python
#!/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()
|