Microsoft’s 31 July 2026 disclosure on CaptiveCrunch gave defenders a rare window into a mature Russian state operation — custom tooling, a named C2 panel, two distinct malware families, and a campaign active since at least May. What it also gave defenders is a reasonably detailed indicator set and a set of behaviours that produce detectable signals across Windows event logs, Entra ID audit logs, and endpoint telemetry.

This playbook translates the technical disclosure into detection logic. It covers CornFlake persistence and keylogging behaviour, ChocoShell in-memory PowerShell execution, device code phishing flows against Entra ID, and fake browser update delivery. All rules are written for Sigma with KQL equivalents for Microsoft Sentinel.

The Attack Chain in Detection Terms

CaptiveCrunch runs through four distinct phases, each of which produces observable telemetry.

Phase 1 — Captive portal interception: Users connect to a compromised hotel or conference Wi-Fi network. Storm-2945 controls the captive portal infrastructure via DNS and HTTP manipulation. From an enterprise visibility standpoint, this phase is largely invisible — you only see it in terms of what comes next.

Phase 2 — Credential harvesting or malware delivery: Two paths. The portal redirects to a fake M365 login page or initiates a device code phishing flow (OAuth 2.0 device code grant). Alternatively, a fake browser update prompt using ClickFix-style HTML delivers CornFlake or ChocoShell.

Phase 3 — CornFlake installation: The Go-based RAT drops to %APPDATA%\svchost32\ and registers a Windows service named “Cloud Sync Service” for persistence. It begins keylogging, clipboard monitoring, screenshot capture, and credential harvesting.

Phase 4 — ChocoShell in-memory execution: The PowerShell-based infostealer executes entirely in memory, extracting browser session cookies, M365 SSO tokens, saved passwords, and Wi-Fi credentials. No files hit disk.

Detection 1: CornFlake Service Installation

CornFlake installs as a service named “Cloud Sync Service” running from %APPDATA%\svchost32\. Service installation events are Windows Event ID 7045 (System event log, source: Service Control Manager).

title: CaptiveCrunch CornFlake RAT Service Installation
id: a3b7f291-9e4c-4d2a-b8f1-2e5c7d8a9f10
status: experimental
description: Detects installation of CornFlake RAT disguised as "Cloud Sync Service" in AppData path
references:
  - https://www.microsoft.com/en-us/security/blog/2026/07/31/captivecrunch-midnight-blizzard-targets-travelers-worldwide
author: Detection Engineering
date: 2026/08/08
logsource:
  product: windows
  service: system
detection:
  selection:
    EventID: 7045
    ServiceName: 'Cloud Sync Service'
  selection_path:
    ImagePath|contains:
      - '\AppData\Roaming\svchost32\'
      - '\AppData\Local\svchost32\'
  condition: selection or selection_path
falsepositives:
  - Legitimate cloud sync services (verify ImagePath — legitimate services do not run from AppData\Roaming)
level: high
tags:
  - attack.persistence
  - attack.t1543.003

KQL (Microsoft Sentinel / Defender XDR):

DeviceEvents
| where ActionType == "ServiceInstalled"
| where AdditionalFields has "Cloud Sync Service"
    or AdditionalFields has @"\svchost32\"
| project Timestamp, DeviceName, AccountName, AdditionalFields
| order by Timestamp desc

Also check registry persistence paths written during installation:

DeviceRegistryEvents
| where RegistryKey has @"HKLM\SYSTEM\CurrentControlSet\Services"
| where RegistryValueData has "svchost32"
| project Timestamp, DeviceName, RegistryKey, RegistryValueData, InitiatingProcessFileName

Detection 2: ChocoShell In-Memory PowerShell Execution

ChocoShell runs entirely in memory. It does not write to disk. Detection depends on PowerShell Script Block Logging (Event ID 4104) being enabled, which logs the script content before execution regardless of obfuscation.

