npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
NIST CSF 2.0
Overview
Attackers frequently install malicious Windows services for persistence and privilege escalation (MITRE ATT&CK T1543.003 — Create or Modify System Process: Windows Service). Event ID 7045 in the System event log records every new service installation. This skill parses .evtx log files to extract service installation events, flags suspicious binary paths (temp directories, PowerShell, cmd.exe, encoded commands), and correlates with known attack patterns.
When to Use
- When investigating security incidents that require hunting for unusual service installations
- 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
- Python 3.9+ with
python-evtx,lxml - Windows System event log (.evtx) files
- Access to live System event log (optional, for real-time monitoring)
- Sysmon logs for enhanced process tracking (optional)
Steps
- Parse System.evtx for Event ID 7045 (new service installed)
- Extract service name, binary path, service type, and account
- Flag services with suspicious binary paths (temp dirs, encoded commands)
- Detect PowerShell-based service creation patterns
- Identify services running as LocalSystem with unusual paths
- Cross-reference with known legitimate service baselines
- Generate threat hunting report with MITRE ATT&CK T1543.003 mapping
Expected Output
- JSON report listing all new service installations with risk scores, suspicious indicators, and remediation recommendations
- Timeline of service installation events with binary path analysis
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.6 KB
API Reference — Hunting for Unusual Service Installations
Libraries Used
- python-evtx: Parse Windows .evtx event log files
- lxml: XML parsing of EVTX record XML
- re: Regex matching for suspicious binary path patterns
- collections.Counter: Statistics aggregation
CLI Interface
python agent.py System.evtx parse
python agent.py System.evtx hunt
python agent.py System.evtx stats
python agent.py System.evtx fullCore Functions
parse_evtx_events(evtx_path) — Extract Event ID 7045 records
Opens .evtx file with evtx.Evtx(), iterates records, parses XML with lxml.
Extracts: ServiceName, ImagePath, ServiceType, StartType, AccountName, timestamp.
Namespace: http://schemas.microsoft.com/win/2004/08/events/event
analyze_service_path(image_path) — Binary path risk analysis
Matches against 17 suspicious patterns (temp dirs, PowerShell, encoded commands, LOLBins, download patterns). Checks against 5 legitimate path prefixes. Scoring: +20 for non-standard path, +15 per suspicious indicator. Max 100.
hunt_suspicious_services(evtx_path) — Main hunting engine
Combines parsing and analysis. Extra +20 risk for LocalSystem account with non-standard binary path. Results sorted by risk score descending.
generate_statistics(results) — Summary statistics
Counts risk distribution, top indicators, service account usage.
full_hunt(evtx_path) — Comprehensive threat hunt report
Suspicious Path Patterns
| Pattern | Indicator |
|---|---|
\temp\, \tmp\ |
temp_directory |
\appdata\ |
appdata_directory |
\users\public\ |
public_user_directory |
powershell.exe |
powershell_execution |
cmd.exe /c |
cmd_execution |
-enc, -encodedcommand |
encoded_command |
downloadstring, webclient |
download_pattern |
invoke-expression, iex |
invoke_expression |
mshta, regsvr32, rundll32 |
lolbin_execution |
Legitimate Service Path Prefixes
C:\Windows\System32\C:\Windows\SysWOW64\C:\Program Files\C:\Program Files (x86)\C:\Windows\Microsoft.NET\
Event ID 7045 Fields
| Field | Description |
|---|---|
| ServiceName | Display name of installed service |
| ImagePath | Binary path and arguments |
| ServiceType | user mode service, kernel driver, etc. |
| StartType | auto start, demand start, boot start |
| AccountName | Service account (LocalSystem, etc.) |
MITRE ATT&CK Mapping
- T1543.003 — Create or Modify System Process: Windows Service
- Tactics: Persistence, Privilege Escalation
Dependencies
python-evtx>= 0.7.4lxml>= 4.9.0
Scripts 1
agent.py7.6 KB
#!/usr/bin/env python3
"""Agent for hunting suspicious Windows service installations (T1543.003) via Event ID 7045."""
import json
import re
import argparse
from datetime import datetime
from collections import Counter
try:
from lxml import etree
except ImportError:
etree = None
try:
import Evtx.Evtx as evtx
except ImportError:
evtx = None
SUSPICIOUS_PATH_PATTERNS = [
(r"\\temp\\", "temp_directory"),
(r"\\tmp\\", "temp_directory"),
(r"\\appdata\\", "appdata_directory"),
(r"\\users\\public\\", "public_user_directory"),
(r"\\programdata\\[^\\]+\.[^\\]+$", "loose_file_in_programdata"),
(r"powershell\.exe", "powershell_execution"),
(r"cmd\.exe\s*/c", "cmd_execution"),
(r"-enc\s+", "encoded_command"),
(r"-encodedcommand", "encoded_command"),
(r"frombase64string", "base64_decode"),
(r"downloadstring|downloadfile|webclient", "download_pattern"),
(r"invoke-expression|iex\s", "invoke_expression"),
(r"\\windows\\temp\\", "windows_temp"),
(r"mshta\.exe|regsvr32\.exe|rundll32\.exe|msiexec\.exe", "lolbin_execution"),
(r"sc\.exe\s+create", "sc_create_chain"),
(r"\\\$recycle\.bin\\", "recycle_bin"),
(r"\\perflog", "perflog_abuse"),
]
LEGITIMATE_SERVICE_PATHS = [
r"^\"?C:\\Windows\\System32\\",
r"^\"?C:\\Windows\\SysWOW64\\",
r"^\"?C:\\Program Files\\",
r"^\"?C:\\Program Files \(x86\)\\",
r"^\"?C:\\Windows\\Microsoft\.NET\\",
]
def parse_evtx_events(evtx_path):
"""Parse System.evtx and extract Event ID 7045 records."""
if not evtx:
raise RuntimeError("python-evtx not installed: pip install python-evtx")
events = []
ns = {"e": "http://schemas.microsoft.com/win/2004/08/events/event"}
with evtx.Evtx(evtx_path) as log:
for record in log.records():
try:
xml = record.xml()
root = etree.fromstring(xml.encode("utf-8") if isinstance(xml, str) else xml)
event_id_el = root.find(".//e:System/e:EventID", ns)
if event_id_el is None or event_id_el.text != "7045":
continue
system = root.find(".//e:System", ns)
event_data = root.find(".//e:EventData", ns)
data_fields = {}
if event_data is not None:
for data in event_data.findall("e:Data", ns):
name = data.get("Name", "")
data_fields[name] = data.text or ""
time_el = system.find("e:TimeCreated", ns)
timestamp = time_el.get("SystemTime", "") if time_el is not None else ""
computer_el = system.find("e:Computer", ns)
computer = computer_el.text if computer_el is not None else ""
events.append({
"timestamp": timestamp,
"event_id": 7045,
"computer": computer,
"service_name": data_fields.get("ServiceName", ""),
"image_path": data_fields.get("ImagePath", ""),
"service_type": data_fields.get("ServiceType", ""),
"start_type": data_fields.get("StartType", ""),
"account_name": data_fields.get("AccountName", ""),
})
except Exception:
continue
return events
def analyze_service_path(image_path):
"""Analyze a service binary path for suspicious indicators."""
findings = []
path_lower = image_path.lower()
for pattern, indicator in SUSPICIOUS_PATH_PATTERNS:
if re.search(pattern, path_lower, re.IGNORECASE):
findings.append(indicator)
is_legitimate = any(re.match(p, image_path, re.IGNORECASE) for p in LEGITIMATE_SERVICE_PATHS)
risk_score = 0
if not is_legitimate:
risk_score += 20
risk_score += len(findings) * 15
risk_score = min(risk_score, 100)
return {
"suspicious_indicators": findings,
"legitimate_path": is_legitimate,
"risk_score": risk_score,
"risk_level": "CRITICAL" if risk_score >= 70 else "HIGH" if risk_score >= 50 else "MEDIUM" if risk_score >= 20 else "LOW",
}
def hunt_suspicious_services(evtx_path):
"""Main hunting function: parse events and analyze each service."""
events = parse_evtx_events(evtx_path)
results = []
for event in events:
analysis = analyze_service_path(event.get("image_path", ""))
entry = {**event, **analysis}
if entry.get("account_name", "").lower() == "localsystem" and not analysis["legitimate_path"]:
entry["risk_score"] = min(entry["risk_score"] + 20, 100)
entry["risk_level"] = "CRITICAL" if entry["risk_score"] >= 70 else entry["risk_level"]
entry["suspicious_indicators"].append("localsystem_nonstandard_path")
results.append(entry)
results.sort(key=lambda x: x.get("risk_score", 0), reverse=True)
return results
def generate_statistics(results):
"""Generate summary statistics from hunting results."""
total = len(results)
risk_counts = Counter(r.get("risk_level", "LOW") for r in results)
indicator_counts = Counter()
account_counts = Counter()
for r in results:
for ind in r.get("suspicious_indicators", []):
indicator_counts[ind] += 1
account_counts[r.get("account_name", "Unknown")] += 1
return {
"total_service_installations": total,
"risk_distribution": dict(risk_counts),
"top_indicators": dict(indicator_counts.most_common(10)),
"service_accounts": dict(account_counts.most_common(10)),
"critical_count": risk_counts.get("CRITICAL", 0),
"high_count": risk_counts.get("HIGH", 0),
}
def full_hunt(evtx_path):
"""Run comprehensive service installation threat hunt."""
results = hunt_suspicious_services(evtx_path)
stats = generate_statistics(results)
suspicious = [r for r in results if r.get("risk_score", 0) >= 20]
return {
"hunt_type": "Unusual Service Installation (T1543.003)",
"timestamp": datetime.utcnow().isoformat(),
"evtx_file": evtx_path,
"statistics": stats,
"suspicious_services": suspicious[:30],
"mitre_technique": {
"id": "T1543.003",
"name": "Create or Modify System Process: Windows Service",
"tactic": "Persistence, Privilege Escalation",
},
"recommendation": "Investigate CRITICAL and HIGH services. Verify binary hashes against known-good baselines." if stats["critical_count"] + stats["high_count"] > 0
else "No high-risk service installations detected.",
}
def main():
parser = argparse.ArgumentParser(description="Service Installation Threat Hunting Agent (T1543.003)")
parser.add_argument("evtx", help="Path to System.evtx file")
sub = parser.add_subparsers(dest="command")
sub.add_parser("parse", help="Parse and list all Event ID 7045 records")
sub.add_parser("hunt", help="Hunt for suspicious service installations")
sub.add_parser("stats", help="Generate hunting statistics")
sub.add_parser("full", help="Full threat hunt report")
args = parser.parse_args()
if args.command == "parse":
result = parse_evtx_events(args.evtx)
elif args.command == "hunt":
result = hunt_suspicious_services(args.evtx)
elif args.command == "stats":
results = hunt_suspicious_services(args.evtx)
result = generate_statistics(results)
elif args.command == "full" or args.command is None:
result = full_hunt(args.evtx)
else:
parser.print_help()
return
print(json.dumps(result, indent=2, default=str))
if __name__ == "__main__":
main()