Detection rules › Kusto

AD FS Abnormal EKU object identifier attribute

Severity
high
Time window
1d
Group by
OID
Author
Microsoft Security Research
Source
github.com/Azure/Azure-Sentinel

This detection uses Security events from the "AD FS Auditing" provider to detect suspicious object identifiers (OIDs) as part EventID 501 and specifically part of the Enhanced Key Usage attributes. This query checks to see if you have any new OIDs in the last hour that have not been seen in the previous day. New OIDs should be validated and OIDs that are very long, as indicated by the OID_Length field, could also be an indicator of malicious activity. In order to use this query you need to enable AD FS auditing on the AD FS Server. References: https://www.microsoft.com/security/blog/2022/08/24/magicweb-nobeliums-post-compromise-trick-to-authenticate-as-anyone/ https://docs.microsoft.com/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-logging

MITRE ATT&CK coverage

TacticTechniques
Credential Access

Telemetry coverage

ProviderRecord / event type
AD-FS-AuditingEvent ID 501

Rule body

id: cfc1ae62-db63-4a3e-b88b-dc04030c2257
name: AD FS Abnormal EKU object identifier attribute
description: |
  'This detection uses Security events from the "AD FS Auditing" provider to detect suspicious object identifiers (OIDs) as part EventID 501 and specifically part of the Enhanced Key Usage attributes.
  This query checks to see if you have any new OIDs in the last hour that have not been seen in the previous day. New OIDs should be validated and OIDs that are very long, as indicated
  by the OID_Length field, could also be an indicator of malicious activity.
  In order to use this query you need to enable AD FS auditing on the AD FS Server.
  References:
  https://www.microsoft.com/security/blog/2022/08/24/magicweb-nobeliums-post-compromise-trick-to-authenticate-as-anyone/
  https://docs.microsoft.com/windows-server/identity/ad-fs/troubleshooting/ad-fs-tshoot-logging
  '
severity: High
requiredDataConnectors:
  - connectorId: SecurityEvents
    dataTypes:
      - SecurityEvent
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - CredentialAccess
relevantTechniques:
  - T1552
tags:
  - Nobelium
  - MagicWeb
query: |
  // change the starttime value for a longer period of known OIDs
  let starttime = 1d;
  // change the lookback value for a longer period of lookback for suspicious/abnormal
  let lookback = 1h;
  let OIDList = SecurityEvent
  | where TimeGenerated >= ago(starttime)
  | where EventSourceName == 'AD FS Auditing'
  | where EventID == 501
  | where EventData has '/eku'
  | extend OIDs = extract_all(@"<Data>([\d+\.]+)</Data>", EventData)
  | mv-expand OIDs
  | extend OID = tostring(OIDs)
  | extend OID_Length = strlen(OID)
  | project TimeGenerated, Computer, EventSourceName, EventID, OID, OID_Length, EventData
  ;
  OIDList
  | where TimeGenerated >= ago(lookback)
  | join kind=leftanti (
  OIDList
  | where TimeGenerated between (ago(starttime) .. ago(lookback))
  | summarize by OID
  ) on OID
  | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: Computer
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: HostNameDomain
version: 1.0.4
kind: Scheduled
metadata:
    source:
        kind: Community
    author:
        name: Microsoft Security Research
    support:
        tier: Community
    categories:
        domains: [ "Security - Others", "Identity" ]

Stages and Predicates

Parameters

let starttime = 1d;
let lookback = 1h;

let OIDList is inlined into the numbered stages below.

Stages 1 to 11 define let OIDList (the rule's main pipeline source); stages 12 to 16 run on it.

Stage 1: source

let OIDList

Stage 2: source

SecurityEvent

Stage 3: where

| where TimeGenerated >= ago(starttime)

Stage 4: where

| where EventSourceName == 'AD FS Auditing'

Stage 5: where

| where EventID == 501

Stage 6: where

| where EventData has '/eku'

Stage 7: extend

| extend OIDs = extract_all(@"<Data>([\d+\.]+)</Data>", EventData)

Stage 8: mv-expand

| mv-expand OIDs

Stage 9: extend

| extend OID = tostring(OIDs)

Stage 10: extend

| extend OID_Length = strlen(OID)

Stage 11: project

| project TimeGenerated, Computer, EventSourceName, EventID, OID, OID_Length, EventData

Stage 12: where

OIDList
| where TimeGenerated >= ago(lookback)

Stage 13: join (negated)

| join kind=leftanti (
OIDList
| where TimeGenerated between (ago(starttime) .. ago(lookback))
| summarize by OID
) on OID

Stage 14: extend

| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))

Stage 15: extend

| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
HostNameDomain =
ifDomainIndex != -1substring(Computer, (DomainIndex + 1))
elseComputer

Stage 16: summarize aggregation inside the join branch

summarize by OID

Exclusions

The rule actively suppresses these predicates.

Indicators

These rows show field, operator, and value matches.

Output fields

These fields are emitted when the rule matches.

FieldSource
OIDsummarize