npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
When to Use
- When investigating how malware maintains presence on a compromised system after reboots
- During incident response to identify all persistence mechanisms for complete remediation
- For threat hunting to discover unauthorized autostart entries across endpoints
- When analyzing malware behavior to understand its persistence strategy
- For verifying that all persistence has been removed after incident remediation
Prerequisites
- Forensic image or live system access with administrative privileges
- Autoruns (Sysinternals) for Windows persistence enumeration
- RegRipper for offline registry analysis
- Understanding of Windows and Linux persistence mechanisms
- YARA rules for scanning persistence locations
- Baseline of known-good autorun entries for comparison
Workflow
Step 1: Enumerate Windows Registry Persistence
# Extract registry hives from forensic image
mount -o ro,loop,offset=$((2048*512)) /cases/case-2024-001/images/evidence.dd /mnt/evidence
# Key registry persistence locations
python3 << 'PYEOF'
from Registry import Registry
import json
results = {'registry_persistence': []}
# SYSTEM hive analysis
system_reg = Registry.Registry("/cases/case-2024-001/registry/SYSTEM")
select = system_reg.open("Select")
current = select.value("Current").value()
cs = f"ControlSet{current:03d}"
# Services (very common persistence)
services = system_reg.open(f"{cs}\\Services")
for svc in services.subkeys():
try:
start_type = svc.value("Start").value()
image_path = ""
try:
image_path = svc.value("ImagePath").value()
except:
pass
# Start types: 0=Boot, 1=System, 2=Auto, 3=Manual, 4=Disabled
if start_type in (0, 1, 2) and image_path:
svc_type = svc.value("Type").value() if svc.values() else 0
results['registry_persistence'].append({
'location': f'HKLM\\SYSTEM\\{cs}\\Services\\{svc.name()}',
'type': 'Service',
'value': image_path,
'start_type': start_type,
'timestamp': str(svc.timestamp())
})
except Exception:
pass
# SOFTWARE hive analysis
sw_reg = Registry.Registry("/cases/case-2024-001/registry/SOFTWARE")
# Machine Run keys
run_keys = [
"Microsoft\\Windows\\CurrentVersion\\Run",
"Microsoft\\Windows\\CurrentVersion\\RunOnce",
"Microsoft\\Windows\\CurrentVersion\\RunServices",
"Microsoft\\Windows\\CurrentVersion\\RunServicesOnce",
"Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run",
"Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run",
"Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
]
for key_path in run_keys:
try:
key = sw_reg.open(key_path)
for value in key.values():
results['registry_persistence'].append({
'location': f'HKLM\\SOFTWARE\\{key_path}',
'type': 'Run Key',
'name': value.name(),
'value': str(value.value()),
'timestamp': str(key.timestamp())
})
except Exception:
pass
# NTUSER.DAT analysis
import glob
for ntuser in glob.glob("/cases/case-2024-001/registry/NTUSER*.DAT"):
try:
user_reg = Registry.Registry(ntuser)
user_run_keys = [
"Software\\Microsoft\\Windows\\CurrentVersion\\Run",
"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce",
"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\Startup",
]
for key_path in user_run_keys:
try:
key = user_reg.open(key_path)
for value in key.values():
results['registry_persistence'].append({
'location': f'HKCU\\{key_path}',
'type': 'User Run Key',
'name': value.name(),
'value': str(value.value()),
'timestamp': str(key.timestamp()),
'hive': ntuser
})
except Exception:
pass
except Exception:
pass
print(f"Total registry persistence entries: {len(results['registry_persistence'])}")
for entry in results['registry_persistence']:
print(f" [{entry['type']}] {entry.get('name', '')} -> {entry.get('value', '')[:100]}")
with open('/cases/case-2024-001/analysis/registry_persistence.json', 'w') as f:
json.dump(results, f, indent=2)
PYEOFStep 2: Check Scheduled Tasks and WMI Persistence
# Extract scheduled tasks from forensic image
mkdir -p /cases/case-2024-001/persistence/tasks/
cp -r /mnt/evidence/Windows/System32/Tasks/* /cases/case-2024-001/persistence/tasks/ 2>/dev/null
# Parse scheduled task XML files
python3 << 'PYEOF'
import os, xml.etree.ElementTree as ET
tasks_dir = '/cases/case-2024-001/persistence/tasks/'
suspicious_tasks = []
for root_dir, dirs, files in os.walk(tasks_dir):
for fname in files:
fpath = os.path.join(root_dir, fname)
try:
tree = ET.parse(fpath)
root = tree.getroot()
ns = {'t': 'http://schemas.microsoft.com/windows/2004/02/mit/task'}
actions = root.findall('.//t:Exec', ns)
for action in actions:
command = action.find('t:Command', ns)
args = action.find('t:Arguments', ns)
cmd_text = command.text if command is not None else ''
args_text = args.text if args is not None else ''
# Flag suspicious commands
suspicious_indicators = [
'powershell', 'cmd.exe', 'wscript', 'cscript', 'mshta',
'regsvr32', 'rundll32', 'certutil', 'bitsadmin',
'/c ', '-enc', '-e ', 'hidden', 'bypass', 'downloadstring',
'invoke-', 'iex', '/tmp/', 'appdata', 'programdata',
'temp\\', '.ps1', '.vbs', '.hta', 'base64'
]
is_suspicious = any(s in (cmd_text + ' ' + args_text).lower() for s in suspicious_indicators)
task_info = {
'name': fname,
'path': fpath.replace(tasks_dir, ''),
'command': cmd_text,
'arguments': args_text,
'suspicious': is_suspicious
}
if is_suspicious:
suspicious_tasks.append(task_info)
print(f"SUSPICIOUS TASK: {fname}")
print(f" Command: {cmd_text}")
print(f" Arguments: {args_text}")
print()
except Exception as e:
pass
print(f"\nTotal suspicious scheduled tasks: {len(suspicious_tasks)}")
PYEOF
# Check WMI event subscriptions (common APT persistence)
# WMI repository: C:\Windows\System32\wbem\Repository\
cp -r /mnt/evidence/Windows/System32/wbem/Repository/ /cases/case-2024-001/persistence/wmi/ 2>/dev/null
# Parse WMI persistence using PyWMIPersistenceFinder
python3 << 'PYEOF'
import os, re
# Search WMI OBJECTS.DATA for event subscriptions
wmi_db = '/cases/case-2024-001/persistence/wmi/OBJECTS.DATA'
if os.path.exists(wmi_db):
with open(wmi_db, 'rb') as f:
data = f.read()
# Search for EventFilter strings
filters = re.findall(b'__EventFilter.*?(?=\x00\x00)', data)
consumers = re.findall(b'CommandLineEventConsumer.*?(?=\x00\x00)', data)
bindings = re.findall(b'__FilterToConsumerBinding.*?(?=\x00\x00)', data)
print("=== WMI PERSISTENCE ===")
print(f"Event Filters: {len(filters)}")
print(f"Command Consumers: {len(consumers)}")
print(f"Filter-Consumer Bindings: {len(bindings)}")
for consumer in consumers:
decoded = consumer.decode('utf-8', errors='ignore')
print(f" Consumer: {decoded[:200]}")
else:
print("WMI repository not found")
PYEOFStep 3: Check File System and Boot Persistence
# Startup folders
echo "=== STARTUP FOLDER CONTENTS ===" > /cases/case-2024-001/analysis/startup_items.txt
ls -la "/mnt/evidence/ProgramData/Microsoft/Windows/Start Menu/Programs/Startup/" \
>> /cases/case-2024-001/analysis/startup_items.txt 2>/dev/null
for userdir in /mnt/evidence/Users/*/; do
username=$(basename "$userdir")
echo "--- User: $username ---" >> /cases/case-2024-001/analysis/startup_items.txt
ls -la "$userdir/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup/" \
>> /cases/case-2024-001/analysis/startup_items.txt 2>/dev/null
done
# Check DLL search order hijacking locations
echo "=== DLL HIJACKING CHECK ===" > /cases/case-2024-001/analysis/dll_hijack.txt
# Check for DLLs in application directories that should only be in System32
find /mnt/evidence/Program\ Files/ /mnt/evidence/Program\ Files\ \(x86\)/ \
-name "*.dll" -newer /mnt/evidence/Windows/System32/ntdll.dll 2>/dev/null \
>> /cases/case-2024-001/analysis/dll_hijack.txt
# Check for COM object hijacking
python3 << 'PYEOF'
from Registry import Registry
reg = Registry.Registry("/cases/case-2024-001/registry/SOFTWARE")
# Check for suspicious CLSID entries
try:
clsid = reg.open("Classes\\CLSID")
for key in clsid.subkeys():
try:
server = key.subkey("InprocServer32")
dll_path = server.value("(default)").value()
if any(s in dll_path.lower() for s in ['temp', 'appdata', 'programdata', 'downloads', 'tmp']):
print(f"SUSPICIOUS COM: {key.name()} -> {dll_path}")
except:
pass
except:
pass
PYEOF
# Check boot configuration for bootkits
# BCD (Boot Configuration Data)
ls -la /mnt/evidence/Boot/BCD 2>/dev/null
# Check for modified bootmgr or winload.exe
sha256sum /mnt/evidence/Windows/System32/winload.exe 2>/dev/nullStep 4: Check Linux Persistence Mechanisms
# If analyzing a Linux system
LINUX_ROOT="/mnt/evidence"
echo "=== LINUX PERSISTENCE CHECK ===" > /cases/case-2024-001/analysis/linux_persistence.txt
# Cron jobs
echo "--- Cron Jobs ---" >> /cases/case-2024-001/analysis/linux_persistence.txt
cat $LINUX_ROOT/etc/crontab >> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/null
ls -la $LINUX_ROOT/etc/cron.d/ >> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/null
cat $LINUX_ROOT/etc/cron.d/* >> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/null
cat $LINUX_ROOT/var/spool/cron/crontabs/* >> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/null
# Systemd services
echo "--- Custom Systemd Services ---" >> /cases/case-2024-001/analysis/linux_persistence.txt
find $LINUX_ROOT/etc/systemd/system/ -name "*.service" -not -type l \
>> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/null
# SSH authorized keys
echo "--- SSH Authorized Keys ---" >> /cases/case-2024-001/analysis/linux_persistence.txt
find $LINUX_ROOT/home/ $LINUX_ROOT/root/ -name "authorized_keys" -exec cat {} \; \
>> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/null
# Init scripts and rc.local
echo "--- RC Scripts ---" >> /cases/case-2024-001/analysis/linux_persistence.txt
cat $LINUX_ROOT/etc/rc.local >> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/null
# Shell profile scripts
echo "--- Profile Scripts ---" >> /cases/case-2024-001/analysis/linux_persistence.txt
cat $LINUX_ROOT/etc/profile.d/*.sh >> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/null
# LD_PRELOAD
echo "--- LD_PRELOAD ---" >> /cases/case-2024-001/analysis/linux_persistence.txt
cat $LINUX_ROOT/etc/ld.so.preload >> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/null
grep -r "LD_PRELOAD" $LINUX_ROOT/etc/ >> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/null
# Kernel modules
echo "--- Loaded Kernel Modules ---" >> /cases/case-2024-001/analysis/linux_persistence.txt
cat $LINUX_ROOT/etc/modules-load.d/*.conf >> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/null
# PAM backdoors
echo "--- PAM Configuration ---" >> /cases/case-2024-001/analysis/linux_persistence.txt
find $LINUX_ROOT/etc/pam.d/ -exec grep -l "pam_exec\|pam_script" {} \; \
>> /cases/case-2024-001/analysis/linux_persistence.txt 2>/dev/nullStep 5: Compile Persistence Report
# Generate comprehensive persistence report
python3 << 'PYEOF'
import json
with open('/cases/case-2024-001/analysis/registry_persistence.json') as f:
reg_data = json.load(f)
report = """
MALWARE PERSISTENCE INVESTIGATION REPORT
==========================================
PERSISTENCE MECHANISMS FOUND:
1. REGISTRY RUN KEYS:
"""
run_keys = [e for e in reg_data['registry_persistence'] if 'Run' in e.get('type', '')]
for entry in run_keys:
report += f" [{entry['timestamp']}] {entry.get('name', 'N/A')} -> {entry.get('value', '')[:100]}\n"
services = [e for e in reg_data['registry_persistence'] if e.get('type') == 'Service']
report += f"\n2. SERVICES ({len(services)} auto-start services):\n"
for entry in services[:20]:
report += f" {entry['location'].split('\\')[-1]}: {entry['value'][:100]}\n"
report += """
3. SCHEDULED TASKS: [See scheduled_tasks analysis]
4. WMI SUBSCRIPTIONS: [See WMI analysis]
5. STARTUP FOLDER: [See startup_items.txt]
6. COM HIJACKING: [See COM analysis]
SUSPICIOUS ENTRIES REQUIRING INVESTIGATION:
"""
# Flag suspicious entries
for entry in reg_data['registry_persistence']:
value = str(entry.get('value', '')).lower()
suspicious_indicators = ['powershell', 'cmd /c', 'wscript', 'certutil',
'programdata', 'appdata\\local\\temp', 'base64',
'.ps1', '.vbs', '.hta', '/tmp/', 'hidden']
if any(s in value for s in suspicious_indicators):
report += f" SUSPICIOUS: {entry.get('name', 'N/A')} -> {entry.get('value', '')[:100]}\n"
with open('/cases/case-2024-001/analysis/persistence_report.txt', 'w') as f:
f.write(report)
print(report)
PYEOFKey Concepts
| Concept | Description |
|---|---|
| Run keys | Registry keys executing programs at user logon (HKLM and HKCU) |
| Scheduled tasks | Windows Task Scheduler entries that execute on triggers (time, event, logon) |
| WMI event subscriptions | Persistent WMI queries that trigger actions (stealthy persistence) |
| COM hijacking | Redirecting COM object loading to execute malicious DLLs |
| DLL search order hijacking | Placing malicious DLLs in directories searched before System32 |
| Service persistence | Installing Windows services that auto-start with the system |
| Boot-level persistence | Modifying boot configuration or MBR/VBR for pre-OS execution |
| Living-off-the-land | Using legitimate system tools (PowerShell, WMI, certutil) for persistence |
Tools & Systems
| Tool | Purpose |
|---|---|
| Autoruns | Sysinternals comprehensive autostart enumeration tool |
| RegRipper | Automated registry persistence artifact extraction |
| KAPE | Automated persistence artifact collection and analysis |
| Velociraptor | Endpoint agent with persistence hunting artifacts |
| OSQuery | SQL-based system querying for persistence enumeration |
| PersistenceSniper | PowerShell tool for Windows persistence detection |
| RECmd | Eric Zimmerman registry command-line analysis tool |
| Volatility | Memory forensics for in-memory only persistence |
Common Scenarios
Scenario 1: APT Persistence After Initial Compromise Check all registry Run keys, enumerate scheduled tasks for encoded PowerShell commands, examine WMI event subscriptions for event-triggered execution, check COM object registrations for hijacked CLSIDs, review services for recently installed entries with suspicious image paths.
Scenario 2: Ransomware Pre-Encryption Persistence Identify how the ransomware maintains access for re-encryption or monitoring, check for scheduled tasks that would re-launch encryption, examine services installed by the ransomware operator, verify no additional backdoor persistence exists before declaring remediation complete.
Scenario 3: Fileless Malware Persistence Focus on registry-based persistence storing payload in registry values, check WMI subscriptions executing PowerShell from event triggers, examine scheduled tasks using encoded command arguments, check for mshta/rundll32 based persistence loading remote content.
Scenario 4: Post-Remediation Verification Run Autoruns comparison against known-good baseline, verify all identified persistence mechanisms have been removed, check for additional persistence that may have been missed, confirm services, tasks, and registry entries are clean, monitor for re-infection indicators.
Output Format
Persistence Investigation Summary:
System: DESKTOP-ABC123 (Windows 10 Pro)
Analysis Date: 2024-01-20
Persistence Mechanisms Found:
Registry Run Keys (HKLM): 5 entries (1 SUSPICIOUS)
Registry Run Keys (HKCU): 3 entries (1 SUSPICIOUS)
Services (Auto-Start): 142 entries (2 SUSPICIOUS)
Scheduled Tasks: 67 entries (3 SUSPICIOUS)
WMI Subscriptions: 1 entry (SUSPICIOUS)
Startup Folder: 4 items (1 SUSPICIOUS)
COM Objects: 0 hijacked entries
DLL Hijacking: 0 detected
Suspicious Entries:
1. HKCU\Run\WindowsUpdate -> powershell -ep bypass -e <base64>
Timestamp: 2024-01-15 14:35:00
Action: Encoded PowerShell download cradle
2. Service: WinDefenderUpdate -> C:\ProgramData\svc\update.exe
Timestamp: 2024-01-15 14:40:00
Action: Unknown executable in ProgramData
3. Task: \Microsoft\Windows\Maintenance\SecurityUpdate
Command: cmd.exe /c powershell -w hidden -e <base64>
Trigger: On system startup
4. WMI: __EventFilter "ProcessStart" -> CommandLineEventConsumer
Action: Execute C:\Windows\Temp\svc.exe on WMI event
Remediation Required: 4 persistence mechanisms to remove
Report: /cases/case-2024-001/analysis/persistence_report.txtReferences and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md1.9 KB
API Reference: Malware Persistence Investigation
python-registry Library
from Registry import Registry
reg = Registry.Registry("SOFTWARE")
key = reg.open("Microsoft\\Windows\\CurrentVersion\\Run")
for value in key.values():
print(f"{value.name()} -> {value.value()}")Key Windows Persistence Locations
| Location | Type | Registry Path / Filesystem Path |
|---|---|---|
| Run Keys (HKLM) | Registry | SOFTWARE\Microsoft\Windows\CurrentVersion\Run |
| Run Keys (HKCU) | Registry | NTUSER.DAT\Software\Microsoft\Windows\CurrentVersion\Run |
| Services | Registry | SYSTEM\ControlSetXXX\Services |
| Scheduled Tasks | Filesystem | C:\Windows\System32\Tasks\ |
| WMI Subscriptions | WMI DB | C:\Windows\System32\wbem\Repository\OBJECTS.DATA |
| Startup Folder | Filesystem | %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup |
| COM Hijacking | Registry | SOFTWARE\Classes\CLSID\{...}\InprocServer32 |
Linux Persistence Locations
| Location | Mechanism |
|---|---|
/etc/crontab, /etc/cron.d/ |
Cron jobs |
/etc/systemd/system/*.service |
Systemd services |
~/.ssh/authorized_keys |
SSH key persistence |
/etc/rc.local |
Boot scripts |
/etc/ld.so.preload |
Shared library injection |
/etc/pam.d/ |
PAM backdoors |
Python Libraries
| Library | Version | Purpose |
|---|---|---|
python-registry |
>=1.4 | Offline Windows registry hive parsing |
xml.etree.ElementTree |
stdlib | Scheduled task XML parsing |
pathlib |
stdlib | Filesystem traversal |
References
- Autoruns: https://learn.microsoft.com/en-us/sysinternals/downloads/autoruns
- RegRipper: https://github.com/keydet89/RegRipper3.0
- PersistenceSniper: https://github.com/last-byte/PersistenceSniper
- MITRE ATT&CK Persistence: https://attack.mitre.org/tactics/TA0003/
Scripts 1
agent.py9.3 KB
#!/usr/bin/env python3
"""Agent for performing malware persistence investigation.
Enumerates Windows registry Run keys, services, scheduled tasks,
WMI subscriptions, and Linux cron/systemd persistence mechanisms.
"""
import json
import sys
import xml.etree.ElementTree as ET
from pathlib import Path
SUSPICIOUS_INDICATORS = [
"powershell", "cmd /c", "wscript", "cscript", "mshta",
"regsvr32", "rundll32", "certutil", "bitsadmin",
"downloadstring", "invoke-", "iex", "hidden",
"bypass", "base64", "-enc", "-e ", ".ps1", ".vbs", ".hta",
"programdata", "appdata\\local\\temp", "/tmp/",
]
class PersistenceInvestigator:
"""Investigates malware persistence mechanisms on forensic images."""
def __init__(self, evidence_root, output_dir):
self.evidence_root = Path(evidence_root)
self.output_dir = Path(output_dir)
self.output_dir.mkdir(parents=True, exist_ok=True)
self.findings = []
def _is_suspicious(self, value):
"""Check if a value matches suspicious indicators."""
value_lower = str(value).lower()
return any(ind in value_lower for ind in SUSPICIOUS_INDICATORS)
def check_registry_run_keys(self):
"""Check registry Run keys using python-registry."""
try:
from Registry import Registry
except ImportError:
return [{"error": "Install python-registry: pip install python-registry"}]
entries = []
sw_path = self.evidence_root / "Windows/System32/config/SOFTWARE"
if not sw_path.exists():
return entries
reg = Registry.Registry(str(sw_path))
run_paths = [
"Microsoft\\Windows\\CurrentVersion\\Run",
"Microsoft\\Windows\\CurrentVersion\\RunOnce",
"Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Run",
]
for key_path in run_paths:
try:
key = reg.open(key_path)
for value in key.values():
entry = {
"location": f"HKLM\\SOFTWARE\\{key_path}",
"name": value.name(),
"value": str(value.value()),
"timestamp": str(key.timestamp()),
"suspicious": self._is_suspicious(str(value.value())),
}
entries.append(entry)
if entry["suspicious"]:
self.findings.append(entry)
except Exception:
continue
return entries
def check_services(self):
"""Check Windows services for suspicious auto-start entries."""
try:
from Registry import Registry
except ImportError:
return []
entries = []
system_path = self.evidence_root / "Windows/System32/config/SYSTEM"
if not system_path.exists():
return entries
reg = Registry.Registry(str(system_path))
try:
select = reg.open("Select")
current = select.value("Current").value()
cs = f"ControlSet{current:03d}"
services = reg.open(f"{cs}\\Services")
for svc in services.subkeys():
try:
start = svc.value("Start").value()
if start not in (0, 1, 2):
continue
image_path = ""
try:
image_path = svc.value("ImagePath").value()
except Exception:
continue
entry = {
"service_name": svc.name(),
"image_path": image_path,
"start_type": start,
"timestamp": str(svc.timestamp()),
"suspicious": self._is_suspicious(image_path),
}
entries.append(entry)
if entry["suspicious"]:
self.findings.append(entry)
except Exception:
continue
except Exception:
pass
return entries
def check_scheduled_tasks(self):
"""Parse Windows scheduled task XML files."""
tasks_dir = self.evidence_root / "Windows/System32/Tasks"
if not tasks_dir.exists():
return []
entries = []
ns = {"t": "http://schemas.microsoft.com/windows/2004/02/mit/task"}
for task_file in tasks_dir.rglob("*"):
if not task_file.is_file():
continue
try:
tree = ET.parse(str(task_file))
root = tree.getroot()
for action in root.findall(".//t:Exec", ns):
cmd = action.find("t:Command", ns)
args = action.find("t:Arguments", ns)
cmd_text = cmd.text if cmd is not None else ""
args_text = args.text if args is not None else ""
combined = f"{cmd_text} {args_text}"
entry = {
"task_name": task_file.name,
"command": cmd_text,
"arguments": args_text,
"suspicious": self._is_suspicious(combined),
}
entries.append(entry)
if entry["suspicious"]:
self.findings.append(entry)
except Exception:
continue
return entries
def check_startup_folder(self):
"""Check Windows startup folder contents."""
entries = []
startup_paths = [
"ProgramData/Microsoft/Windows/Start Menu/Programs/Startup",
]
for user_dir in (self.evidence_root / "Users").iterdir() if (self.evidence_root / "Users").exists() else []:
if user_dir.is_dir():
startup_paths.append(
f"Users/{user_dir.name}/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup"
)
for spath in startup_paths:
target = self.evidence_root / spath
if target.exists() and target.is_dir():
for item in target.iterdir():
if item.is_file():
entries.append({
"location": str(spath),
"filename": item.name,
"size": item.stat().st_size,
"suspicious": self._is_suspicious(item.name),
})
return entries
def check_linux_persistence(self):
"""Check Linux persistence mechanisms."""
entries = []
checks = {
"crontab": "etc/crontab",
"rc_local": "etc/rc.local",
"ld_preload": "etc/ld.so.preload",
}
for name, path in checks.items():
target = self.evidence_root / path
if target.exists() and target.is_file():
content = target.read_text(errors="ignore")
entries.append({
"mechanism": name,
"file": path,
"content_preview": content[:500],
"suspicious": self._is_suspicious(content),
})
cron_dirs = ["etc/cron.d", "etc/cron.daily", "var/spool/cron/crontabs"]
for cron_dir in cron_dirs:
target = self.evidence_root / cron_dir
if target.exists() and target.is_dir():
for f in target.iterdir():
if f.is_file():
content = f.read_text(errors="ignore")
entries.append({
"mechanism": "cron_job",
"file": str(f.relative_to(self.evidence_root)),
"content_preview": content[:300],
})
auth_keys_pattern = "home/*/. ssh/authorized_keys".replace(". ", ".")
for ak in self.evidence_root.glob("home/*/.ssh/authorized_keys"):
entries.append({
"mechanism": "ssh_authorized_keys",
"file": str(ak.relative_to(self.evidence_root)),
"content_preview": ak.read_text(errors="ignore")[:300],
})
return entries
def generate_report(self):
"""Run all persistence checks and generate report."""
report = {
"case_output": str(self.output_dir),
"evidence_root": str(self.evidence_root),
"registry_run_keys": self.check_registry_run_keys(),
"services": self.check_services()[:30],
"scheduled_tasks": self.check_scheduled_tasks(),
"startup_folder": self.check_startup_folder(),
"linux_persistence": self.check_linux_persistence(),
"suspicious_findings": self.findings,
"total_suspicious": len(self.findings),
}
report_path = self.output_dir / "persistence_report.json"
with open(report_path, "w") as f:
json.dump(report, f, indent=2)
print(json.dumps(report, indent=2))
return report
def main():
if len(sys.argv) < 3:
print("Usage: agent.py <evidence_root> <output_dir>")
sys.exit(1)
investigator = PersistenceInvestigator(sys.argv[1], sys.argv[2])
investigator.generate_report()
if __name__ == "__main__":
main()