Cloud Security Office Hours Banner

Storm-2949 / Entra ID SSPR 2026

Step-by-step kill chain mapped to MITRE ATT&CK Cloud, sourced from official post-mortems and primary technical analyses.

May 2026 Critical Azure

Storm-2949 - SSPR Reset + Fake IT Call → MFA Method Takeover → Azure RBAC Abuse → Key Vault, SQL and Storage Theft

On May 18, 2026 Microsoft Threat Intelligence published its analysis of Storm-2949, a threat activity cluster that broke into Microsoft 365 and Azure tenants with no malware at initial access. Microsoft assesses with high confidence that the actor started a Microsoft Entra ID Self-Service Password Reset (SSPR) on a target's behalf and then phoned that target while impersonating internal IT support, so the victim would approve the resulting MFA prompt as part of what sounded like a routine reset. With the account in hand the actor removed the victim's existing authentication methods, enrolled its own Microsoft Authenticator device, and then rode existing privileged Azure RBAC assignments across multiple subscriptions into App Service publishing profiles, Key Vault secrets, SQL databases, storage accounts, and virtual machines. Victim organizations were not named; the targeted users were IT personnel and senior leadership, and the objective was to exfiltrate as much data as possible from high-value assets.

Dozens of Key Vault secrets taken in a four-minute window
Thousands of OneDrive / SharePoint files exfiltrated
No malware at initial access - identity abuse only
Threat actor: Storm-2949 (Microsoft designation for an activity cluster not yet attributed)
📄 Microsoft Security Blog - How Storm-2949 turned a compromised identity into a cloud-wide breach ↗ 📄 BleepingComputer - Self-Service Password Reset abused in Azure data theft attacks ↗
Initial Access - Attacker-Initiated SSPR + Vishing
01
Storm-2949 started an Entra ID Self-Service Password Reset on a target's behalf, then called the target posing as IT support to get the MFA prompt approved
T1621 - MFA Request Generation T1078.004 - Valid Accounts: Cloud Accounts

Microsoft is explicit about its confidence here: it assesses with high confidence that Storm-2949 used a social engineering technique consistent with known abuses of the SSPR process, an assessment drawn from the roles of the compromised users and the investigation findings rather than from a directly observed initial-access artifact. The actor triggered the SSPR flow for a chosen user, then contacted that user by phone while impersonating an internal IT support representative, claiming the account needed urgent verification and instructing them to approve the MFA prompt as part of a routine password reset. The prompt was genuine, so number matching and push approval bought nothing: the control was validating a real Entra ID request, not the identity of the person who asked for it. Victim selection skewed to IT personnel and senior leadership, which Microsoft says indicated deliberate targeting and, in its assessment, an organized and convincing phishing scheme.

Mechanism: Attacker-initiated Entra ID SSPR, followed by a voice call impersonating internal IT support
Confidence: Microsoft assesses this vector with high confidence rather than asserting direct observation
Targets: IT personnel and senior leadership - users likely to hold privileged roles
Why it worked: The MFA prompt was legitimate; a user primed to expect it will approve it, and number matching cannot tell the difference
Defense gap: SSPR accepted push and number-match approval instead of phishing-resistant verification
SSPR AbuseVishingMFA ApprovalNo MalwareT1621
🔐 Persistence - Authentication Method Takeover
02
Existing authentication methods were stripped and an attacker-controlled Microsoft Authenticator device enrolled, locking the legitimate owner out of their own account
T1556.006 - Modify Authentication Process: MFA T1098.005 - Account Manipulation: Device Registration

Holding the reset flow, the actor rewrote the account's authentication posture rather than simply using it. Registered phone numbers, email addresses, and prior Microsoft Authenticator registrations were removed, and an attacker-controlled Authenticator device was enrolled in their place. That single change turned MFA from a control into an asset: every subsequent sign-in satisfied MFA and Conditional Access policy using the attacker's device, while the real owner lost the exact methods they would have needed to recover the account. The actor also tried to push persistence past user accounts entirely by adding credentials to a compromised Entra service principal, which would have survived any user-side password reset. That attempt failed for lack of permissions.

