mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-09-18 05:35:53 +03:00
Add 10 new cybersecurity skills with full folder anatomy
Skills added: - implementing-privileged-access-workstation (IAM, PAW hardening) - detecting-suspicious-oauth-application-consent (cloud security, Graph API) - performing-hardware-security-module-integration (cryptography, PKCS#11) - analyzing-android-malware-with-apktool (malware analysis, androguard) - hunting-for-unusual-service-installations (threat hunting, T1543.003) - detecting-shadow-it-cloud-usage (cloud security, proxy/DNS log analysis) - performing-active-directory-forest-trust-attack (red team, impacket) - implementing-deception-based-detection-with-canarytoken (deception, Canary API) - analyzing-office365-audit-logs-for-compromise (cloud security, BEC detection) - hunting-for-startup-folder-persistence (threat hunting, T1547.001) Each skill includes SKILL.md, LICENSE, scripts/agent.py, references/api-reference.md
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Mahipal
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: hunting-for-unusual-service-installations
|
||||
description: Detect suspicious Windows service installations (MITRE ATT&CK T1543.003) by parsing System event logs for Event ID 7045, analyzing service binary paths, and identifying indicators of persistence mechanisms.
|
||||
domain: cybersecurity
|
||||
subdomain: threat-hunting
|
||||
tags: [threat-hunting, T1543.003, service-installation, persistence, Event-7045, Sysmon, Windows-services]
|
||||
version: "1.0"
|
||||
author: mahipal
|
||||
license: Apache-2.0
|
||||
---
|
||||
|
||||
# Hunting for Unusual Service Installations
|
||||
|
||||
## 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.
|
||||
|
||||
## 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
|
||||
|
||||
1. Parse System.evtx for Event ID 7045 (new service installed)
|
||||
2. Extract service name, binary path, service type, and account
|
||||
3. Flag services with suspicious binary paths (temp dirs, encoded commands)
|
||||
4. Detect PowerShell-based service creation patterns
|
||||
5. Identify services running as LocalSystem with unusual paths
|
||||
6. Cross-reference with known legitimate service baselines
|
||||
7. 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
|
||||
@@ -0,0 +1,73 @@
|
||||
# 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 full
|
||||
```
|
||||
|
||||
## Core 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.4
|
||||
- `lxml` >= 4.9.0
|
||||
@@ -0,0 +1,194 @@
|
||||
#!/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
|
||||
import Evtx.Views as evtx_views
|
||||
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()
|
||||
Reference in New Issue
Block a user