mirror of
https://github.com/mukul975/Anthropic-Cybersecurity-Skills.git
synced 2026-08-02 09:07:41 +03:00
Initial commit - 611 cybersecurity skills across all subdomains
This commit is contained in:
@@ -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()
|
||||
Reference in New Issue
Block a user