Methods removed: Registered phone number, email address, and prior Microsoft Authenticator registrations
Method added: Attacker-controlled Microsoft Authenticator device
Attempted and failed: Adding credentials to a compromised Entra service principal, blocked by insufficient permissions
Effect: MFA and Conditional Access now attest the attacker's device; the legitimate user cannot self-recover
Detection signal: Microsoft Defender XDR alert for suspicious addition of a default third-party MFA method to a user account
Auth Method TakeoverDevice RegistrationService PrincipalT1556.006T1098.005
🔍 Discovery - Microsoft Graph Enumeration
03
Custom Python scripts drove the Microsoft Graph API to enumerate users, roles, applications, and service principals across the tenant
T1087.004 - Account Discovery: Cloud Account T1580 - Cloud Infrastructure Discovery

Instead of clicking through the portal, the actor issued automated API requests through Microsoft Graph using custom Python scripts, enumerating users and applications within the tenant. It searched Entra ID for accounts by name pattern and role attribute, which Microsoft assesses was likely intended to identify privileged identities and additional high-value targets, and it mapped the applications and service principals registered in the tenant. Graph reads of this kind are authenticated, expected, and high volume in most tenants, so scripted enumeration coming from a legitimate compromised account produces very little that stands out without behavior baselining on request volume and pattern.

Interface: Microsoft Graph API, driven by custom Python scripts
Enumerated: User accounts by name pattern and role attribute, groups, applications, service principals
Purpose: Locate privileged identities and follow-on targets inside the tenant
Detection gap: Graph reads from a valid user session resemble ordinary tooling unless volume and pattern are baselined
Microsoft GraphPython ToolingTenant EnumerationT1087.004T1580
⬆️ Privilege Escalation - Inherited Azure RBAC and App Service Profiles
04
Existing privileged Azure RBAC assignments were used as-is, and microsoft.Web/sites/publishxml/action handed over App Service deployment credentials and Kudu console access
T1078.004 - Valid Accounts: Cloud Accounts T1552 - Unsecured Credentials

No exploit was required at this stage. The compromised identities already carried privileged custom Azure RBAC roles on several subscriptions, so the actor simply used the authorization the accounts were already holding. It called microsoft.Web/sites/publishxml/action to retrieve App Service publishing profiles, which carry FTP and Web Deploy deployment credentials inside the profile itself, and used those to reach the Kudu console. Kudu is the built-in administrative interface for Azure App Services that lets an authenticated user browse the file system, inspect environment variables, and execute commands in the application's own context. An ARM permission that reads like a deployment convenience therefore delivered interactive command execution inside production web applications.

ARM operation: microsoft.Web/sites/publishxml/action - retrieves the App Service publishing profile
Credentials obtained: FTP and Web Deploy deployment credentials, carried in the profile
Follow-on access: Kudu console - file system browsing, environment variables, command execution in the app context
Why it worked: Privileged custom RBAC roles were already assigned to the compromised users across multiple subscriptions
Defense gap: publishxml is classed as a management action, but it functions as credential issuance
Azure RBACpublishxmlKudu ConsoleApp ServiceT1078.004
🔑 Credential Access - Key Vault Secrets in Four Minutes
05
Key Vault access configuration was modified and dozens of secrets pulled inside a four-minute window
T1555 - Credentials from Password Stores

The actor manipulated Key Vault access configurations and then read dozens of secrets out of the vault, all inside roughly four minutes. Those secrets included database connection strings and identity credentials, which Microsoft notes dramatically expanded the attack's blast radius. The structural lesson for defenders sits in the sequence: changing who may read a vault is an ARM control-plane operation, while reading the secrets is a data-plane operation. An actor with sufficient control-plane rights can grant itself data-plane access and spend it long before a human reviews the policy change.

