Collection activity hunting¶
Proactively hunting for evidence of data collection in progress or recently completed, before exfiltration occurs.
Hunt 1: AD enumeration anomalies¶
Unusual LDAP query volume or pattern from a host that does not normally perform AD administration.
# identify hosts generating high LDAP query volume (requires AD audit logs)
Get-WinEvent -LogName Security |
Where-Object { $_.Id -eq 4662 } |
Group-Object -Property { $_.Properties[1].Value } | # group by Subject Account
Where-Object { $_.Count -gt 500 } |
Sort-Object Count -Descending |
Select-Object Name, Count
# cross-reference with known admin hosts
$adminHosts = @('DC01', 'MGMT01', 'SCCM01') # populate with known admin hosts
# flag any high-count results NOT in $adminHosts
# from Zeek/Suricata: detect BloodHound characteristic LDAP queries
# BloodHound queries for: objectSid, adminCount, servicePrincipalName, etc.
# in rapid succession from a single source
zeek-cut id.orig_h id.resp_h query -d '\t' < ldap.log |
awk '{count[$1]++} END {for (h in count) if (count[h] > 200) print h, count[h]}' |
sort -k2 -rn | head -20
Hunt 2: LSASS access anomalies¶
# Sysmon Event ID 10: unexpected processes accessing LSASS
$expected = @('C:\Windows\System32\svchost.exe',
'C:\Program Files\CrowdStrike\CSFalconService.exe',
'C:\Program Files\SentinelOne\*') # populate with known EDR paths
Get-WinEvent -LogName 'Microsoft-Windows-Sysmon/Operational' |
Where-Object { $_.Id -eq 10 -and $_.Message -match 'lsass' } |
ForEach-Object {
$source = ($_.Message | Select-String 'SourceImage: (.+)').Matches.Groups[1].Value.Trim()
$access = ($_.Message | Select-String 'GrantedAccess: (.+)').Matches.Groups[1].Value.Trim()
[PSCustomObject]@{
Time = $_.TimeCreated
Source = $source
Access = $access
}
} |
Where-Object {
$src = $_.Source
-not ($expected | Where-Object { $src -like $_ })
} | Format-Table
Hunt 3: credential files accessed outside normal context¶
# Sysmon Event ID 11: file created; Event ID 15: stream created
# look for access to known credential file paths
$credPaths = @(
'*\.aws\credentials',
'*\.azure\accessTokens.json',
'*\.azure\msal_token_cache*',
'*\gcloud\credentials*',
'*\AppData\Local\Google\Chrome\User Data\Default\Login Data'
)
Get-WinEvent -LogName 'Microsoft-Windows-Sysmon/Operational' |
Where-Object { $_.Id -in @(11, 15) } |
Where-Object {
$path = ($_.Message | Select-String 'TargetFilename: (.+)').Matches.Groups[1].Value
$credPaths | Where-Object { $path -like $_ }
} | Format-List TimeCreated, Message
Hunt 4: bulk download from SharePoint¶
# Microsoft 365 Unified Audit Log: bulk file access from a single identity
# over a short window
$yesterday = (Get-Date).AddDays(-1)
$downloads = Search-UnifiedAuditLog `
-StartDate $yesterday -EndDate (Get-Date) `
-Operations 'FileDownloaded','FileSyncDownloadedFull','FileAccessed' |
ForEach-Object {
$data = $_.AuditData | ConvertFrom-Json
[PSCustomObject]@{
Time = $_.CreationDate
User = $_.UserIds
File = $data.SourceFileName
SiteUrl = $data.SiteUrl
ClientIP = $data.ClientIP
}
}
$downloads |
Group-Object -Property User |
Where-Object { $_.Count -gt 200 } |
Select-Object Name, Count |
Sort-Object Count -Descending
Hunt 5: credential harvesting via process injection into LSASS¶
# look for processes that migrated or injected into LSASS
# Sysmon Event ID 8: CreateRemoteThread targeting LSASS
Get-WinEvent -LogName 'Microsoft-Windows-Sysmon/Operational' |
Where-Object { $_.Id -eq 8 -and $_.Message -match 'lsass' } |
Format-List TimeCreated, Message
Hunt 6: shadow copy and VSS access¶
# SAM extraction via VSS uses specific process behaviour
# look for access to HarddiskVolumeShadowCopy paths
Get-WinEvent -LogName 'Microsoft-Windows-Sysmon/Operational' |
Where-Object { $_.Id -eq 11 -and $_.Message -match 'HarddiskVolumeShadowCopy' } |
Format-List TimeCreated, Message
Hunt 7: cloud metadata access from unexpected processes¶
# on EC2 Linux: detect unexpected processes accessing IMDS
# use auditd to monitor connections to 169.254.169.254
ausearch -k imds_access --start yesterday | aureport -x --summary
# expected processes: AWS CLI, SSM agent, CloudWatch agent
# unexpected: curl, python, powershell (without a known legitimate use case)
Triage and investigation workflow¶
When a hunt produces a hit:
Identify the source identity and host
Determine whether the activity corresponds to a known administrative task (query the change management system or ask the account owner)
If unaccounted for: pull related Sysmon events for the same host and timeframe (+/- 2 hours)
Check outbound network connections from that host in the same window (look for new external destinations)
Check whether any scheduled tasks, services, or WMI subscriptions were created from that host in the same window
Escalate to incident response if no legitimate explanation is found