npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
NIST CSF 2.0
MITRE D3FEND
Overview
Sysinternals Autoruns extracts data from hundreds of Auto-Start Extensibility Points (ASEPs) on Windows, scanning 18+ categories including Run/RunOnce keys, services, scheduled tasks, drivers, Winlogon entries, LSA providers, print monitors, WMI subscriptions, and AppInit DLLs. Digital signature verification filters Microsoft-signed entries. The compare function identifies newly added persistence via baseline diffing. VirusTotal integration checks hash reputation. Offline analysis via -z flag enables forensic disk image examination.
When to Use
- When investigating security incidents that require analyzing malware persistence with autoruns
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques
Prerequisites
- Sysinternals Autoruns (GUI) and Autorunsc (CLI)
- Administrative privileges on target system
- Python 3.9+ for automated analysis
- VirusTotal API key for reputation checks
- Clean baseline export for comparison
Workflow
Step 1: Automated Persistence Scanning
#!/usr/bin/env python3
"""Automate Autoruns-based persistence analysis."""
import subprocess
import csv
import json
import sys
def scan_and_analyze(autorunsc_path="autorunsc64.exe", csv_path="scan.csv"):
cmd = [autorunsc_path, "-a", "*", "-c", "-h", "-s", "-nobanner", "*"]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=600)
with open(csv_path, 'w') as f:
f.write(result.stdout)
return parse_and_flag(csv_path)
def parse_and_flag(csv_path):
suspicious = []
with open(csv_path, 'r', errors='replace') as f:
for row in csv.DictReader(f):
reasons = []
signer = row.get("Signer", "")
if not signer or signer == "(Not verified)":
reasons.append("Unsigned binary")
if not row.get("Description") and not row.get("Company"):
reasons.append("Missing metadata")
path = row.get("Image Path", "").lower()
for sp in ["\temp\\", "\appdata\local\temp", "\users\public\\"]:
if sp in path:
reasons.append(f"Suspicious path")
launch = row.get("Launch String", "").lower()
for kw in ["powershell", "cmd /c", "wscript", "mshta", "regsvr32"]:
if kw in launch:
reasons.append(f"LOLBin: {kw}")
if reasons:
row["reasons"] = reasons
suspicious.append(row)
return suspicious
if __name__ == "__main__":
if len(sys.argv) > 1:
results = parse_and_flag(sys.argv[1])
print(f"[!] {len(results)} suspicious entries")
for r in results:
print(f" {r.get('Entry','')} - {r.get('Image Path','')}")
for reason in r.get('reasons', []):
print(f" - {reason}")Validation Criteria
- All ASEP categories scanned and cataloged
- Unsigned entries flagged for investigation
- Suspicious paths and LOLBin launch strings highlighted
- Baseline comparison identifies new persistence mechanisms
References
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md1.8 KB
API Reference: Autoruns Persistence Analysis
Autoruns CLI (autorunsc.exe)
autorunsc.exe -a * -c -h -s -v -vt -o autoruns.csv| Flag | Description |
|---|---|
-a * |
All autostart categories |
-c |
CSV output |
-h |
Show file hashes |
-s |
Verify digital signatures |
-v |
Verify signatures against catalog |
-vt |
Check VirusTotal |
-o |
Output file |
CSV Columns
| Column | Description |
|---|---|
| Time | Entry timestamp |
| Entry Location | Registry key or path |
| Entry | Entry name |
| Enabled | enabled/disabled |
| Category | Autoruns category |
| Description | File description |
| Company | Publisher name |
| Image Path | Full binary path |
| Launch String | Complete command line |
| MD5 / SHA-1 / SHA-256 | File hashes |
| Signer | Code signing status |
| VT detection | VirusTotal ratio (e.g., "5/72") |
Autostart Categories
| Category | Examples |
|---|---|
| Logon | Run/RunOnce keys, Startup folder |
| Services | Windows services |
| Drivers | Kernel drivers |
| Scheduled Tasks | Task Scheduler entries |
| Winlogon | Shell, Userinit, Notify |
| WMI | Event subscriptions |
| AppInit | AppInit_DLLs |
| Boot Execute | BootExecute values |
| Image Hijacks | IFEO debugger entries |
| LSA Providers | Authentication packages |
Suspicious Indicators
| Indicator | Significance |
|---|---|
| VT detection > 0 | Known malware |
| Unsigned binary | Potential unsigned malware |
| LOLBin in launch string | Living-off-the-land |
| Path in %TEMP% or %PUBLIC% | Staging location |
| Missing company info | Suspicious unsigned entry |
MITRE ATT&CK Persistence
- T1547.001 - Registry Run Keys / Startup Folder
- T1053.005 - Scheduled Task
- T1543.003 - Windows Service
- T1546.003 - WMI Event Subscription
standards.md0.3 KB
Standards Reference - analyzing-malware-persistence-with-autoruns
Applicable Standards
- MITRE ATT&CK Framework
- NIST SP 800-83 Guide to Malware Incident Prevention
- NIST SP 800-86 Guide to Integrating Forensic Techniques
Related MITRE ATT&CK Techniques
See SKILL.md for specific technique mappings.
workflows.md0.5 KB
Analysis Workflows - analyzing-malware-persistence-with-autoruns
Primary Workflow
[Sample Collection] --> [Static Analysis] --> [Dynamic Analysis] --> [IOC Extraction]
|
v
[Report Generation]See SKILL.md for detailed step-by-step procedures.
Scripts 1
agent.py5.7 KB
#!/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()