Sequence: Modify Key Vault access configuration (control plane) → read secrets (data plane)
Volume and window: Dozens of secrets in roughly four minutes
Secret types: Database connection strings, identity credentials, and more
Why it worked: Control-plane rights over the vault were convertible into data-plane read access on demand
Defense gap: No alert on the access-configuration change, and no rate anomaly raised on bulk secret reads
Azure Key VaultSecret TheftControl PlaneT1555
🔀 Lateral Movement - Control Plane to Data Plane
06
firewallrules/write opened Azure SQL to attacker IPs and storageAccounts/listkeys/action produced account keys and SAS tokens
T1528 - Steal Application Access Token

This is the hinge of the entire intrusion. Holding connection strings from Key Vault, the actor still needed a network path, so it called microsoft.sql/servers/firewallrules/write to add its own addresses to the Azure SQL server firewall and then signed in to the databases with the harvested credentials. In parallel it used microsoft.storage/storageaccounts/write to manipulate storage account network access configuration and microsoft.Storage/storageAccounts/listkeys/action to obtain account keys and shared access signature (SAS) tokens. Not one of those operations reads a byte of customer data by itself, and every one of them looks like ordinary infrastructure management on a change ticket. Chained, they are a complete path from Azure Resource Manager rights to live production data.

ARM operations: microsoft.sql/servers/firewallrules/write, microsoft.storage/storageaccounts/write, microsoft.Storage/storageAccounts/listkeys/action
Result: SQL server firewall opened to attacker addresses; storage account keys and SAS tokens obtained
Credentials used: Database connection strings taken from Key Vault in the previous step
Attacker IPs: 176.123.4[.]44, 91.208.197[.]87
Why it worked: listkeys and firewallrules/write are classed as management permissions but behave as direct data access
SQL FirewalllistkeysSAS TokenData Plane PivotT1528
💻 Execution & Defense Evasion - Azure VMs
07
VMAccess and Run Command created backdoor admin accounts and ran scripts on Azure VMs, then Defender was disabled and a renamed ScreenConnect service installed
T1651 - Cloud Administration Command T1685 - Disable or Modify Tools

From the Azure control plane the actor reached into the guest operating system. It deployed the VMAccess extension to create backdoor local administrator accounts on targeted VMs and used Run Command to execute scripts, including an attempt to abuse a VM managed identity by requesting an access token from the Azure Instance Metadata Service and using it to authenticate to and retrieve secrets from the production web app's Key Vault. It then set about blinding the host. PowerShell scripts attempted to disable Microsoft Defender Antivirus real-time protection and behavior monitoring and to interfere with the associated service, and ScreenConnect was installed from attacker infrastructure with network requests spoofed to resemble trusted software updates, files placed in locations resembling legitimate system content, and the service renamed to resemble a Windows component. Windows event logs were cleared, and command history and temporary files were deleted.

Cloud-to-guest tooling: VMAccess extension (backdoor local admin accounts), Run Command (script execution)
Managed identity attempt: Request an access token from IMDS, then authenticate to the web app Key Vault with it
Defender tampering: PowerShell disabling real-time protection and behavior monitoring, plus interference with the service
RMM masquerade: ScreenConnect served from 185.241.208[.]243, service renamed to resemble a Windows component
Anti-forensics: Windows event logs cleared, command history and temporary files deleted (T1685.005)
VMAccessRun CommandIMDSDefender TamperingScreenConnectT1651T1685
📤 Exfiltration - OneDrive, SharePoint and Azure Blobs
08
Thousands of files pulled from OneDrive and SharePoint through the web interface, and a custom Python script on the Azure Storage SDK drained blobs over multiple days
T1530 - Data from Cloud Storage T1213.002 - Data from Information Repositories: Sharepoint

