Detection rules › Splunk

Windows Exchange Autodiscover SSRF Abuse

Status
production
Severity
medium
Group by
Web.src, Web.status, c-uri-query, c-uri-stem, c-useragent, cs-host, cs-method
Author
Michael Haag, Nathaniel Stearns, Splunk
Source
github.com/splunk/security_content

This analytic identifies potential exploitation attempts of ProxyShell (CVE-2021-34473, CVE-2021-34523, CVE-2021-31207) and ProxyNotShell (CVE-2022-41040, CVE-2022-41082) vulnerabilities in Microsoft Exchange Server. The detection focuses on identifying the SSRF attack patterns used in these exploit chains. The analytic monitors for suspicious POST requests to /autodiscover/autodiscover.json endpoints that may indicate attempts to enumerate LegacyDN attributes as part of initial reconnaissance. It also detects requests containing X-Rps-CAT parameters that could indicate attempts to impersonate Exchange users and access the PowerShell backend. Additionally, it looks for MAPI requests that may be used to obtain user SIDs, along with suspicious user agents (particularly Python-based) commonly used in automated exploit attempts. If successful, these attacks can lead to remote code execution as SYSTEM, allowing attackers to deploy webshells, access mailboxes, or gain persistent access to the Exchange server and potentially the broader network environment.

MITRE ATT&CK coverage

Rule body splunk

name: Windows Exchange Autodiscover SSRF Abuse
id: d436f9e7-0ee7-4a47-864b-6dea2c4e2752
version: 10
creation_date: '2022-10-03'
modification_date: '2026-05-13'
author: Michael Haag, Nathaniel Stearns, Splunk
status: production
type: TTP
description: This analytic identifies potential exploitation attempts of ProxyShell (CVE-2021-34473, CVE-2021-34523, CVE-2021-31207) and ProxyNotShell (CVE-2022-41040, CVE-2022-41082) vulnerabilities in Microsoft Exchange Server. The detection focuses on identifying the SSRF attack patterns used in these exploit chains. The analytic monitors for suspicious POST requests to /autodiscover/autodiscover.json endpoints that may indicate attempts to enumerate LegacyDN attributes as part of initial reconnaissance. It also detects requests containing X-Rps-CAT parameters that could indicate attempts to impersonate Exchange users and access the PowerShell backend. Additionally, it looks for MAPI requests that may be used to obtain user SIDs, along with suspicious user agents (particularly Python-based) commonly used in automated exploit attempts. If successful, these attacks can lead to remote code execution as SYSTEM, allowing attackers to deploy webshells, access mailboxes, or gain persistent access to the Exchange server and potentially the broader network environment.
data_source:
    - Windows IIS
