Detection rules › Kusto
Service Principal Name (SPN) Assigned to User Account
This query identifies whether an Active Directory user object was assigned a service principal name which could indicate that an adversary is preparing for performing Kerberoasting. This query checks for event id 5136, that the Object Class field is "user" and the LDAP Display Name is "servicePrincipalName". Ref: https://thevivi.net/assets/docs/2019/theVIVI-AD-Security-Workshop_AfricaHackon2019.pdf
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Privilege Escalation | T1134 Access Token Manipulation |
Event coverage
| Provider | Event | Title |
|---|---|---|
| Security-Auditing | Event ID 5136 | A directory service object was modified. |
Rule body kusto
id: 875d0eb1-883a-4191-bd0e-dbfdeb95a464
name: Service Principal Name (SPN) Assigned to User Account
description: |
'This query identifies whether an Active Directory user object was assigned a service principal name which could indicate that an adversary is preparing for performing Kerberoasting.
This query checks for event id 5136, that the Object Class field is "user" and the LDAP Display Name is "servicePrincipalName".
Ref: https://thevivi.net/assets/docs/2019/theVIVI-AD-Security-Workshop_AfricaHackon2019.pdf'
severity: Medium
requiredDataConnectors:
- connectorId: SecurityEvents
dataTypes:
- SecurityEvent
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- PrivilegeEscalation
relevantTechniques:
- T1134
query: |
SecurityEvent
| where EventID == 5136
| parse EventData with * 'AttributeLDAPDisplayName">' AttributeLDAPDisplayName "<" *
| parse EventData with * 'ObjectClass">' ObjectClass "<" *
| where AttributeLDAPDisplayName == "servicePrincipalName" and ObjectClass == "user"
| parse EventData with * 'ObjectDN">' ObjectDN "<" *
| parse EventData with * 'AttributeValue">' AttributeValue "<" *
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by Computer, SubjectAccount, ObjectDN, AttributeValue, SubjectUserName, SubjectDomainName, SubjectUserSid
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| project-away DomainIndex
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: SubjectAccount
- identifier: Name
columnName: SubjectUserName
- identifier: NTDomain
columnName: SubjectDomainName
- entityType: Account
fieldMappings:
- identifier: Sid
columnName: SubjectUserSid
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: Computer
- identifier: HostName
columnName: HostName
- identifier: NTDomain
columnName: HostNameDomain
version: 1.0.4
kind: Scheduled
metadata:
source:
kind: Community
author:
name: Vasileios Paschalidis
support:
tier: Community
categories:
domains: [ "Security - Others", "Identity" ]
Stages and Predicates
Stage 1: source
SecurityEvent
Stage 2: where
| where EventID == 5136
Stage 3: parse
| parse EventData with * 'AttributeLDAPDisplayName">' AttributeLDAPDisplayName "<" *
Stage 4: parse
| parse EventData with * 'ObjectClass">' ObjectClass "<" *
Stage 5: where
| where AttributeLDAPDisplayName == "servicePrincipalName" and ObjectClass == "user"
Stage 6: parse
| parse EventData with * 'ObjectDN">' ObjectDN "<" *
Stage 7: parse
| parse EventData with * 'AttributeValue">' AttributeValue "<" *
Stage 8: summarize
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated) by Computer, SubjectAccount, ObjectDN, AttributeValue, SubjectUserName, SubjectDomainName, SubjectUserSid
Stage 9: extend
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
Stage 10: extend
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
HostNameDomain =DomainIndex != -1substring(Computer, (DomainIndex + 1))ComputerStage 11: project-away
| project-away DomainIndex
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 |
|---|---|---|
AttributeLDAPDisplayName | eq |
|
EventID | eq |
|
ObjectClass | 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 |
|---|---|
AttributeValue | summarize |
Computer | summarize |
EndTime | summarize |
ObjectDN | summarize |
StartTime | summarize |
SubjectAccount | summarize |
SubjectDomainName | summarize |
SubjectUserName | summarize |
SubjectUserSid | summarize |
HostName | extend |
HostNameDomain | extend |