Detection rules › Kusto
Exchange OAB Virtual Directory Attribute Containing Potential Webshell
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
| Tactic | Techniques |
|---|---|
| Initial Access | T1190 Exploit Public-Facing Application |
Event coverage
| Provider | Event | Title |
|---|---|---|
| Security-Auditing | Event ID 5136 | A directory service object was modified. |
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.
| Field | Kind | Values |
|---|---|---|
AttributeLDAPDisplayName | in |
|
AttributeValue | match |
|
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 |
|---|---|
EventData | extend |
Key | extend |
Value | extend |
ObjectClass | extend |
AttributeLDAPDisplayName | extend |
AttributeValue | extend |
LastSeen | project-rename |
ObjectDN | extend |
timestamp | extend |
DomainIndex | extend |
HostName | extend |
HostNameDomain | extend |
AccountNTDomain | extend |
AccountName | extend |