search: |-
    | tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime FROM datamodel=Web
      WHERE (
            Web.status=200
        )
        AND Web.http_method=POST
      BY Web.src Web.status Web.uri_path
         Web.dest Web.http_method Web.uri_query
         Web.http_user_agent
    | `drop_dm_object_name("Web")`
    | eval is_autodiscover=if(like(lower(uri_path),"%autodiscover/autodiscover.json%"),1,0)
    | eval has_rps_cat=if(like(lower(uri_query),"%x-rps-cat=%"),1,0)
    | eval exchange_backend=if(like(lower(uri_query),"%/powershell/?%"),1,0)
    | eval mapi=if(like(uri_query,"%/mapi/%"),1,0)
    | eval suspicious_agent=if(match(lower(http_user_agent), "python
    | urllib"),1,0)
    | addtotals fieldname=Score is_autodiscover, has_rps_cat, exchange_backend, mapi, suspicious_agent
    | where Score >= 3
    | fields Score, src, dest, status, uri_query, uri_path, http_method, http_user_agent
    | `windows_exchange_autodiscover_ssrf_abuse_filter`
how_to_implement: To successfully implement this search you need to be ingesting information on Web traffic, Exchange OR IIS logs, mapped to `Web` datamodel in the `Web` node. In addition, confirm the latest CIM App 4.20 or higher is installed.
known_false_positives: False positives are limited.
references:
    - https://www.gteltsc.vn/blog/warning-new-attack-campaign-utilized-a-new-0day-rce-vulnerability-on-microsoft-exchange-server-12715.html
    - https://msrc-blog.microsoft.com/2022/09/29/customer-guidance-for-reported-zero-day-vulnerabilities-in-microsoft-exchange-server/
    - https://twitter.com/GossiTheDog/status/1575762721353916417?s=20&t=67gq9xCWuyPm1VEm8ydfyA
    - https://twitter.com/cglyer/status/1575793769814728705?s=20&t=67gq9xCWuyPm1VEm8ydfyA
    - https://www.gteltsc.vn/blog/warning-new-attack-campaign-utilized-a-new-0day-rce-vulnerability-on-microsoft-exchange-server-12715.html
    - https://research.splunk.com/stories/proxyshell/
    - https://splunk.github.io/splunk-add-on-for-microsoft-iis/
    - https://highon.coffee/blog/ssrf-cheat-sheet/
    - https://owasp.org/Top10/A10_2021-Server-Side_Request_Forgery_%28SSRF%29/
    - https://m365internals.com/2022/10/18/hunting-and-responding-to-proxyshell-attacks/
drilldown_searches:
    - name: View the detection results for - "$dest$"
      search: '%original_detection_search% | search  dest = "$dest$"'
      earliest_offset: $info_min_time$
      latest_offset: $info_max_time$
    - name: View risk events for the last 7 days for - "$dest$"
      search: '| from datamodel Risk.All_Risk | search normalized_risk_object IN ("$dest$") | stats count min(_time) as firstTime max(_time) as lastTime values(search_name) as "Search Name" values(risk_message) as "Risk Message" values(analyticstories) as "Analytic Stories" values(annotations._all) as "Annotations" values(annotations.mitre_attack.mitre_tactic) as "ATT&CK Tactics" by normalized_risk_object | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)`'
      earliest_offset: 7d
      latest_offset: "0"
finding:
    title: Activity related to ProxyShell or ProxyNotShell has been identified on $dest$. Review events and take action accordingly.
    entity:
        field: dest
        type: system
        score: 50
analytic_story:
    - ProxyShell
    - BlackByte Ransomware
    - ProxyNotShell
    - Seashell Blizzard
asset_type: Web Server
cve:
    - CVE-2021-34523
    - CVE-2021-34473
    - CVE-2021-31207
    - CVE-2022-41040
    - CVE-2022-41082
mitre_attack_id:
    - T1190
    - T1133
product:
    - Splunk Enterprise
    - Splunk Enterprise Security
    - Splunk Cloud
category: web
security_domain: network
tests:
    - name: True Positive Test
      attack_data:
        - data: https://media.githubusercontent.com/media/splunk/attack_data/master/datasets/attack_techniques/T1190/proxyshell/proxyshell.log
          source: ms:iis:splunk
          sourcetype: ms:iis:splunk
      test_type: unit

Stages and Predicates

Stage 1: tstats

| tstats `security_content_summariesonly` count min(_time) as firstTime max(_time) as lastTime FROM datamodel=Web
  WHERE (
        Web.status=200
    )
    AND Web.http_method=POST
  BY Web.src Web.status Web.uri_path
     Web.dest Web.http_method Web.uri_query
     Web.http_user_agent

Stage 2: search

| `drop_dm_object_name("Web")`

Stage 3: eval

| eval is_autodiscover=if(like(lower(uri_path),"%autodiscover/autodiscover.json%"),1,0)
is_autodiscover =
iflike(lower(uri_path), "%autodiscover/autodiscover.json%")1
else0

Stage 4: eval

| eval has_rps_cat=if(like(lower(uri_query),"%x-rps-cat=%"),1,0)
has_rps_cat =
iflike(lower(uri_query), "%x-rps-cat=%")1
else0

Stage 5: eval

| eval exchange_backend=if(like(lower(uri_query),"%/powershell/?%"),1,0)
exchange_backend =
iflike(lower(uri_query), "%/powershell/?%")1
else0

Stage 6: eval

| eval mapi=if(like(uri_query,"%/mapi/%"),1,0)
mapi =
iflike(uri_query, "%/mapi/%")1
else0

Stage 7: eval

| eval suspicious_agent=if(match(lower(http_user_agent), "python
| urllib"),1,0)
suspicious_agent =
ifmatch(lower(http_user_agent), "python | urllib")1
else0

Stage 8: addtotals

| addtotals fieldname=Score is_autodiscover, has_rps_cat, exchange_backend, mapi, suspicious_agent

Stage 9: where

| where Score >= 3

Stage 10: fields

| fields Score, src, dest, status, uri_query, uri_path, http_method, http_user_agent

Stage 11: search

| `windows_exchange_autodiscover_ssrf_abuse_filter`

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
Scorege
  • 3
Web.http_methodeq
  • POST
Web.statuseq
  • 200