Microsoft Sentinel Analytic Rules
cloudbrothers.infoAzure Sentinel RepoToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeToggle Dark/Light/Auto modeBack to homepage

Exchange SSRF Autodiscover ProxyShell - Detection

Back
Id968358d6-6af8-49bb-aaa4-187b3067fb95
RulenameExchange SSRF Autodiscover ProxyShell - Detection
DescriptionThis query looks for suspicious request patterns to Exchange servers that fit patterns recently blogged about by PeterJson. This exploitation chain utilises an SSRF vulnerability in Exchange which eventually allows the attacker to execute arbitrary Powershell on the server.

In the example powershell can be used to write an email to disk with an encoded attachment containing a shell.

Reference: https://peterjson.medium.com/reproducing-the-proxyshell-pwn2own-exploit-49743a4ea9a1
SeverityHigh
TacticsInitialAccess
TechniquesT1190
Required data connectorsAzureMonitor(IIS)
KindScheduled
Query frequency12h
Query period12h
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Detections/W3CIISLog/ProxyShellPwn2Own.yaml
Version1.0.3
Arm template968358d6-6af8-49bb-aaa4-187b3067fb95.json
Deploy To Azure
let successCodes = dynamic([200, 302, 401]);
W3CIISLog
| where scStatus has_any (successCodes)
| where ipv4_is_private(cIP) == False
| where csUriStem hasprefix "/autodiscover/autodiscover.json"
| project TimeGenerated, cIP, sIP, sSiteName, csUriStem, csUriQuery, Computer, csUserName, _ResourceId, FileUri
| where (csUriQuery !has "Protocol" and isnotempty(csUriQuery))
or (csUriQuery has_any("/mapi/", "powershell"))
or (csUriQuery contains "@" and csUriQuery matches regex @"\.[a-zA-Z]{2,4}?(?:[a-zA-Z]{2,4}\/)")
or (csUriQuery contains ":" and csUriQuery matches regex @"\:[0-9]{2,4}\/")
| extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
| extend AccountName = tostring(split(csUserName, "@")[0]), AccountUPNSuffix = tostring(split(csUserName, "@")[1])
version: 1.0.3
metadata:
  categories:
    domains:
    - Security - Others
  source:
    kind: Community
  support:
    tier: Community
  author:
    name: Thomas McElroy
relevantTechniques:
- T1190
description: |
  'This query looks for suspicious request patterns to Exchange servers that fit patterns recently blogged about by PeterJson. This exploitation chain utilises an SSRF vulnerability in Exchange which eventually allows the attacker to execute arbitrary Powershell on the server.
  In the example powershell can be used to write an email to disk with an encoded attachment containing a shell.
  Reference: https://peterjson.medium.com/reproducing-the-proxyshell-pwn2own-exploit-49743a4ea9a1'  
requiredDataConnectors:
- connectorId: AzureMonitor(IIS)
  dataTypes:
  - W3CIISLog
entityMappings:
- fieldMappings:
  - identifier: FullName
    columnName: csUserName
  - identifier: Name
    columnName: AccountName
  - identifier: UPNSuffix
    columnName: AccountUPNSuffix
  entityType: Account
- fieldMappings:
  - identifier: FullName
    columnName: Computer
  entityType: Host
- fieldMappings:
  - identifier: Address
    columnName: cIP
  entityType: IP
- fieldMappings:
  - identifier: ResourceId
    columnName: _ResourceId
  entityType: AzureResource