title: CaptiveCrunch ChocoShell In-Memory PowerShell Infostealer Indicators
id: c8d2e4f6-1a3b-4c5d-9e7f-8b1c2d3e4f56
status: experimental
description: Detects PowerShell script block content patterns consistent with ChocoShell credential harvesting from browser stores and M365 token extraction
references:
  - https://www.microsoft.com/en-us/security/blog/2026/07/31/captivecrunch-midnight-blizzard-targets-travelers-worldwide
author: Detection Engineering
date: 2026/08/08
logsource:
  product: windows
  service: powershell
  definition: 'Script block logging must be enabled (HKLM\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging: EnableScriptBlockLogging = 1)'
detection:
  browser_credential_access:
    EventID: 4104
    ScriptBlockText|contains:
      - 'Login Data'
      - 'Cookies'
      - '\AppData\Local\Google\Chrome\'
      - '\AppData\Roaming\Microsoft\Credentials'
  token_harvest:
    EventID: 4104
    ScriptBlockText|contains:
      - '.office.com'
      - 'Bearer'
      - 'access_token'
  no_file_writes:
    EventID: 4104
    ScriptBlockText|contains:
      - 'IEX'
      - 'Invoke-Expression'
      - '[System.Net.WebClient]'
  condition: (browser_credential_access or token_harvest) and no_file_writes
falsepositives:
  - Legitimate IT automation scripts accessing browser profiles (should be rare in user context)
  - Penetration testing tools
level: high
tags:
  - attack.credential_access
  - attack.t1555.003
  - attack.t1528

KQL:

DeviceEvents
| where ActionType == "PowerShellCommand"
| where AdditionalFields has_any ("Login Data", "Bearer", "access_token", "Cookies")
| where AdditionalFields has_any ("IEX", "Invoke-Expression", "[System.Net.WebClient]")
| where InitiatingProcessFileName =~ "powershell.exe"
| project Timestamp, DeviceName, AccountName, AdditionalFields
| order by Timestamp desc

Detection 3: Device Code Phishing (Entra ID)

Storm-2945 has used OAuth 2.0 device code phishing against M365 tenants since at least February 2026. The flow produces a distinctive Entra ID sign-in event: a device code grant for a first-party application (often Microsoft Office or Azure CLI) from an IP associated with hotel or conference infrastructure.

title: Suspicious OAuth Device Code Grant from Hospitality Network
id: d7e3f8a2-4b5c-6d7e-0f1a-2b3c4d5e6f78
status: experimental
description: Detects OAuth 2.0 device code grant completions from IP ranges associated with hotel or conference infrastructure, particularly for first-party Microsoft apps
author: Detection Engineering
date: 2026/08/08
logsource:
  product: azure
  service: signin
detection:
  device_code:
    AuthenticationProtocol: 'deviceCode'
    ResourceDisplayName|contains:
      - 'Microsoft Office'
      - 'Azure CLI'
      - 'Microsoft Azure PowerShell'
  location_anomaly:
    IsRisky: 'true'
  condition: device_code and location_anomaly
falsepositives:
  - Legitimate device code sign-ins from travel locations (review in context of travel schedule)
level: high
tags:
  - attack.initial_access
  - attack.t1566
  - attack.t1078.004

KQL (Entra ID Sign-In Logs via Sentinel):

SigninLogs
| where AuthenticationProtocol == "deviceCode"
| where ResourceDisplayName in ("Microsoft Office", "Windows Azure Active Directory", "Azure CLI")
| where RiskLevelDuringSignIn in ("high", "medium")
| extend City = tostring(LocationDetails.city)
| extend CountryOrRegion = tostring(LocationDetails.countryOrRegion)
| project TimeGenerated, UserPrincipalName, IPAddress, City, CountryOrRegion, 
          ResourceDisplayName, AppDisplayName, RiskLevelDuringSignIn
| order by TimeGenerated desc

Detection 4: Unexpected Device Registration

Storm-2945 uses harvested credentials and device code grants to register attacker-controlled devices with Entra ID. Unexpected new device registrations from unfamiliar locations following travel are high-priority indicators.

