Detection rules › Kusto
Hunt for ADWS requests from unknown devices
This hunting rule searches for incomming ADWS connections on Domain Controllers (DC's need to be onboarded in Defender for Endpoint) from IP Addresses that cannot be linked to MDE onboarded devices.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Discovery | |
| Lateral Movement | |
| Collection |
References
- https://falconforce.nl/soaphound-tool-to-collect-active-directory-data-via-adws/
- https://github.com/FalconForceTeam/FalconFriday/blob/master/Discovery/ADWS_Connection_from_Unexpected_Binary-Win.md
- https://github.com/FalconForceTeam/FalconFriday/blob/master/Discovery/ADWS_Connection_from_Process_Injection_Target-Win.md
- https://cyberlandsec.com/soapy-the-ultimate-stealthy-active-directory-enumeration-tool-via-adws/
- https://github.com/FalconForceTeam/SOAPHound
Telemetry coverage
Rule body
let device_info = (
// Get device network info from last 7 days
DeviceNetworkInfo
| where Timestamp > ago(7d)
// Expand the IP Addresses of the devices
| mv-expand todynamic(IPAddresses)
| extend IPAddress = tostring(IPAddresses.IPAddress)
// Distinct IP address for each device
| distinct DeviceName, DeviceId, IPAddress
// Search for each device if it is onboarded or not
| join kind=inner (
DeviceInfo
| where Timestamp > ago(7d)
| distinct DeviceName, DeviceId, OnboardingStatus
// Get the first timestamp the device was seen
| join kind=inner (
DeviceInfo
| where Timestamp > ago(30d)
| summarize FirstSeen = arg_min(Timestamp, DeviceId) by DeviceId
) on DeviceId
| project-away DeviceId1, DeviceId2
) on DeviceId, DeviceName
| project-away DeviceName1, DeviceId1
);
// Get incomming traffic on ADWS port and save unique remote IP addresses
DeviceNetworkEvents
| where Timestamp > ago(30d)
| where ActionType != "ListeningConnectionCreated"
| where InitiatingProcessFolderPath == @"c:\windows\adws\microsoft.activedirectory.webservices.exe"
| where LocalPort == "9389"
| summarize ConnectionTimes=make_list(Timestamp) by RemoteIP, DeviceName
// Get device information of remote IP addresses, results for IP we do not find information for are allowed
| join kind=leftouter device_info on $left.RemoteIP == $right.IPAddress
| project-away IPAddress
// Check if the remote IPs are onboarded devices or not
| where OnboardingStatus != "Onboarded"
// Make output better
| project DeviceName, ConnectionTimes, RemoteIP, RemoteDeviceName = DeviceName1, RemoteDeviceId = DeviceId, RemoteOnboardingStatus = OnboardingStatus, RemoteDeviceFirstSeen = FirstSeen
let device_info = (
// Get device network info from last 7 days
DeviceNetworkInfo
| where TimeGenerated > ago(7d)
// Expand the IP Addresses of the devices
| mv-expand todynamic(IPAddresses)
| extend IPAddress = tostring(IPAddresses.IPAddress)
// Distinct IP address for each device
| distinct DeviceName, DeviceId, IPAddress
// Search for each device if it is onboarded or not
| join kind=inner (
DeviceInfo
| where TimeGenerated > ago(7d)
| distinct DeviceName, DeviceId, OnboardingStatus
// Get the first timestamp the device was seen
| join kind=inner (
DeviceInfo
| where TimeGenerated > ago(30d)
| summarize FirstSeen = arg_min(TimeGenerated, DeviceId) by DeviceId
) on DeviceId
| project-away DeviceId1, DeviceId2
) on DeviceId, DeviceName
| project-away DeviceName1, DeviceId1
);
// Get incomming traffic on ADWS port and save unique remote IP addresses
DeviceNetworkEvents
| where TimeGenerated > ago(30d)
| where ActionType != "ListeningConnectionCreated"
| where InitiatingProcessFolderPath == @"c:\windows\adws\microsoft.activedirectory.webservices.exe"
| where LocalPort == "9389"
| summarize ConnectionTimes=make_list(TimeGenerated) by RemoteIP, DeviceName
// Get device information of remote IP addresses, results for IP we do not find information for are allowed
| join kind=leftouter device_info on $left.RemoteIP == $right.IPAddress
| project-away IPAddress
// Check if the remote IPs are onboarded devices or not
| where OnboardingStatus != "Onboarded"
// Make output better
| project DeviceName, ConnectionTimes, RemoteIP, RemoteDeviceName = DeviceName1, RemoteDeviceId = DeviceId, RemoteOnboardingStatus = OnboardingStatus, RemoteDeviceFirstSeen = FirstSeen
Stages and Predicates
Let binding: device_info
let device_info = (
DeviceNetworkInfo
| where Timestamp > ago(7d)
| mv-expand todynamic(IPAddresses)
| extend IPAddress = tostring(IPAddresses.IPAddress)
| distinct DeviceName, DeviceId, IPAddress
| join kind=inner (
DeviceInfo
| where Timestamp > ago(7d)
| distinct DeviceName, DeviceId, OnboardingStatus
| join kind=inner (
DeviceInfo
| where Timestamp > ago(30d)
| summarize FirstSeen = arg_min(Timestamp, DeviceId) by DeviceId
) on DeviceId
| project-away DeviceId1, DeviceId2
) on DeviceId, DeviceName
| project-away DeviceName1, DeviceId1
);
Stage 1: source
let device_info
Stage 2: source
DeviceNetworkEvents
Stage 3: where
where Timestamp > ago(2592000s)
Stage 4: where
where ActionType !~ "ListeningConnectionCreated"
Stage 5: where
where InitiatingProcessFolderPath =~ @"c:\windows\adws\microsoft.activedirectory.webservices.exe"
Stage 6: where
where LocalPort == 9389
Stage 7: summarize
summarize ConnectionTimes by RemoteIP, DeviceName
Stage 8: join
join kind=leftouter (device_info) on RemoteIP, IPAddress
Stage 9: project-away
project-away IPAddress
Stage 10: where
where OnboardingStatus !~ "Onboarded"
Stage 11: project
project ConnectionTimes, DeviceName, RemoteDeviceFirstSeen, RemoteDeviceId, RemoteDeviceName, RemoteIP, RemoteOnboardingStatus
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActionType | ne |
| field:"ActionType" kind:ne value:"ListeningConnectionCreated" |
InitiatingProcessFolderPath | eq |
| field:"Image" kind:eq value:"c:\windows\adws\microsoft.activedirectory.webservices.exe" |
LocalPort | eq |
| field:"SourcePort" kind:eq value:"9389" |
OnboardingStatus | ne |
| field:"OnboardingStatus" kind:ne value:"Onboarded" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ConnectionTimes | project |
DeviceName | project |
RemoteDeviceFirstSeen | project |
RemoteDeviceId | project |
RemoteDeviceName | project |
RemoteIP | project |
RemoteOnboardingStatus | project |