triggerThreshold: 0
id: 968358d6-6af8-49bb-aaa4-187b3067fb95
tactics:
- InitialAccess
queryPeriod: 12h
query: |
  let successCodes = dynamic([200, 302, 401]);
  W3CIISLog
  | where scStatus has_any (successCodes)
  | where ipv4_is_private(cIP) == False
  | where csUriStem hasprefix "/autodiscover/autodiscover.json"
  | project TimeGenerated, cIP, sIP, sSiteName, csUriStem, csUriQuery, Computer, csUserName, _ResourceId, FileUri
  | where (csUriQuery !has "Protocol" and isnotempty(csUriQuery))
  or (csUriQuery has_any("/mapi/", "powershell"))
  or (csUriQuery contains "@" and csUriQuery matches regex @"\.[a-zA-Z]{2,4}?(?:[a-zA-Z]{2,4}\/)")
  or (csUriQuery contains ":" and csUriQuery matches regex @"\:[0-9]{2,4}\/")
  | extend HostName = tostring(split(Computer, ".")[0]), DomainIndex = toint(indexof(Computer, '.'))
  | extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)
  | extend AccountName = tostring(split(csUserName, "@")[0]), AccountUPNSuffix = tostring(split(csUserName, "@")[1])  
severity: High
name: Exchange SSRF Autodiscover ProxyShell - Detection
kind: Scheduled
queryFrequency: 12h
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Detections/W3CIISLog/ProxyShellPwn2Own.yaml
triggerOperator: gt
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/968358d6-6af8-49bb-aaa4-187b3067fb95')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/968358d6-6af8-49bb-aaa4-187b3067fb95')]",
      "properties": {
        "alertRuleTemplateName": "968358d6-6af8-49bb-aaa4-187b3067fb95",
        "customDetails": null,
        "description": "'This query looks for suspicious request patterns to Exchange servers that fit patterns recently blogged about by PeterJson. This exploitation chain utilises an SSRF vulnerability in Exchange which eventually allows the attacker to execute arbitrary Powershell on the server.\nIn the example powershell can be used to write an email to disk with an encoded attachment containing a shell.\nReference: https://peterjson.medium.com/reproducing-the-proxyshell-pwn2own-exploit-49743a4ea9a1'\n",
        "displayName": "Exchange SSRF Autodiscover ProxyShell - Detection",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "csUserName",
                "identifier": "FullName"
              },
              {
                "columnName": "AccountName",
                "identifier": "Name"
              },
              {
                "columnName": "AccountUPNSuffix",
                "identifier": "UPNSuffix"
              }
            ]
          },
          {
            "entityType": "Host",
            "fieldMappings": [
              {
                "columnName": "Computer",
                "identifier": "FullName"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "cIP",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "AzureResource",
            "fieldMappings": [
              {
                "columnName": "_ResourceId",
                "identifier": "ResourceId"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Detections/W3CIISLog/ProxyShellPwn2Own.yaml",
        "query": "let successCodes = dynamic([200, 302, 401]);\nW3CIISLog\n| where scStatus has_any (successCodes)\n| where ipv4_is_private(cIP) == False\n| where csUriStem hasprefix \"/autodiscover/autodiscover.json\"\n| project TimeGenerated, cIP, sIP, sSiteName, csUriStem, csUriQuery, Computer, csUserName, _ResourceId, FileUri\n| where (csUriQuery !has \"Protocol\" and isnotempty(csUriQuery))\nor (csUriQuery has_any(\"/mapi/\", \"powershell\"))\nor (csUriQuery contains \"@\" and csUriQuery matches regex @\"\\.[a-zA-Z]{2,4}?(?:[a-zA-Z]{2,4}\\/)\")\nor (csUriQuery contains \":\" and csUriQuery matches regex @\"\\:[0-9]{2,4}\\/\")\n| extend HostName = tostring(split(Computer, \".\")[0]), DomainIndex = toint(indexof(Computer, '.'))\n| extend HostNameDomain = iff(DomainIndex != -1, substring(Computer, DomainIndex + 1), Computer)\n| extend AccountName = tostring(split(csUserName, \"@\")[0]), AccountUPNSuffix = tostring(split(csUserName, \"@\")[1])\n",
        "queryFrequency": "PT12H",
        "queryPeriod": "PT12H",
        "severity": "High",
        "subTechniques": [],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "InitialAccess"
        ],
        "techniques": [
          "T1190"
        ],
        "templateVersion": "1.0.3",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}