Detection rules › Kusto
Semperis DSP RBAC Changes
'Alerts when there are RBAC changes in the DSP system.'
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence | T1098 Account Manipulation |
| Privilege Escalation | T1098 Account Manipulation, T1548 Abuse Elevation Control Mechanism |
Rule body kusto
id: "e5edf3f3-de53-45e6-b0d7-1ce1c048df4a"
name: Semperis DSP RBAC Changes
description: |
'Alerts when there are RBAC changes in the DSP system.'
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: SemperisDSP
dataTypes:
- dsp_parser
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
- Persistence
relevantTechniques:
- T1548
- T1098
query: |
SecurityEvent
| where EventSourceName == 'Semperis-Operation-Log' and EventID == 20012
| order by TimeGenerated desc
| extend p1Xml = parse_xml(EventData).DataItem.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, Computer, Level, EventLevelName, EventID, Type, _ResourceId)
| extend det = column_ifexists('details', '')
| parse det with "Occured at (UTC): " OccurredAt "Session ID: " SessionID "Trustee Name: " TrusteeName "Correlation ID: " CorrelationID "Source: " Source "WebSite Target: " WebSiteTarget "Product: " Product "Component: " Component "AD Information: " ADInformation "Object GUID: " ObjectGUID "Attribute: " Attribute "Distinguished Name: " DistinguishedName "Additional Information: "AdditionalInformation "Operation Detail: " OperationDetail "operationName: " operationName "trustee: " trustee "personas: " personas "Status: " status "Granted: " Granted "Result: " Result
| extend _AccessGranted = iif(operationName contains "CreateRbacIdentity", "Added", "Removed")
| extend _Identity = iif(operationName contains "CreateRbacIdentity", trustee, tostring(substring(trustee, 1, strlen(trustee))))
| extend _Identity = iif(operationName contains "CreateRbacIdentity", _Identity, replace_string(_Identity, "'", ""))
| extend add_personas = replace_string(replace_string(replace_string(personas, "{ Name = ", ""), " }", ""), ";", ",")
| extend remove_personas = replace_string(personas, ";", ",")
| extend grid_personas = iif(operationName contains "CreateRbacIdentity", add_personas, remove_personas)
| extend date_to_sort = format_datetime(TimeGenerated, "yyyy-mm-dd HH:mm:ss")
| order by date_to_sort desc
| extend NTDomain = tostring(split(TrusteeName, '\\', 0)[0]), LoginUser = tostring(split(TrusteeName, '\\', 1)[0])
| extend HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: LoginUser
- identifier: NTDomain
columnName: NTDomain
- entityType: Host
fieldMappings:
- identifier: HostName
columnName: HostName
- identifier: DnsDomain
columnName: DnsDomain
eventGroupingSettings:
aggregationKind: SingleAlert
alertDetailsOverride:
alertDisplayNameFormat: RBAC Change -- Alert from Semperis Directory Services Protector
alertDescriptionFormat: A RBAC change was detected in 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 == 20012
Stage 3: sort
| order by TimeGenerated desc
Stage 4: extend
| extend p1Xml = parse_xml(EventData).DataItem.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, Computer, Level, EventLevelName, EventID, Type, _ResourceId)
Stage 9: extend
| extend det = column_ifexists('details', '')
Stage 10: parse
| parse det with "Occured at (UTC): " OccurredAt "Session ID: " SessionID "Trustee Name: " TrusteeName "Correlation ID: " CorrelationID "Source: " Source "WebSite Target: " WebSiteTarget "Product: " Product "Component: " Component "AD Information: " ADInformation "Object GUID: " ObjectGUID "Attribute: " Attribute "Distinguished Name: " DistinguishedName "Additional Information: "AdditionalInformation "Operation Detail: " OperationDetail "operationName: " operationName "trustee: " trustee "personas: " personas "Status: " status "Granted: " Granted "Result: " Result
Stage 11: extend (7 consecutive steps)
| extend _AccessGranted = iif(operationName contains "CreateRbacIdentity", "Added", "Removed")
| extend _Identity = iif(operationName contains "CreateRbacIdentity", trustee, tostring(substring(trustee, 1, strlen(trustee))))
| extend _Identity = iif(operationName contains "CreateRbacIdentity", _Identity, replace_string(_Identity, "'", ""))
| extend add_personas = replace_string(replace_string(replace_string(personas, "{ Name = ", ""), " }", ""), ";", ",")
| extend remove_personas = replace_string(personas, ";", ",")
| extend grid_personas = iif(operationName contains "CreateRbacIdentity", add_personas, remove_personas)
| extend date_to_sort = format_datetime(TimeGenerated, "yyyy-mm-dd HH:mm:ss")
Stage 12: sort
| order by date_to_sort desc
Stage 13: extend
| extend NTDomain = tostring(split(TrusteeName, '\\', 0)[0]), LoginUser = tostring(split(TrusteeName, '\\', 1)[0])
Stage 14: extend
| extend HostName = tostring(split(Computer, '.', 0)[0]), DnsDomain = tostring(strcat_array(array_slice(split(Computer, '.'), 1, -1), '.'))
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 |
|---|---|---|
EventID | eq |
|
EventSourceName | eq |
|
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
p1Xml | extend |
Name | extend |
Value | extend |
det | extend |
_AccessGranted | extend |
_Identity | extend |
add_personas | extend |
remove_personas | extend |
grid_personas | extend |
date_to_sort | extend |
LoginUser | extend |
NTDomain | extend |
DnsDomain | extend |
HostName | extend |