Initial commit - 611 cybersecurity skills across all subdomains

This commit is contained in:
mukul975
2026-02-25 10:47:44 +01:00
commit 22a7ab1462
1765 changed files with 280648 additions and 0 deletions
@@ -0,0 +1,90 @@
---
name: detecting-credential-dumping-with-edr
description: Detect OS credential dumping techniques including LSASS access, SAM extraction, and DCSync using EDR telemetry and Sysmon logs.
domain: cybersecurity
subdomain: threat-hunting
tags: [threat-hunting, mitre-attack, credential-dumping, edr, lsass, t1003, proactive-detection]
version: "1.0"
author: mahipal
license: MIT
---
# Detecting Credential Dumping with EDR
## When to Use
- When hunting for post-exploitation credential theft in compromised environments
- After detecting suspicious LSASS process access in EDR alerts
- When investigating potential Active Directory compromise
- During incident response to determine scope of credential exposure
- When proactively hunting for T1003 sub-techniques across endpoints
## Prerequisites
- EDR platform with process access monitoring (CrowdStrike, MDE, SentinelOne)
- Sysmon deployed with Event ID 10 (Process Access) configured for LSASS
- Windows Security Event Log 4688 with command-line auditing enabled
- Active Directory event forwarding for DCSync detection (Event ID 4662)
- Windows Security Event Log 4656/4663 for SAM registry access
## Workflow
1. **Identify Credential Dumping Vectors**: Map the T1003 sub-techniques relevant to your environment (LSASS Memory, SAM, NTDS, DCSync, /etc/passwd, Cached Credentials).
2. **Query LSASS Access Events**: Search for Sysmon Event ID 10 where TargetImage is lsass.exe with suspicious GrantedAccess masks (0x1010, 0x1038, 0x1FFFFF).
3. **Analyze Process Context**: Examine the source process accessing LSASS - legitimate security tools vs. unknown or suspicious binaries.
4. **Hunt for SAM/NTDS Access**: Query for reg.exe save operations against SAM/SECURITY/SYSTEM hives and ntdsutil/vssadmin shadow copy access.
5. **Detect DCSync Activity**: Monitor for DS-Replication-Get-Changes requests from non-domain-controller sources (Event ID 4662).
6. **Correlate with Network Activity**: Cross-reference credential dumping with subsequent lateral movement or authentication anomalies.
7. **Assess Impact and Report**: Determine which credentials were potentially exposed and recommend password resets and containment.
## Key Concepts
| Concept | Description |
|---------|-------------|
| T1003 | OS Credential Dumping - parent technique |
| T1003.001 | LSASS Memory - dumping credentials from LSASS process |
| T1003.002 | Security Account Manager (SAM) - extracting local password hashes |
| T1003.003 | NTDS - extracting AD database from Domain Controllers |
| T1003.004 | LSA Secrets - accessing stored service credentials |
| T1003.005 | Cached Domain Credentials (DCC2) |
| T1003.006 | DCSync - replicating AD credentials via DRSUAPI |
| LSASS | Local Security Authority Subsystem Service |
| GrantedAccess | Bitmask indicating the access rights requested for a process |
| Minidump | Memory dump technique used by tools like comsvcs.dll |
## Tools & Systems
| Tool | Purpose |
|------|---------|
| CrowdStrike Falcon | LSASS access detection and process tree analysis |
| Microsoft Defender for Endpoint | Advanced hunting for credential access events |
| Sysmon | Process access monitoring (Event ID 10) |
| Velociraptor | Endpoint artifact collection for LSASS analysis |
| Elastic Security | Correlation of credential dumping indicators |
| Splunk | SPL queries for credential access event analysis |
| Volatility | Memory forensics for LSASS credential extraction |
## Common Scenarios
1. **Mimikatz LSASS Dump**: Attacker runs `sekurlsa::logonpasswords` causing direct LSASS memory read with GrantedAccess 0x1010.
2. **Comsvcs.dll MiniDump**: Process uses `rundll32.exe comsvcs.dll MiniDump [LSASS PID]` to create LSASS memory dump file.
3. **ProcDump LSASS**: Attacker uses Microsoft-signed procdump.exe with `-ma lsass.exe` to dump LSASS memory.
4. **SAM Registry Export**: Adversary runs `reg save HKLM\SAM sam.bak` to extract local password hashes.
5. **DCSync Replication**: Compromised account with Replicating Directory Changes permissions performs DCSync from a workstation.
6. **NTDS Shadow Copy**: Attacker uses `vssadmin create shadow /for=C:` then copies ntds.dit from the shadow copy.
## Output Format
```
Hunt ID: TH-CRED-DUMP-[DATE]-[SEQ]
Technique: T1003.[Sub-technique]
Source Process: [Process accessing LSASS/SAM/NTDS]
Target: [lsass.exe / SAM / NTDS.dit / DC Replication]
Host: [Hostname]
User: [Account context]
GrantedAccess: [Access mask if applicable]
Timestamp: [UTC]
Risk Level: [Critical/High/Medium/Low]
Evidence: [Log entries, process tree, network activity]
Recommended Action: [Password reset scope, containment steps]
```
@@ -0,0 +1,64 @@
# Credential Dumping Hunt Template
## Hunt Metadata
| Field | Value |
|-------|-------|
| Hunt ID | TH-CRED-DUMP-YYYY-MM-DD-NNN |
| Analyst | |
| Date | |
| Status | [ ] In Progress / [ ] Complete |
## Hypothesis
> [e.g., "Adversaries have used Mimikatz or similar tools to dump LSASS memory on compromised endpoints to harvest domain credentials."]
## Target Techniques
- [ ] T1003.001 - LSASS Memory
- [ ] T1003.002 - SAM Database
- [ ] T1003.003 - NTDS.dit
- [ ] T1003.004 - LSA Secrets
- [ ] T1003.005 - Cached Domain Credentials
- [ ] T1003.006 - DCSync
## Data Sources
- [ ] Sysmon Event ID 10 (Process Access)
- [ ] Sysmon Event ID 1 (Process Creation)
- [ ] Windows Security 4656/4663
- [ ] Windows Security 4662 (DCSync)
- [ ] EDR Telemetry: _______________
## LSASS Access Findings
| # | Timestamp | Host | User | Source Process | Access Mask | Risk | Verdict |
|---|-----------|------|------|---------------|-------------|------|---------|
| 1 | | | | | | | |
| 2 | | | | | | | |
## Tool Detection Findings
| # | Timestamp | Host | User | Tool | Command Line | Technique | Verdict |
|---|-----------|------|------|------|-------------|-----------|---------|
| 1 | | | | | | | |
| 2 | | | | | | | |
## DCSync Findings
| # | Timestamp | Source Host | User | Replication Right | Is Legitimate DC? | Verdict |
|---|-----------|------------|------|-------------------|-------------------|---------|
| 1 | | | | | | |
## Compromised Credentials Assessment
| Account | Type | Hash Type | Exposure Scope | Reset Required? |
|---------|------|-----------|---------------|----------------|
| | | | | |
## Recommendations
1. **Immediate Actions**: [Password resets, account lockouts]
2. **Containment**: [Isolate affected systems]
3. **Detection Improvements**: [New rules, LSASS protection]
4. **Hardening**: [Credential Guard, PPL, ASR rules]
@@ -0,0 +1,87 @@
# Standards and References - Credential Dumping Detection
## MITRE ATT&CK Mappings
### T1003 - OS Credential Dumping (Parent Technique)
| Sub-Technique | Name | Description |
|---------------|------|-------------|
| T1003.001 | LSASS Memory | Dumping credentials stored in LSASS process memory |
| T1003.002 | Security Account Manager | Extracting local hashes from SAM database |
| T1003.003 | NTDS | Stealing AD database from Domain Controllers |
| T1003.004 | LSA Secrets | Accessing stored service account credentials |
| T1003.005 | Cached Domain Credentials | Extracting DCC2 hashed credentials |
| T1003.006 | DCSync | Simulating DC replication to extract credentials |
| T1003.007 | Proc Filesystem (/proc) | Linux credential extraction |
| T1003.008 | /etc/passwd and /etc/shadow | Unix credential files |
### Related Techniques
- **T1555 - Credentials from Password Stores**: Browser, keychain, password manager credentials
- **T1552 - Unsecured Credentials**: Files, registry, bash history, cloud metadata
- **T1558 - Steal or Forge Kerberos Tickets**: Kerberoasting, Golden/Silver tickets
- **T1550 - Use Alternate Authentication Material**: Pass the Hash, Pass the Ticket
### Tactic
- **TA0006 - Credential Access**
## Detection Data Sources
### LSASS Access Detection
| Source | Event ID | Details |
|--------|----------|---------|
| Sysmon | 10 | ProcessAccess - TargetImage = lsass.exe |
| Windows Security | 4656 | Handle requested to process object |
| Windows Security | 4663 | Attempt to access process object |
| Windows Security | 4688 | Process creation with command line |
| ETW | Microsoft-Windows-Kernel-Process | Kernel-level process access |
### SAM/Registry Detection
| Source | Event ID | Details |
|--------|----------|---------|
| Sysmon | 1 | reg.exe with save SAM/SECURITY/SYSTEM |
| Windows Security | 4656 | Handle to registry key |
| Windows Security | 4688 | reg.exe/regedit.exe command line |
### DCSync Detection
| Source | Event ID | Details |
|--------|----------|---------|
| Windows Security | 4662 | DS-Replication-Get-Changes operation |
| Windows Security | 4624/4625 | Authentication to DC from non-DC source |
| Network | DRSUAPI | RPC calls for directory replication |
### NTDS Access Detection
| Source | Event ID | Details |
|--------|----------|---------|
| Sysmon | 1 | ntdsutil.exe, vssadmin.exe execution |
| Windows Security | 4688 | Shadow copy creation commands |
| VSS | 8224 | Volume Shadow Copy Service operations |
## LSASS Access Mask Reference
| Access Mask | Hex | Meaning |
|-------------|-----|---------|
| PROCESS_VM_READ | 0x0010 | Read process memory |
| PROCESS_QUERY_INFORMATION | 0x0400 | Query process info |
| 0x1010 | Combined | VM_READ + QUERY_INFO (Mimikatz default) |
| 0x1038 | Combined | Common credential dumping mask |
| 0x1FFFFF | PROCESS_ALL_ACCESS | Full access to process |
| 0x0410 | Combined | Query + VM_READ minimal |
## Known Credential Dumping Tools
| Tool | Technique | Detection Signature |
|------|-----------|-------------------|
| Mimikatz | T1003.001, T1003.006 | LSASS access with 0x1010, sekurlsa module |
| LaZagne | T1003.001, T1555 | Multi-credential extractor |
| ProcDump | T1003.001 | Signed MS tool, -ma lsass.exe |
| comsvcs.dll | T1003.001 | MiniDump via rundll32 |
| secretsdump.py | T1003.002, T1003.003, T1003.006 | Impacket DCSync/SAM |
| ntdsutil.exe | T1003.003 | IFM creation for NTDS |
| SharpDump | T1003.001 | .NET LSASS dumper |
| PPLdump | T1003.001 | PPL bypass LSASS dump |
| nanodump | T1003.001 | Stealthy minidump |
## Regulatory References
- NIST SP 800-171 Rev 2: 3.1.1 (Access Control)
- CIS Controls v8: Control 6 (Access Control Management)
- PCI DSS 4.0: Requirement 7 (Restrict Access)
@@ -0,0 +1,134 @@
# Detailed Hunting Workflow - Credential Dumping Detection
## Phase 1: LSASS Memory Access Hunting
### Step 1.1 - Sysmon Event ID 10 Analysis
```spl
index=sysmon EventCode=10 TargetImage="*\\lsass.exe"
| where NOT match(SourceImage, "(?i)(csrss|svchost|services|lsass|wininit|MsMpEng|MsSense|CrowdStrike)")
| eval suspicious_access=case(
GrantedAccess="0x1FFFFF", "CRITICAL-Full_Access",
GrantedAccess="0x1010", "HIGH-VM_Read_Query",
GrantedAccess="0x1038", "HIGH-Credential_Dump_Mask",
GrantedAccess="0x0410", "MEDIUM-Query_VM_Read",
1=1, "LOW-Other"
)
| stats count by SourceImage, GrantedAccess, suspicious_access, Computer, User
| sort -count
```
### Step 1.2 - KQL for Microsoft Defender for Endpoint
```kql
DeviceEvents
| where Timestamp > ago(7d)
| where ActionType == "OpenProcessApiCall"
| where FileName == "lsass.exe"
| where InitiatingProcessFileName !in~ ("csrss.exe","svchost.exe","services.exe","MsMpEng.exe")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName,
InitiatingProcessCommandLine, AdditionalFields
| order by Timestamp desc
```
### Step 1.3 - CrowdStrike Falcon Query
```
event_simpleName=ProcessRollup2 TargetProcessImageFileName=lsass.exe
| where ContextProcessImageFileName!="csrss.exe" AND ContextProcessImageFileName!="svchost.exe"
| stats count by ContextProcessImageFileName ComputerName UserName
```
## Phase 2: SAM/SECURITY Hive Access
### Step 2.1 - Registry Save Operations
```spl
index=sysmon EventCode=1
| where match(CommandLine, "(?i)reg\s+(save|export)\s+.*(SAM|SECURITY|SYSTEM)")
| table _time Computer User Image CommandLine ParentImage
```
### Step 2.2 - Shadow Copy for SAM Access
```spl
index=sysmon EventCode=1
| where match(CommandLine, "(?i)(vssadmin|wmic)\s+.*(shadow|create)")
| append [
search index=sysmon EventCode=1
| where match(CommandLine, "(?i)copy.*\\\\?\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy")
]
| table _time Computer User CommandLine ParentImage
```
## Phase 3: DCSync Detection
### Step 3.1 - Directory Replication Monitoring
```spl
index=wineventlog EventCode=4662
| where match(Properties, "(?i)(1131f6aa|1131f6ad|89e95b76)")
| where NOT match(SubjectUserName, "(?i)(\\$|DomainController)")
| table _time SubjectUserName SubjectDomainName ObjectName Properties
```
The GUIDs to monitor:
- `1131f6aa-9c07-11d1-f79f-00c04fc2dcd2` = DS-Replication-Get-Changes
- `1131f6ad-9c07-11d1-f79f-00c04fc2dcd2` = DS-Replication-Get-Changes-All
- `89e95b76-444d-4c62-991a-0facbeda640c` = DS-Replication-Get-Changes-In-Filtered-Set
### Step 3.2 - Non-DC Source Validation
```kql
SecurityEvent
| where EventID == 4662
| where Properties has "1131f6ad-9c07-11d1-f79f-00c04fc2dcd2"
| where Computer !in (known_domain_controllers)
| project TimeGenerated, Computer, SubjectAccount, SubjectDomainName
```
## Phase 4: Tool-Specific Detection
### Step 4.1 - Mimikatz Indicators
```spl
index=sysmon (EventCode=1 OR EventCode=10)
| where match(CommandLine, "(?i)(sekurlsa|lsadump|kerberos::list|crypto::cng|privilege::debug)")
OR (EventCode=10 AND TargetImage="*\\lsass.exe" AND GrantedAccess IN ("0x1010","0x1038"))
| table _time EventCode Computer User Image CommandLine GrantedAccess
```
### Step 4.2 - Comsvcs.dll MiniDump Detection
```spl
index=sysmon EventCode=1 Image="*\\rundll32.exe"
| where match(CommandLine, "(?i)comsvcs.*MiniDump")
| table _time Computer User CommandLine ParentImage
```
### Step 4.3 - ProcDump LSASS Detection
```spl
index=sysmon EventCode=1
| where match(CommandLine, "(?i)procdump.*(-ma|-accepteula).*lsass")
| table _time Computer User CommandLine ParentImage
```
## Phase 5: Correlation and Impact Assessment
### Step 5.1 - Post-Credential-Dump Lateral Movement
```spl
index=sysmon EventCode=10 TargetImage="*\\lsass.exe" GrantedAccess IN ("0x1010","0x1038","0x1FFFFF")
| rename Computer as src_host
| join src_host [
search index=wineventlog EventCode=4624 Logon_Type=3
| rename Computer as src_host
]
| table _time src_host User SourceImage dest_host
```
### Step 5.2 - Timeline Construction
Build a timeline correlating:
1. Initial LSASS access event (credential dump)
2. Subsequent authentication events (Pass-the-Hash/Ticket)
3. Lateral movement to new hosts
4. Additional credential dumping on new hosts
## Phase 6: Reporting
### Key Metrics to Report
- Number of unique hosts with LSASS access anomalies
- Tools identified (known vs. custom)
- Accounts potentially compromised
- Lateral movement scope
- Time from initial dump to last detected activity
@@ -0,0 +1,383 @@
#!/usr/bin/env python3
"""
Credential Dumping Detection Script
Analyzes process access logs for LSASS memory access, SAM extraction,
DCSync activity, and other credential theft indicators.
"""
import json
import csv
import argparse
import datetime
import re
import sys
from collections import defaultdict
from pathlib import Path
# Suspicious LSASS access masks indicating credential dumping
SUSPICIOUS_ACCESS_MASKS = {
"0x1FFFFF": {"risk": "CRITICAL", "description": "PROCESS_ALL_ACCESS - full process access"},
"0x1010": {"risk": "HIGH", "description": "PROCESS_VM_READ + PROCESS_QUERY_INFORMATION (Mimikatz default)"},
"0x1038": {"risk": "HIGH", "description": "Common credential dumping access mask"},
"0x0410": {"risk": "MEDIUM", "description": "PROCESS_QUERY_INFORMATION + PROCESS_VM_READ"},
"0x1400": {"risk": "MEDIUM", "description": "PROCESS_QUERY_INFORMATION + PROCESS_QUERY_LIMITED"},
"0x0040": {"risk": "HIGH", "description": "PROCESS_DUP_HANDLE - handle duplication"},
"0x0810": {"risk": "HIGH", "description": "PROCESS_SUSPEND_RESUME + PROCESS_VM_READ"},
"0x1fffff": {"risk": "CRITICAL", "description": "PROCESS_ALL_ACCESS (lowercase)"},
}
# Legitimate processes that commonly access LSASS
LSASS_WHITELIST = {
"csrss.exe", "svchost.exe", "services.exe", "lsass.exe", "wininit.exe",
"smss.exe", "wmiprvse.exe", "taskmgr.exe", "procexp.exe", "procexp64.exe",
"msmpsvc.exe", "msmpeng.exe", "nissrv.exe", "mssense.exe", "sensecncproxy.exe",
"csfalconservice.exe", "csfalconcontainer.exe",
"sentinelagent.exe", "sentinelone.exe",
"cb.exe", "carbonblack.exe",
"logrhythmagent.exe",
}
# Known credential dumping tool command-line patterns
CRED_DUMP_TOOL_PATTERNS = {
"mimikatz": {
"patterns": [
r"sekurlsa::",
r"lsadump::",
r"kerberos::list",
r"crypto::cng",
r"privilege::debug",
r"token::elevate",
r"dpapi::",
r"vault::cred",
],
"technique": "T1003.001/T1003.006",
},
"comsvcs_minidump": {
"patterns": [
r"comsvcs\.dll.*MiniDump",
r"comsvcs\.dll.*#24",
],
"technique": "T1003.001",
},
"procdump": {
"patterns": [
r"procdump.*-ma.*lsass",
r"procdump.*lsass.*-ma",
r"procdump.*-accepteula.*lsass",
],
"technique": "T1003.001",
},
"reg_save": {
"patterns": [
r"reg\s+(save|export)\s+HKLM\\SAM",
r"reg\s+(save|export)\s+HKLM\\SECURITY",
r"reg\s+(save|export)\s+HKLM\\SYSTEM",
],
"technique": "T1003.002",
},
"ntdsutil": {
"patterns": [
r"ntdsutil.*ifm",
r"ntdsutil.*\"activate instance ntds\"",
r"ntdsutil.*create full",
],
"technique": "T1003.003",
},
"vssadmin_shadow": {
"patterns": [
r"vssadmin.*create\s+shadow",
r"copy.*GLOBALROOT.*Device.*HarddiskVolumeShadowCopy",
r"wmic.*shadowcopy.*create",
],
"technique": "T1003.003",
},
"secretsdump": {
"patterns": [
r"secretsdump",
r"impacket.*dump",
],
"technique": "T1003.002/T1003.003/T1003.006",
},
"lazagne": {
"patterns": [
r"lazagne",
r"LaZagne\.exe",
],
"technique": "T1003.001/T1555",
},
"sharpdump": {
"patterns": [
r"SharpDump",
r"sharpdump",
],
"technique": "T1003.001",
},
"nanodump": {
"patterns": [
r"nanodump",
],
"technique": "T1003.001",
},
}
# DCSync detection GUIDs
DCSYNC_GUIDS = {
"1131f6aa-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes",
"1131f6ad-9c07-11d1-f79f-00c04fc2dcd2": "DS-Replication-Get-Changes-All",
"89e95b76-444d-4c62-991a-0facbeda640c": "DS-Replication-Get-Changes-In-Filtered-Set",
}
def parse_logs(input_path: str) -> list[dict]:
"""Parse log files in JSON or CSV format."""
events = []
path = Path(input_path)
if path.suffix == ".json":
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
events = data if isinstance(data, list) else data.get("events", data.get("hits", {}).get("hits", []))
if events and isinstance(events[0], dict) and "_source" in events[0]:
events = [e["_source"] for e in events]
elif path.suffix == ".csv":
with open(path, "r", encoding="utf-8-sig") as f:
reader = csv.DictReader(f)
events = [dict(row) for row in reader]
return events
def normalize_event(event: dict) -> dict:
"""Normalize event field names."""
field_map = {
"source_image": ["SourceImage", "source_image", "InitiatingProcessFileName", "process.executable"],
"target_image": ["TargetImage", "target_image", "FileName", "target.process.executable"],
"granted_access": ["GrantedAccess", "granted_access", "AccessMask"],
"command_line": ["CommandLine", "command_line", "ProcessCommandLine", "process.command_line"],
"user": ["User", "user", "AccountName", "SubjectUserName", "user.name"],
"hostname": ["Computer", "hostname", "DeviceName", "host.name"],
"timestamp": ["UtcTime", "timestamp", "Timestamp", "@timestamp"],
"event_id": ["EventID", "EventCode", "event_id", "event.code"],
"parent_image": ["ParentImage", "parent_image", "InitiatingProcessParentFileName"],
"properties": ["Properties", "properties", "ObjectType"],
}
normalized = {}
for target, sources in field_map.items():
for src in sources:
if src in event and event[src]:
normalized[target] = str(event[src])
break
if target not in normalized:
normalized[target] = ""
return normalized
def detect_lsass_access(event: dict) -> dict | None:
"""Detect suspicious LSASS process access."""
target = event.get("target_image", "").lower()
if "lsass.exe" not in target:
return None
source = event.get("source_image", "").lower()
source_name = source.split("\\")[-1].split("/")[-1]
access = event.get("granted_access", "").lower()
# Skip whitelisted processes
if source_name in LSASS_WHITELIST:
return None
risk_info = SUSPICIOUS_ACCESS_MASKS.get(access, SUSPICIOUS_ACCESS_MASKS.get(access.upper()))
if not risk_info:
risk_info = {"risk": "LOW", "description": f"Unknown access mask: {access}"}
return {
"detection_type": "LSASS_ACCESS",
"technique": "T1003.001",
"source_process": event.get("source_image", ""),
"target_process": event.get("target_image", ""),
"granted_access": access,
"access_description": risk_info["description"],
"risk_level": risk_info["risk"],
"user": event.get("user", "unknown"),
"hostname": event.get("hostname", "unknown"),
"timestamp": event.get("timestamp", "unknown"),
"indicators": [f"LSASS access from {source_name} with mask {access}"],
}
def detect_credential_tool(event: dict) -> dict | None:
"""Detect known credential dumping tool execution."""
cmd = event.get("command_line", "")
if not cmd:
return None
for tool_name, tool_info in CRED_DUMP_TOOL_PATTERNS.items():
for pattern in tool_info["patterns"]:
if re.search(pattern, cmd, re.IGNORECASE):
return {
"detection_type": "CREDENTIAL_TOOL",
"technique": tool_info["technique"],
"tool": tool_name,
"command_line": cmd,
"source_process": event.get("source_image", ""),
"parent_process": event.get("parent_image", ""),
"risk_level": "CRITICAL",
"user": event.get("user", "unknown"),
"hostname": event.get("hostname", "unknown"),
"timestamp": event.get("timestamp", "unknown"),
"indicators": [f"Credential tool detected: {tool_name}", f"Pattern matched: {pattern}"],
}
return None
def detect_dcsync(event: dict) -> dict | None:
"""Detect DCSync activity from non-DC sources."""
props = event.get("properties", "")
for guid, name in DCSYNC_GUIDS.items():
if guid.lower() in props.lower():
return {
"detection_type": "DCSYNC",
"technique": "T1003.006",
"replication_right": name,
"guid": guid,
"risk_level": "CRITICAL",
"user": event.get("user", "unknown"),
"hostname": event.get("hostname", "unknown"),
"timestamp": event.get("timestamp", "unknown"),
"indicators": [f"DCSync activity: {name}", f"GUID: {guid}"],
}
return None
def run_hunt(input_path: str, output_dir: str, dc_list: list[str] | None = None) -> None:
"""Execute credential dumping hunt."""
print(f"[*] Credential Dumping Hunt - {datetime.datetime.now().isoformat()}")
print(f"[*] Input: {input_path}")
events = parse_logs(input_path)
print(f"[*] Loaded {len(events)} events")
findings = []
stats = defaultdict(int)
for raw_event in events:
event = normalize_event(raw_event)
# Check for LSASS access
result = detect_lsass_access(event)
if result:
findings.append(result)
stats["LSASS_ACCESS"] += 1
stats[result["risk_level"]] += 1
# Check for credential dumping tools
result = detect_credential_tool(event)
if result:
findings.append(result)
stats["CREDENTIAL_TOOL"] += 1
stats[result["risk_level"]] += 1
# Check for DCSync
result = detect_dcsync(event)
if result:
if dc_list and result["hostname"].lower() in [dc.lower() for dc in dc_list]:
continue # Skip legitimate DC replication
findings.append(result)
stats["DCSYNC"] += 1
stats[result["risk_level"]] += 1
# Write output
output_path = Path(output_dir)
output_path.mkdir(parents=True, exist_ok=True)
findings_file = output_path / "credential_dump_findings.json"
with open(findings_file, "w", encoding="utf-8") as f:
json.dump({
"hunt_id": f"TH-CRED-DUMP-{datetime.date.today().isoformat()}",
"timestamp": datetime.datetime.now().isoformat(),
"total_events": len(events),
"total_findings": len(findings),
"statistics": dict(stats),
"findings": findings,
}, f, indent=2)
# Write report
report_file = output_path / "hunt_report.md"
with open(report_file, "w", encoding="utf-8") as f:
f.write(f"# Credential Dumping Hunt Report\n\n")
f.write(f"**Date**: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n")
f.write(f"**Events Analyzed**: {len(events)}\n")
f.write(f"**Findings**: {len(findings)}\n\n")
f.write("## Detection Breakdown\n\n")
for key, count in sorted(stats.items()):
f.write(f"- {key}: {count}\n")
f.write("\n## Critical Findings\n\n")
for finding in sorted(findings, key=lambda x: ("CRITICAL", "HIGH", "MEDIUM", "LOW").index(x["risk_level"])):
if finding["risk_level"] in ("CRITICAL", "HIGH"):
f.write(f"### [{finding['risk_level']}] {finding['detection_type']} - {finding['technique']}\n")
f.write(f"- **Host**: {finding['hostname']}\n")
f.write(f"- **User**: {finding['user']}\n")
f.write(f"- **Indicators**: {', '.join(finding['indicators'])}\n\n")
print(f"[+] Output written to {output_dir}")
print(f"\n{'='*60}")
print(f"FINDINGS: {len(findings)} | CRITICAL: {stats.get('CRITICAL',0)} | HIGH: {stats.get('HIGH',0)}")
print(f"{'='*60}")
def generate_queries(platform: str) -> None:
"""Generate hunting queries for specified platform."""
if platform in ("splunk", "all"):
print("\n=== SPLUNK QUERIES ===\n")
print("--- LSASS Access Detection ---")
print("""index=sysmon EventCode=10 TargetImage="*\\\\lsass.exe"
| where NOT match(SourceImage, "(?i)(csrss|svchost|services|lsass|wininit|MsMpEng)")
| stats count by SourceImage GrantedAccess Computer User
| sort -count""")
print("\n--- Credential Tool Detection ---")
print("""index=sysmon EventCode=1
| where match(CommandLine, "(?i)(sekurlsa|lsadump|comsvcs.*MiniDump|procdump.*lsass|reg save.*SAM)")
| table _time Computer User Image CommandLine ParentImage""")
print("\n--- DCSync Detection ---")
print("""index=wineventlog EventCode=4662
| where match(Properties, "(?i)(1131f6aa|1131f6ad|89e95b76)")
| table _time SubjectUserName SubjectDomainName Computer Properties""")
if platform in ("kql", "all"):
print("\n=== KQL QUERIES ===\n")
print("--- LSASS Access ---")
print("""DeviceEvents
| where ActionType == "OpenProcessApiCall"
| where FileName == "lsass.exe"
| where InitiatingProcessFileName !in~ ("csrss.exe","svchost.exe","MsMpEng.exe")
| project Timestamp, DeviceName, AccountName, InitiatingProcessFileName, AdditionalFields""")
def main():
parser = argparse.ArgumentParser(description="Credential Dumping Detection Hunt")
subparsers = parser.add_subparsers(dest="command")
hunt_parser = subparsers.add_parser("hunt", help="Run credential dumping hunt")
hunt_parser.add_argument("--input", "-i", required=True, help="Log file path")
hunt_parser.add_argument("--output", "-o", default="./cred_dump_output", help="Output directory")
hunt_parser.add_argument("--dc-list", nargs="*", help="List of known DCs to exclude from DCSync alerts")
query_parser = subparsers.add_parser("queries", help="Generate hunting queries")
query_parser.add_argument("--platform", "-p", choices=["splunk", "kql", "all"], default="all")
subparsers.add_parser("signatures", help="List detection signatures")
args = parser.parse_args()
if args.command == "hunt":
run_hunt(args.input, args.output, args.dc_list)
elif args.command == "queries":
generate_queries(args.platform)
elif args.command == "signatures":
print("\n=== Credential Dumping Tool Signatures ===\n")
for tool, info in CRED_DUMP_TOOL_PATTERNS.items():
print(f"{tool:<25} {info['technique']:<25} Patterns: {len(info['patterns'])}")
else:
parser.print_help()
if __name__ == "__main__":
main()