Detection rules › Kusto
Semperis DSP Failed Logons
Alerts when there are failed logons in the DSP system.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Credential Access |
Telemetry coverage
| Provider | Record / event type |
|---|---|
| Semperis-Operation-Log | Event ID 20002: DSP failed logon |
Rule body
id: "0e105444-fe13-4ce6-9239-21880076a3f9"
name: Semperis DSP Failed Logons
description: |
'Alerts when there are failed logons in the DSP system.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SemperisDSP
dataTypes:
- dsp_parser
queryFrequency: 30m
queryPeriod: 30m
tactics:
- InitialAccess
- CredentialAccess
relevantTechniques:
- T1078
- T1110
triggerOperator: gt
triggerThreshold: 0
query: |
SecurityEvent
| where EventSourceName == 'Semperis-Operation-Log' and EventID == 20002
| sort by TimeGenerated desc
| extend p1Xml = parse_xml(EventData).EventData.Data
| mv-expand bagexpansion=array p1Xml
| evaluate bag_unpack(p1Xml)
| extend Name=column_ifexists('@Name', ''), Value=column_ifexists('#text', '')
| evaluate pivot(Name, any(Value), TimeGenerated, EventSourceName, Channel, Computer, Level, EventLevelName, EventID, Task, Type, _ResourceId)
| extend det = column_ifexists('details', '')
| parse det with * "Trustee Name: " TrusteeName " Correlation ID: " * " Source: " HostIP "WebSite Target" *
| extend host = tostring(HostIP)
| extend HostIP = trim_end(":", HostIP)
| project TimeGenerated, TrusteeName, HostIP, _ResourceId
| extend NTDomain = tostring(split(TrusteeName, '\\', 0)[0]), Name = tostring(split(TrusteeName, '\\', 1)[0])
entityMappings:
- entityType: IP
fieldMappings:
- identifier: Address
columnName: HostIP
- entityType: Account
fieldMappings:
- identifier: Name
columnName: Name
- identifier: NTDomain
columnName: NTDomain
eventGroupingSettings:
aggregationKind: SingleAlert
alertDetailsOverride:
alertDisplayNameFormat: Failed Logon -- Alert from Semperis Directory Services Protector
alertDescriptionFormat: A failed logon was detected to the DSP system.
version: 2.0.7
kind: Scheduled
Stages and Predicates
Stage 1: source
SecurityEvent
Stage 2: where
| where EventSourceName == 'Semperis-Operation-Log' and EventID == 20002
Stage 3: sort
| sort by TimeGenerated desc
Stage 4: extend
| extend p1Xml = parse_xml(EventData).EventData.Data
Stage 5: mv-expand
| mv-expand bagexpansion=array p1Xml
Stage 6: evaluate
| evaluate bag_unpack(p1Xml)
Stage 7: extend
| extend Name=column_ifexists('@Name', ''), Value=column_ifexists('#text', '')
Stage 8: evaluate
| evaluate pivot(Name, any(Value), TimeGenerated, EventSourceName, Channel, Computer, Level, EventLevelName, EventID, Task, Type, _ResourceId)
Stage 9: extend
| extend det = column_ifexists('details', '')
Stage 10: parse
| parse det with * "Trustee Name: " TrusteeName " Correlation ID: " * " Source: " HostIP "WebSite Target" *
Stage 11: extend
| extend host = tostring(HostIP)
Stage 12: extend
| extend HostIP = trim_end(":", HostIP)
Stage 13: project
| project TimeGenerated, TrusteeName, HostIP, _ResourceId
Stage 14: extend
| extend NTDomain = tostring(split(TrusteeName, '\\', 0)[0]), Name = tostring(split(TrusteeName, '\\', 1)[0])
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
EventID | eq |
| field:"EventID" kind:eq value:"20002" |
EventSourceName | eq |
| field:"Category" kind:eq value:"Semperis-Operation-Log" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
HostIP | project |
TimeGenerated | project |
TrusteeName | project |
_ResourceId | project |
NTDomain | extend |
Name | extend |