Exfiltration ran on two tracks. In Microsoft 365 the actor used the OneDrive web interface to download thousands of files in a single action to its own infrastructure, concentrating on IT documents covering virtual private network (VPN) configuration and remote access procedures - precisely the material that makes the next intrusion cheaper. In Azure it ran a custom Python script built on the Azure SDK for Storage to programmatically enumerate and download blobs directly to an attacker-controlled endpoint device. That storage-based exfiltration continued over multiple days from the initial access, with the actor alternating between secret-based and OAuth-based authentication as access conditions and controls shifted around it. The actor also discovered and exfiltrated .pfx certificate files, artifacts that may contain private keys and could be valuable for follow-on access if imported or reused elsewhere.

Microsoft 365: OneDrive web interface, thousands of files in a single action, sent to attacker infrastructure
Documents targeted: VPN configuration and remote access procedure documentation
Azure Storage: Custom Python script on the Azure SDK for Storage, enumerating and downloading blobs
Duration and auth: Continued over multiple days, alternating secret-based and OAuth-based authentication
Also taken: .pfx certificate files that may contain private keys usable for follow-on access
OneDriveSharePointAzure Storage SDK.pfx CertificatesT1530

🛡 How to Defend Against This Chain

Treat self-service password reset as a credential-issuance system and protect it like one. SSPR mints a working credential for anyone who can satisfy it, so it deserves the same scrutiny as an admin role grant. Require phishing-resistant methods (FIDO2 security keys, passkeys, or Windows Hello for Business) in the Entra ID Authentication Methods policy for reset and for every privileged account. MFA number matching alone does not stop this: the prompt Storm-2949 generated was real, and a user who has just been told by IT to expect it will approve it.
Alert on authentication method registration changes, not only on sign-ins. The whole takeover is visible in the Entra ID audit log as method removals followed by a new device enrollment. Treat "all existing methods removed, then one new Authenticator registered" as an incident rather than a help-desk event, and enable the Defender XDR detection for suspicious addition of a default third-party MFA method to a user account. Monitor for credentials being added to service principals as well: Storm-2949 tried exactly that and was stopped only by a permissions gap.
Gate the registration flow itself with Conditional Access. Apply a policy to the Register security information user action that requires a compliant or hybrid-joined device, or a trusted network, so a caller working from an unmanaged device cannot re-enroll MFA at all. In the same pass, disable legacy authentication tenant-wide and turn off basic authentication on App Services, which removes the FTP and Web Deploy path that the stolen publishing profiles depended on.
Stop treating ARM management permissions as harmless, and monitor the specific operations. Audit Azure RBAC role assignments regularly, replace standing privileged custom roles with just-in-time elevation, and alert in Azure Monitor activity logs on microsoft.Web/sites/publishxml/action, microsoft.Storage/storageAccounts/listkeys/action, microsoft.sql/servers/firewallrules/write, and microsoft.storage/storageaccounts/write. Every one of those reads as management and every one is, in practice, a direct path to production data. Restrict VMAccess extension deployment and Run Command the same way, and scope each VM managed identity to least privilege so a stolen IMDS token is worth as little as possible.
Harden Key Vault on all four axes: RBAC, network, purge protection, and logging. Use Azure RBAC authorization rather than legacy access policies, put the vault behind its firewall and private endpoints, enable soft delete and purge protection, and stream diagnostic logs to your SIEM. Alert on any access-configuration or role-assignment change on a vault, and on bulk secret-read volume: dozens of reads inside four minutes should page someone.
Turn on Defender tamper protection and hunt with the tables Microsoft named. Tamper protection blocks the exact PowerShell attempts to disable real-time protection and behavior monitoring that this actor used. For retrospective hunting, Microsoft points at the Defender XDR advanced hunting tables CloudAuditEvents for Azure control-plane activity and CloudStorageAggregatedEvents for storage data-plane access. Published indicators to sweep for: 176.123.4[.]44, 91.208.197[.]87, and 185.241.208[.]243.

Related defense topics