Detection rules › Kusto

Exchange OAB Virtual Directory Attribute Containing Potential Webshell

Status
available
Severity
high
Time window
1h
Source
github.com/Azure/Azure-Sentinel

This query uses Windows Event ID 5136 in order to detect potential webshell deployment by exploitation of CVE-2021-27065. This query looks for changes to the InternalHostName or ExternalHostName properties of Exchange OAB Virtual Directory objects in AD Directory Services where the new objects contain potential webshell objects.

MITRE ATT&CK coverage

TacticTechniques
Initial AccessT1190 Exploit Public-Facing Application

Event coverage

Rule body kusto

id: faf1a6ff-53b5-4f92-8c55-4b20e9957594
name: Exchange OAB Virtual Directory Attribute Containing Potential Webshell
description: |
  'This query uses Windows Event ID 5136 in order to detect potential webshell deployment by exploitation of CVE-2021-27065.
  This query looks for changes to the InternalHostName or ExternalHostName properties of Exchange OAB Virtual Directory objects in AD Directory Services where the new objects contain potential webshell objects.'
severity: High
requiredDataConnectors:
  - connectorId: SecurityEvents
    dataTypes:
      - SecurityEvent
  - connectorId: WindowsSecurityEvents
    dataTypes:
      - SecurityEvent
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
status: Available
tactics:
  - InitialAccess
relevantTechniques:
  - T1190
query: |
  SecurityEvent
  // Look for specific Directory Service Changes and parse data
  | where EventID == 5136
  | extend EventData = parse_xml(EventData).EventData.Data
  | mv-expand bagexpansion = array EventData
  | evaluate bag_unpack(EventData)
  | extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "")
  | evaluate pivot(Key, any(Value),TimeGenerated, EventID, Computer, Account, AccountType, EventSourceName, Activity, SubjectAccount)
  // Where changes relate to Exchange OAB
  | extend ObjectClass = column_ifexists("ObjectClass", "")
  | where ObjectClass =~ "msExchOABVirtualDirectory"
  // Look for InternalHostName or ExternalHostName properties being changed
  | extend AttributeLDAPDisplayName = column_ifexists("AttributeLDAPDisplayName", "")
  | where AttributeLDAPDisplayName in~ ("msExchExternalHostName", "msExchInternalHostName")
  // Look for suspected webshell activity
  | extend AttributeValue = column_ifexists("AttributeValue", "")
  | where AttributeValue has "script"
  | project-rename LastSeen = TimeGenerated
  | extend ObjectDN = column_ifexists("ObjectDN", "")
  | project-reorder LastSeen, Computer, Account, ObjectDN, AttributeLDAPDisplayName, AttributeValue
  | extend timestamp = LastSeen
  | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
  | extend AccountName = tostring(split(Account, @'\')[1]), AccountNTDomain = tostring(split(Account, @'\')[0])
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: Account
      - identifier: Name
        columnName: AccountName
      - identifier: NTDomain
        columnName: AccountNTDomain
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: Computer
      - identifier: HostName
        columnName: HostName
      - identifier: DnsDomain
        columnName: HostNameDomain
version: 1.0.4
kind: Scheduled

Stages and Predicates

Stage 1: source

SecurityEvent

Stage 2: where

| where EventID == 5136

Stage 3: extend

| extend EventData = parse_xml(EventData).EventData.Data

Stage 4: mv-expand

| mv-expand bagexpansion = array EventData

Stage 5: evaluate

| evaluate bag_unpack(EventData)

Stage 6: extend

| extend Key = tostring(column_ifexists('@Name', "")), Value = column_ifexists('#text', "")

Stage 7: evaluate

| evaluate pivot(Key, any(Value),TimeGenerated, EventID, Computer, Account, AccountType, EventSourceName, Activity, SubjectAccount)

Stage 8: extend

| extend ObjectClass = column_ifexists("ObjectClass", "")

Stage 9: where

| where ObjectClass =~ "msExchOABVirtualDirectory"

Stage 10: extend

| extend AttributeLDAPDisplayName = column_ifexists("AttributeLDAPDisplayName", "")

Stage 11: where

| where AttributeLDAPDisplayName in~ ("msExchExternalHostName", "msExchInternalHostName")

Stage 12: extend

| extend AttributeValue = column_ifexists("AttributeValue", "")

Stage 13: where

| where AttributeValue has "script"

Stage 14: project-rename

| project-rename LastSeen = TimeGenerated

Stage 15: extend

| extend ObjectDN = column_ifexists("ObjectDN", "")

Stage 16: project-reorder

| project-reorder LastSeen, Computer, Account, ObjectDN, AttributeLDAPDisplayName, AttributeValue

Stage 17: extend (4 consecutive steps)

| extend timestamp = LastSeen
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| extend AccountName = tostring(split(Account, @'\')[1]), AccountNTDomain = tostring(split(Account, @'\')[0])

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.

FieldKindValues
AttributeLDAPDisplayNamein
  • msExchExternalHostName
  • msExchInternalHostName
AttributeValuematch
  • script transforms: term
EventIDeq
  • 5136 transforms: cased corpus 30 (splunk 24, kusto 5, elastic 1)
ObjectClasseq
  • msExchOABVirtualDirectory

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.

FieldSource
EventDataextend
Keyextend
Valueextend
ObjectClassextend
AttributeLDAPDisplayNameextend
AttributeValueextend
LastSeenproject-rename
ObjectDNextend
timestampextend
DomainIndexextend
HostNameextend
HostNameDomainextend
AccountNTDomainextend
AccountNameextend