Detection rules › Kusto
Suspicious SPN logon from workstation (DumpGuard)
With the DumpGuard tool, attackers are able to dump credetials via Remote Credential Guard on devices that have Credential Guard enabled. Since the DumpGuard tool needs to use an SPN enabled account (in the POC they use a machine account) for two exploitation scenario's, it is interesting to look for TGT requests happening from client devices for SPN enabled accounts.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Credential Access | T1003.004 OS Credential Dumping: LSA Secrets |
References
Rule body yaml
let spn_accounts = toscalar(
// Search for all SPNs we can find in historic logs
IdentityLogonEvents
| where TimeGenerated > ago(14d)
| where Application == "Active Directory"
| where isnotempty(AdditionalFields.Spns)
| extend Spns = split(AdditionalFields.Spns, ",")
| summarize make_set(Spns)
);
let workstation_subnets = toscalar(
DeviceNetworkInfo
| where TimeGenerated > ago(14d)
// Filter out empty device names
| where isnotempty(DeviceName)
// Expand IP Addresses
| mv-expand todynamic(IPAddresses)
// Focus on device name and IP Address info
| distinct DeviceName, tostring(IPAddresses)
// Filter out IPv6 addresses, /32 addresses, and APIPA addresses
| where todynamic(IPAddresses).IPAddress !contains ":"
| where todynamic(IPAddresses).SubnetPrefix != "32"
| where todynamic(IPAddresses).IPAddress !startswith "169.254"
// Find Device Type of the device
| join kind=inner (
DeviceInfo
| where TimeGenerated > ago(30d)
| distinct DeviceName, DeviceType
) on DeviceName
// Only focus on workstations
| where DeviceType == "Workstation"
// Create Network Address based on the host IP Address and create a distinct list
| extend NetworkAddress = format_ipv4_mask(tostring(todynamic(IPAddresses).IPAddress), tolong(todynamic(IPAddresses).SubnetPrefix))
| summarize make_set(NetworkAddress)
);
IdentityLogonEvents
| where TimeGenerated > ago(1h)
// Get AD TGT requests by looking for Kerberos requests to KRBTGT account
| where Application == "Active Directory"
| where Protocol == "Kerberos"
| where AdditionalFields.Spns contains "krbtgt"
// Check for requests to account names with SPNs
| where AccountName in (spn_accounts)
// Check if IP Address is from a client range
| where ipv4_is_in_any_range(IPAddress, workstation_subnets)
// Optional - Ignore failed logins
| where ActionType != "LogonFailed"
Stages and Predicates
Let binding: spn_accounts
let spn_accounts = toscalar(
IdentityLogonEvents
| where TimeGenerated > ago(14d)
| where Application == "Active Directory"
| where isnotempty(AdditionalFields.Spns)
| extend Spns = split(AdditionalFields.Spns, ",")
| summarize make_set(Spns)
);
Let binding: workstation_subnets
let workstation_subnets = toscalar(
DeviceNetworkInfo
| where TimeGenerated > ago(14d)
| where isnotempty(DeviceName)
| mv-expand todynamic(IPAddresses)
| distinct DeviceName, tostring(IPAddresses)
| where todynamic(IPAddresses).IPAddress !contains ":"
| where todynamic(IPAddresses).SubnetPrefix != "32"
| where todynamic(IPAddresses).IPAddress !startswith "169.254"
| join kind=inner (
DeviceInfo
| where TimeGenerated > ago(30d)
| distinct DeviceName, DeviceType
) on DeviceName
| where DeviceType == "Workstation"
| extend NetworkAddress = format_ipv4_mask(tostring(todynamic(IPAddresses).IPAddress), tolong(todynamic(IPAddresses).SubnetPrefix))
| summarize make_set(NetworkAddress)
);
Stage 1: source
IdentityLogonEvents
Stage 2: where
| where TimeGenerated > ago(1h)
Stage 3: where
| where Application == "Active Directory"
Stage 4: where
| where Protocol == "Kerberos"
Stage 5: where
| where AdditionalFields.Spns contains "krbtgt"
Stage 6: where
| where AccountName in (spn_accounts)
References spn_accounts (defined above).
Stage 7: where
| where ipv4_is_in_any_range(IPAddress, workstation_subnets)
References workstation_subnets (defined above).
Stage 8: where
| where ActionType != "LogonFailed"
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
| Field | Kind | Values |
|---|---|---|
AccountName | in |
|
ActionType | ne |
|
Application | eq |
|
Protocol | eq |
|
Spns | contains |
|