Install this skill
npx skills add mukul975/Anthropic-Cybersecurity-SkillsFramework mappings
MITRE ATT&CK
NIST CSF 2.0
When to Use
- When proactively hunting for indicators of detecting service account abuse in the environment
- After threat intelligence indicates active campaigns using these techniques
- During incident response to scope compromise related to these techniques
- When EDR or SIEM alerts trigger on related indicators
- During periodic security assessments and purple team exercises
Prerequisites
- EDR platform with process and network telemetry (CrowdStrike, MDE, SentinelOne)
- SIEM with relevant log data ingested (Splunk, Elastic, Sentinel)
- Sysmon deployed with comprehensive configuration
- Windows Security Event Log forwarding enabled
- Threat intelligence feeds for IOC correlation
Workflow
- Formulate Hypothesis: Define a testable hypothesis based on threat intelligence or ATT&CK gap analysis.
- Identify Data Sources: Determine which logs and telemetry are needed to validate or refute the hypothesis.
- Execute Queries: Run detection queries against SIEM and EDR platforms to collect relevant events.
- Analyze Results: Examine query results for anomalies, correlating across multiple data sources.
- Validate Findings: Distinguish true positives from false positives through contextual analysis.
- Correlate Activity: Link findings to broader attack chains and threat actor TTPs.
- Document and Report: Record findings, update detection rules, and recommend response actions.
Key Concepts
| Concept | Description |
|---|---|
| T1078.002 | Domain Accounts |
| T1078.001 | Default Accounts |
| T1021 | Remote Services |
Tools & Systems
| Tool | Purpose |
|---|---|
| CrowdStrike Falcon | EDR telemetry and threat detection |
| Microsoft Defender for Endpoint | Advanced hunting with KQL |
| Splunk Enterprise | SIEM log analysis with SPL queries |
| Elastic Security | Detection rules and investigation timeline |
| Sysmon | Detailed Windows event monitoring |
| Velociraptor | Endpoint artifact collection and hunting |
| Sigma Rules | Cross-platform detection rule format |
Common Scenarios
- Scenario 1: Service account RDP to domain controller
- Scenario 2: SQL service accessing file shares outside scope
- Scenario 3: Backup service lateral movement off-hours
- Scenario 4: Compromised svc with DA privileges used for DCSync
Output Format
Hunt ID: TH-DETECT-[DATE]-[SEQ]
Technique: T1078.002
Host: [Hostname]
User: [Account context]
Evidence: [Log entries, process trees, network data]
Risk Level: [Critical/High/Medium/Low]
Confidence: [High/Medium/Low]
Recommended Action: [Containment, investigation, monitoring]Source materials
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 3
api-reference.md2.1 KB
API Reference: Service Account Abuse Detection
Active Directory PowerShell Module
Get Service Accounts (SPN-based)
Get-ADUser -Filter {ServicePrincipalName -ne "$null"} -Properties `
ServicePrincipalName, LastLogonDate, Enabled, PasswordLastSet, `
PasswordNeverExpires, AdminCount, MemberOfGet Managed Service Accounts
Get-ADServiceAccount -Filter * -Properties `
PrincipalsAllowedToRetrieveManagedPassword, LastLogonDateCheck Kerberos Delegation
Get-ADUser -Filter {TrustedForDelegation -eq $true} -Properties `
TrustedForDelegation, TrustedToAuthForDelegation, `
msDS-AllowedToDelegateToWindows Event Log Queries
Logon Type Values
| Type | Description | Concern for Service Accounts |
|---|---|---|
| 2 | Interactive | HIGH — should not happen |
| 3 | Network | Normal for services |
| 5 | Service | Normal |
| 10 | RemoteInteractive (RDP) | HIGH — should not happen |
Event IDs
| ID | Log | Description |
|---|---|---|
| 4624 | Security | Successful logon |
| 4625 | Security | Failed logon |
| 4648 | Security | Explicit credential use |
| 4672 | Security | Special privilege logon |
| 4720 | Security | Account created |
| 4738 | Security | Account modified |
Microsoft Graph API — Service Principal Audit
List Service Principals
GET https://graph.microsoft.com/v1.0/servicePrincipals
Authorization: Bearer {token}List App Role Assignments
GET https://graph.microsoft.com/v1.0/servicePrincipals/{id}/appRoleAssignmentsAudit Sign-In Logs
GET https://graph.microsoft.com/v1.0/auditLogs/signIns
?$filter=appId eq '{service-principal-app-id}'AWS IAM — Service Role Audit
List service-linked roles
aws iam list-roles --query "Roles[?starts_with(Path, '/aws-service-role/')]"Get role last used
aws iam get-role --role-name MyServiceRole \
--query "Role.RoleLastUsed"Access Analyzer findings
aws accessanalyzer list-findings --analyzer-arn {arn} \
--filter '{"resourceType":{"eq":["AWS::IAM::Role"]}}'standards.md1.5 KB
Standards and References - Detecting Service Account Abuse
MITRE ATT&CK Mappings
| Technique | Name | Description |
|---|---|---|
| T1078.002 | Domain Accounts | See attack.mitre.org/techniques/T1078/002 |
| T1078.001 | Default Accounts | See attack.mitre.org/techniques/T1078/001 |
| T1021 | Remote Services | See attack.mitre.org/techniques/T1021 |
Detection Data Sources
| Source | Event ID | Purpose |
|---|---|---|
| Sysmon | 1 | Process creation with command line |
| Sysmon | 3 | Network connection initiated |
| Sysmon | 7 | Image loaded (DLL) |
| Sysmon | 10 | Process access (LSASS) |
| Sysmon | 11 | File creation |
| Sysmon | 12/13 | Registry create/set |
| Sysmon | 22 | DNS query |
| Sysmon | 25 | Process tampering |
| Windows Security | 4624 | Successful logon |
| Windows Security | 4625 | Failed logon |
| Windows Security | 4648 | Explicit credential logon |
| Windows Security | 4672 | Special privileges assigned |
| Windows Security | 4688 | Process creation |
| Windows Security | 4697 | Service installed |
| Windows Security | 4698 | Scheduled task created |
| Windows Security | 4769 | Kerberos TGS requested |
| Windows Security | 5140 | Network share accessed |
References
- MITRE ATT&CK Framework: https://attack.mitre.org/
- Sigma Detection Rules: https://github.com/SigmaHQ/sigma
- LOLBAS Project: https://lolbas-project.github.io/
- Atomic Red Team Tests: https://github.com/redcanaryco/atomic-red-team
- Red Canary Threat Detection Report
- SANS Threat Hunting Summit Resources
workflows.md2.8 KB
Detailed Hunting Workflow - Detecting Service Account Abuse
Phase 1: Data Collection and Querying
Splunk SPL Query
index=wineventlog EventCode=4624 Logon_Type IN (2, 10)
| where match(Account_Name, "(?i)(svc_|service|admin_)")
| stats count values(Computer) as hosts by Account_Name Source_Network_Address
| sort -countKQL Query (Microsoft Defender for Endpoint)
SecurityEvent
| where EventID == 4624 and LogonType in (2, 10)
| where SubjectUserName startswith "svc_" or SubjectUserName contains "service"
| summarize count(), Hosts=make_set(Computer) by SubjectUserName, IpAddressPhase 2: Baseline and Anomaly Detection
Step 2.1 - Establish Normal Behavior Baseline
- Collect 30 days of historical data for the targeted technique
- Document expected patterns, frequencies, and legitimate use cases
- Identify known false positive sources and document exceptions
- Build statistical baseline (mean, standard deviation) for key metrics
Step 2.2 - Identify Anomalies
- Compare current activity against the 30-day baseline
- Flag events exceeding 3 standard deviations from normal
- Prioritize anomalies by risk score and potential business impact
- Cross-reference with threat intelligence for known IOCs
Phase 3: Investigation and Correlation
Step 3.1 - Deep Dive Analysis
- For each anomaly, collect full process tree context
- Correlate with network activity, file operations, and authentication events
- Check binary signatures, file hashes, and certificate validity
- Review user account context and access patterns
Step 3.2 - Attack Chain Reconstruction
- Map findings to MITRE ATT&CK kill chain stages
- Identify initial access vector if applicable
- Trace lateral movement and privilege escalation paths
- Determine data access and potential exfiltration
Phase 4: Validation and Response
Step 4.1 - True/False Positive Determination
- Verify findings with system owners and IT operations
- Check change management records for authorized activities
- Validate user context (authorized actions vs. compromised account)
- Document determination rationale for each finding
Step 4.2 - Response Actions
- For confirmed threats: initiate incident response procedures
- For detection gaps: create or update detection rules
- For false positives: tune existing rules and update exclusions
- Update threat hunting playbook with lessons learned
Phase 5: Documentation and Reporting
Step 5.1 - Hunt Report
- Summarize hypothesis, methodology, and findings
- Include all queries executed and their results
- Document IOCs discovered and detection rules created
- Provide recommendations for security improvements
Step 5.2 - Knowledge Base Update
- Add findings to threat intelligence platform
- Update MITRE ATT&CK coverage heatmap
- Share detection rules via Sigma format
- Schedule follow-up hunts for related techniques
Scripts 2
agent.py5.3 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Agent for detecting service account abuse in Active Directory and cloud environments."""
import argparse
import json
import subprocess
from datetime import datetime, timezone
def query_ad_service_accounts():
"""Query Active Directory for service accounts via PowerShell."""
ps_cmd = (
"Get-ADUser -Filter {ServicePrincipalName -ne '$null'} "
"-Properties ServicePrincipalName,LastLogonDate,Enabled,PasswordLastSet,"
"PasswordNeverExpires,AdminCount,MemberOf "
"| Select-Object SamAccountName,Enabled,LastLogonDate,PasswordLastSet,"
"PasswordNeverExpires,AdminCount,@{N='SPNCount';E={$_.ServicePrincipalName.Count}} "
"| ConvertTo-Json"
)
try:
result = subprocess.check_output(
["powershell", "-NoProfile", "-Command", ps_cmd],
text=True, errors="replace", timeout=30
)
data = json.loads(result) if result.strip().startswith(("[", "{")) else []
return data if isinstance(data, list) else [data]
except (subprocess.SubprocessError, json.JSONDecodeError):
return []
def check_interactive_logons(days=7):
"""Find service accounts with interactive logon events (type 2/10)."""
ps_cmd = (
f"Get-WinEvent -FilterHashtable @{{LogName='Security';Id=4624;"
f"StartTime=(Get-Date).AddDays(-{days})}} "
"| Where-Object {($_.Properties[8].Value -eq 2 -or $_.Properties[8].Value -eq 10) "
"-and $_.Properties[5].Value -match 'svc_|service'} "
"| Select-Object TimeCreated,@{N='Account';E={$_.Properties[5].Value}},"
"@{N='LogonType';E={$_.Properties[8].Value}},"
"@{N='SourceIP';E={$_.Properties[18].Value}} "
"| ConvertTo-Json"
)
try:
result = subprocess.check_output(
["powershell", "-NoProfile", "-Command", ps_cmd],
text=True, errors="replace", timeout=30
)
data = json.loads(result) if result.strip() else []
return data if isinstance(data, list) else [data]
except (subprocess.SubprocessError, json.JSONDecodeError):
return []
def analyze_logon_patterns(events):
"""Detect anomalous logon patterns for service accounts."""
anomalies = []
account_sources = {}
for evt in events:
acct = evt.get("Account", "unknown")
src = evt.get("SourceIP", "unknown")
account_sources.setdefault(acct, []).append(src)
for acct, sources in account_sources.items():
unique = set(sources)
if len(unique) > 3:
anomalies.append({
"account": acct,
"issue": "Service account logged in from multiple sources",
"source_count": len(unique),
"sources": list(unique)[:10],
})
return anomalies
def check_account_risks(accounts):
"""Identify risky service account configurations."""
risks = []
for acct in accounts:
name = acct.get("SamAccountName", "unknown")
issues = []
if acct.get("PasswordNeverExpires"):
issues.append("Password never expires")
if acct.get("AdminCount") == 1:
issues.append("Has AdminCount=1 (privileged)")
if acct.get("Enabled") is False:
issues.append("Account disabled but has SPNs")
pw_set = acct.get("PasswordLastSet")
if pw_set and isinstance(pw_set, str):
try:
pw_date = datetime.fromisoformat(pw_set.replace("Z", "+00:00"))
age = (datetime.now(timezone.utc) - pw_date).days
if age > 365:
issues.append(f"Password {age} days old")
except ValueError:
pass
if issues:
risks.append({"account": name, "issues": issues, "risk_count": len(issues)})
return risks
def main():
parser = argparse.ArgumentParser(
description="Detect service account abuse in AD environments"
)
parser.add_argument("--days", type=int, default=7, help="Lookback days for logon events")
parser.add_argument("--output", "-o", help="Output JSON report path")
parser.add_argument("--verbose", "-v", action="store_true")
args = parser.parse_args()
print("[*] Service Account Abuse Detection Agent")
report = {"timestamp": datetime.now(timezone.utc).isoformat(), "findings": {}}
accounts = query_ad_service_accounts()
report["findings"]["service_accounts"] = len(accounts)
print(f"[*] Found {len(accounts)} service accounts with SPNs")
risks = check_account_risks(accounts)
report["findings"]["risky_accounts"] = risks
print(f"[*] Risky accounts: {len(risks)}")
logons = check_interactive_logons(args.days)
report["findings"]["interactive_logons"] = len(logons)
anomalies = analyze_logon_patterns(logons)
report["findings"]["logon_anomalies"] = anomalies
print(f"[*] Logon anomalies: {len(anomalies)}")
total_issues = len(risks) + len(anomalies)
report["risk_level"] = "CRITICAL" if total_issues >= 5 else "HIGH" if total_issues >= 3 else "MEDIUM" if total_issues > 0 else "LOW"
if args.output:
with open(args.output, "w") as f:
json.dump(report, f, indent=2)
print(f"[*] Report saved to {args.output}")
else:
print(json.dumps(report, indent=2))
if __name__ == "__main__":
main()
process.py3.5 KB
Display-only source. This catalog never executes bundled scripts.
#!/usr/bin/env python3
"""Service Account Abuse Detection - Analyzes logs for T1078.002 indicators."""
import json, csv, argparse, datetime, re
from collections import defaultdict
from pathlib import Path
DETECTION_PATTERNS = [
r'svc_.*Logon_Type=(2|10)',
r'service.*interactive',
]
def parse_logs(path):
p = Path(path)
if p.suffix == ".json":
with open(p, encoding="utf-8") as f:
data = json.load(f)
return data if isinstance(data, list) else data.get("events", [])
elif p.suffix == ".csv":
with open(p, encoding="utf-8-sig") as f:
return [dict(r) for r in csv.DictReader(f)]
return []
def analyze_event(event):
cmd = event.get("CommandLine", event.get("command_line", event.get("ProcessCommandLine", "")))
content = event.get("Task_Content", event.get("Parameters", event.get("RawEventData", "")))
search_text = f"{cmd} {content}"
risk = 0
indicators = []
for pattern in DETECTION_PATTERNS:
if re.search(pattern, search_text, re.IGNORECASE):
risk += 25
indicators.append(f"Pattern match: {pattern}")
if not indicators:
return None
risk = min(risk, 100)
return {
"technique": "T1078.002",
"command_line": cmd[:500] if cmd else content[:500],
"hostname": event.get("Computer", event.get("DeviceName", event.get("hostname", "unknown"))),
"user": event.get("User", event.get("AccountName", event.get("UserId", "unknown"))),
"timestamp": event.get("_time", event.get("timestamp", event.get("UtcTime", event.get("Timestamp", "")))),
"risk_score": risk,
"risk_level": "CRITICAL" if risk >= 75 else "HIGH" if risk >= 50 else "MEDIUM" if risk >= 25 else "LOW",
"indicators": indicators,
}
def run_hunt(input_path, output_dir):
print(f"[*] Service Account Abuse Hunt - {datetime.datetime.now().isoformat()}")
events = parse_logs(input_path)
findings = [f for f in (analyze_event(e) for e in events) if f]
Path(output_dir).mkdir(parents=True, exist_ok=True)
slug = "detecting_service_ac"
with open(Path(output_dir) / f"{slug}_findings.json", "w", encoding="utf-8") as f:
json.dump({"hunt_id": f"TH-{datetime.date.today()}", "total_events": len(events), "findings": findings}, f, indent=2)
with open(Path(output_dir) / "hunt_report.md", "w", encoding="utf-8") as f:
f.write(f"# Service Account Abuse Hunt Report\n\n")
f.write(f"**Date**: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"**Findings**: {len(findings)}\n\n")
for finding in sorted(findings, key=lambda x: x["risk_score"], reverse=True)[:20]:
f.write(f"### [{finding['risk_level']}] {finding['technique']}\n")
f.write(f"- **Host**: {finding['hostname']}\n")
f.write(f"- **Indicators**: {', '.join(finding['indicators'])}\n\n")
print(f"[+] {len(findings)} findings written to {output_dir}")
def main():
p = argparse.ArgumentParser(description="Service Account Abuse Detection")
sp = p.add_subparsers(dest="cmd")
h = sp.add_parser("hunt"); h.add_argument("--input", "-i", required=True); h.add_argument("--output", "-o", default="./detecting_servi_output")
sp.add_parser("queries")
args = p.parse_args()
if args.cmd == "hunt": run_hunt(args.input, args.output)
elif args.cmd == "queries":
print("=== Detection Queries ===")
print("See references/workflows.md for platform-specific queries")
else: p.print_help()
if __name__ == "__main__": main()
Assets 1
template.mdtext/markdown · 2.6 KBKeep exploring