Suspect Mailbox Export on IIS/OWA


Description

'The hunting query looks for suspicious files accessed on a IIS server that might indicate exfiltration hosting. This technique has been observed when exporting mailbox files from OWA servers.'

Query · kql

let excludeIps = dynamic(["127.0.0.1", "::1"]);
let scriptingExt = dynamic(["aspx", "ashx", "asp"]);
W3CIISLog
| where csUriStem contains "/owa/"
//The actor pulls a file back but won't send it any URI params
| where isempty(csUriQuery)
| extend file_ext = tostring(split(csUriStem, ".")[-1])
//Giving your file a known scripting extension will throw an error
//rather than just serving the file as it will try to interpret the script
| where file_ext !in~ (scriptingExt)
//The actor was seen using image files, but we go wider in case they change this behaviour
//| where file_ext in~ ("jpg", "jpeg", "png", "bmp")
| extend file_name = tostring(split(csUriStem, "/")[-1])
| where file_name != ""
| where cIP !in~ (excludeIps)
//Exclude local addresses, using the ipv4_is_private operator
| where ipv4_is_private(cIP) == false and  cIP !startswith "fe80" and cIP !startswith "::" and cIP !startswith "127."
| project file_ext, csUriStem, file_name, Computer, cIP, sIP, TenantId, TimeGenerated
| summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), dcount(cIP), AccessingIPs=make_set(cIP), AccessTimes=make_set(TimeGenerated), Access=count() by TenantId, file_name, Computer, csUriStem
//Collection of the exfiltration will occur only once, lets check for 2 accesses in case they mess up
//Tailor this for hunting
| where Access <= 2 and dcount_cIP == 1
| extend timestamp = StartTime, HostCustomEntity = Computer
Raw source Suspect Mailbox Export on IIS/OWA · KQL
Esc
Published by Azure/Azure-Sentinel ↗, licensed under MIT ↗. Reproduced here unmodified.
id: a523786c-8382-4029-80e9-f1a7ecd067c1
name: Suspect Mailbox Export on IIS/OWA
description: |
  'The hunting query looks for suspicious files accessed on a IIS server that might indicate exfiltration hosting. This technique has been observed when exporting mailbox files from OWA servers.'
description_detailed: |
  'The hunting query looks for suspicious files accessed on a IIS server that might indicate exfiltration hosting.
  This technique has been observed when exporting mailbox files from OWA servers.
  Reference: https://www.volexity.com/blog/2020/12/14/dark-halo-leverages-solarwinds-compromise-to-breach-organizations/'
severity: Low
requiredDataConnectors:
  - connectorId: AzureMonitor(IIS)
    dataTypes:
      - W3CIISLog
tactics:
  - Exfiltration
relevantTechniques:
  - T1567
tags:
  - Solorigate
  - NOBELIUM
query: |

  let excludeIps = dynamic(["127.0.0.1", "::1"]);
  let scriptingExt = dynamic(["aspx", "ashx", "asp"]);
  W3CIISLog
  | where csUriStem contains "/owa/"
  //The actor pulls a file back but won't send it any URI params
  | where isempty(csUriQuery)
  | extend file_ext = tostring(split(csUriStem, ".")[-1])
  //Giving your file a known scripting extension will throw an error
  //rather than just serving the file as it will try to interpret the script
  | where file_ext !in~ (scriptingExt)
  //The actor was seen using image files, but we go wider in case they change this behaviour
  //| where file_ext in~ ("jpg", "jpeg", "png", "bmp")
  | extend file_name = tostring(split(csUriStem, "/")[-1])
  | where file_name != ""
  | where cIP !in~ (excludeIps)
  //Exclude local addresses, using the ipv4_is_private operator
  | where ipv4_is_private(cIP) == false and  cIP !startswith "fe80" and cIP !startswith "::" and cIP !startswith "127."
  | project file_ext, csUriStem, file_name, Computer, cIP, sIP, TenantId, TimeGenerated
  | summarize StartTime = min(TimeGenerated), EndTime = max(TimeGenerated), dcount(cIP), AccessingIPs=make_set(cIP), AccessTimes=make_set(TimeGenerated), Access=count() by TenantId, file_name, Computer, csUriStem
  //Collection of the exfiltration will occur only once, lets check for 2 accesses in case they mess up
  //Tailor this for hunting
  | where Access <= 2 and dcount_cIP == 1
  | extend timestamp = StartTime, HostCustomEntity = Computer
entityMappings:
  - entityType: Host
    fieldMappings:
      - identifier: FullName
        columnName: Computer
version: 1.0.1
metadata:
    source:
        kind: Community
    author:
        name: Pete Bryan
    support:
        tier: Community
    categories:
        domains: [ "Security - Threat Protection" ]

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.