AuditLogs
| where OperationName == "Add device"
| extend ActorUPN = tostring(InitiatedBy.user.userPrincipalName)
| extend IPAddress = tostring(InitiatedBy.user.ipAddress)
| extend DeviceName = tostring(TargetResources[0].displayName)
| project TimeGenerated, ActorUPN, IPAddress, DeviceName, Result
| join kind=inner (
    SigninLogs
    | where AuthenticationProtocol == "deviceCode"
    | summarize DeviceCodeSigns = count() by UserPrincipalName
    | project UserPrincipalName, DeviceCodeSigns
) on $left.ActorUPN == $right.UserPrincipalName
| where DeviceCodeSigns > 0
| order by TimeGenerated desc

Detection 5: CornFlake Keylogger and Screenshot Behaviour

CornFlake captures screenshots and keystrokes. On Windows endpoints with Defender for Endpoint or compatible EDR, suspicious ReadFile activity from svchost32.exe against input desktop objects, or CreateFile handles opened against win32kbase.sys style objects, can surface this behaviour. More reliably, process creation events show CornFlake spawning child processes for credential harvesting from browsers.

title: Suspicious Process Reading Browser Credential Stores from AppData Masquerade Path
id: f1a2b3c4-d5e6-7f8a-9b0c-1d2e3f4a5b6c
status: experimental
description: Detects a process running from AppData\Roaming\svchost32\ opening browser Login Data or cookie stores
author: Detection Engineering
date: 2026/08/08
logsource:
  product: windows
  category: file_access
detection:
  masquerade_process:
    Image|contains: '\AppData\Roaming\svchost32\'
  browser_data_access:
    TargetFilename|contains:
      - '\AppData\Local\Google\Chrome\User Data\Default\Login Data'
      - '\AppData\Roaming\Microsoft\Credentials'
      - '\AppData\Local\Microsoft\Edge\User Data\Default\Login Data'
  condition: masquerade_process or (browser_data_access and masquerade_process)
falsepositives:
  - None expected — legitimate processes running from AppData\Roaming\svchost32 do not exist
level: critical
tags:
  - attack.credential_access
  - attack.t1555.003

Hunting: Users Who Connected via Hotel Wi-Fi

For retrospective hunting, correlate Entra ID sign-in geography against employee travel records. Look for sign-ins from hotel/conference IP ranges in the 90 days before review. The RiskEventType field in AADRiskyUsers will flag accounts with detected impossible travel or anonymous IP usage, which can serve as a proxy.

AADRiskyUsers
| where RiskLevel in ("high", "medium")
| where RiskDetail has_any ("anonymizedIPAddress", "unfamiliarFeatures", "impossibleTravel")
| project UserPrincipalName, RiskLevel, RiskDetail, RiskLastUpdatedDateTime
| join kind=inner (
    SigninLogs
    | where TimeGenerated > ago(90d)
    | where NetworkLocationDetails has_any ("hotel", "conference")
       or IPAddress startswith "192.168."  // refine with known hotel IP blocks
    | summarize LastSeen = max(TimeGenerated) by UserPrincipalName
) on UserPrincipalName
| order by LastSeen desc

Immediate Actions

If you suspect CaptiveCrunch compromise:

  1. Check for the Cloud Sync Service in services.msc or via Get-Service | Where-Object {$_.DisplayName -eq "Cloud Sync Service"}. If present, collect the binary from %APPDATA%\svchost32\ before remediation.
  2. Revoke all active sessions for the affected account via Entra ID portal > Users > [user] > Authentication methods > Revoke sessions.
  3. Audit registered devices under Entra ID > Devices > All devices — look for devices registered within the travel window from unfamiliar OS/platform combinations.
  4. Rotate all credentials accessible from the compromised endpoint: M365, VPN, SSH keys, stored browser passwords.
  5. Block device code authentication in Conditional Access if not already restricted — Storm-2945 has used this flow consistently since February 2026.

References