#!/usr/bin/env python3 """Autoruns Persistence Analysis Agent - Analyzes Windows autostart entries for malware persistence.""" import json import csv import re import logging import argparse from datetime import datetime from collections import Counter logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s") logger = logging.getLogger(__name__) SUSPICIOUS_PATHS = [ r"\\temp\\", r"\\tmp\\", r"\\appdata\\local\\temp", r"\\public\\", r"\\programdata\\", r"\\users\\default", r"\\recycler\\", r"\\windows\\debug", ] SUSPICIOUS_COMMANDS = [ "powershell", "cmd.exe /c", "wscript", "cscript", "mshta", "regsvr32", "rundll32", "certutil", "bitsadmin", "schtasks", "msiexec /q", "forfiles", ] KNOWN_PERSISTENCE_LOCATIONS = [ "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", "HKCU\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce", "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", "HKLM\\SYSTEM\\CurrentControlSet\\Services", "Task Scheduler", "Startup Folder", "WMI", ] def parse_autoruns_csv(csv_file): """Parse Autoruns CSV export file.""" entries = [] with open(csv_file, "r", encoding="utf-8-sig", errors="ignore") as f: reader = csv.DictReader(f, delimiter=",") for row in reader: entries.append({ "time": row.get("Time", ""), "entry_location": row.get("Entry Location", ""), "entry": row.get("Entry", ""), "enabled": row.get("Enabled", ""), "category": row.get("Category", ""), "profile": row.get("Profile", ""), "description": row.get("Description", ""), "company": row.get("Company", ""), "image_path": row.get("Image Path", ""), "version": row.get("Version", ""), "launch_string": row.get("Launch String", ""), "md5": row.get("MD5", ""), "sha1": row.get("SHA-1", ""), "sha256": row.get("SHA-256", ""), "signer": row.get("Signer", ""), "vt_detection": row.get("VT detection", ""), }) logger.info("Parsed %d autoruns entries from %s", len(entries), csv_file) return entries def analyze_entry(entry): """Analyze a single autoruns entry for suspicious indicators.""" findings = [] image_path = (entry.get("image_path") or "").lower() launch_string = (entry.get("launch_string") or "").lower() signer = entry.get("signer") or "" vt = entry.get("vt_detection") or "" company = entry.get("company") or "" for pattern in SUSPICIOUS_PATHS: if re.search(pattern, image_path, re.IGNORECASE): findings.append({"type": "Suspicious file path", "severity": "high", "detail": image_path}) break for cmd in SUSPICIOUS_COMMANDS: if cmd.lower() in launch_string: findings.append({"type": "LOLBin in launch string", "severity": "high", "detail": cmd}) break if signer in ("(Not verified)", "") or "(Not verified)" in signer: findings.append({"type": "Unsigned binary", "severity": "medium", "detail": signer}) if vt and "/" in vt: try: detections, total = vt.split("/") if int(detections.strip()) > 0: findings.append({"type": "VirusTotal detections", "severity": "critical", "detail": vt}) except (ValueError, AttributeError): pass if not company and entry.get("enabled") == "enabled": findings.append({"type": "No company info", "severity": "low", "detail": "Enabled entry without publisher"}) return findings def analyze_all_entries(entries): """Analyze all autoruns entries and generate findings.""" all_findings = [] for entry in entries: entry_findings = analyze_entry(entry) if entry_findings: all_findings.append({ "entry": entry.get("entry"), "location": entry.get("entry_location"), "category": entry.get("category"), "image_path": entry.get("image_path"), "findings": entry_findings, "max_severity": max((f["severity"] for f in entry_findings), key=lambda s: {"critical": 4, "high": 3, "medium": 2, "low": 1}.get(s, 0)), }) return all_findings def generate_report(entries, findings): """Generate persistence analysis report.""" categories = Counter(e.get("category", "Unknown") for e in entries) critical = [f for f in findings if f["max_severity"] == "critical"] report = { "timestamp": datetime.utcnow().isoformat(), "total_entries": len(entries), "enabled_entries": len([e for e in entries if e.get("enabled") == "enabled"]), "suspicious_entries": len(findings), "critical_entries": len(critical), "category_breakdown": dict(categories.most_common()), "findings": findings, } print(f"AUTORUNS REPORT: {len(entries)} entries, {len(findings)} suspicious, {len(critical)} critical") return report def main(): parser = argparse.ArgumentParser(description="Autoruns Persistence Analysis Agent") parser.add_argument("--csv-file", required=True, help="Autoruns CSV export file") parser.add_argument("--output", default="autoruns_report.json") args = parser.parse_args() entries = parse_autoruns_csv(args.csv_file) findings = analyze_all_entries(entries) report = generate_report(entries, findings) with open(args.output, "w") as f: json.dump(report, f, indent=2) logger.info("Report saved to %s", args.output) if __name__ == "__main__": main()