StorageCertificateTheft¶
Category: Resource-Based Privilege Escalation
An attacker compromises an identity with read access to Azure Blob Storage and downloads application certificates and private keys stored in a storage container. The attacker uses certificate-based authentication to impersonate a privileged application.
Posture¶
graph LR
ID(("Compromised<br/>Identity")) -->|"Blob Data<br/>Reader on"| SA(("Azure Storage<br/>Account"))
SA -->|"stores certificate for"| APP(("Privileged<br/>Application"))
APP -->|"assigned"| PRIV(("Entra ID Role<br/>or API Permission"))
Attack Steps¶
graph LR
A(("Attacker")) -->|"1. Download cert from"| SA(("Azure Storage<br/>Account"))
A -->|"2. Authenticate as"| SP(("Service<br/>Principal"))
SP -->|"3. Escalate to"| ACCESS(("Privileged<br/>Access"))
What Happens¶
- The attacker gains access to a user account or service principal
- The compromised identity has Storage Blob Data Reader role on an Azure Storage Account
- The storage account contains X.509 certificates (
.pem) and private keys (.key) for application registrations - The attacker downloads the certificate and private key files from blob storage
- The attacker uses certificate-based authentication to impersonate the application's service principal
- The application has high-privileged Entra ID roles or API permissions
How It Differs From KeyVaultSecretTheft¶
| StorageCertificateTheft | KeyVaultSecretTheft | |
|---|---|---|
| Target resource | Azure Storage Account | Azure Key Vault |
| Credential type | Certificates + private keys | Client secrets |
| Auth method | Certificate-based (X.509) | Secret-based (client credentials) |
| Detection | Certificate auth is harder to detect in logs | Secret-based auth produces clearer audit signals |
How It Differs From ManagedIdentityAbuse¶
This attack path provides direct access to the Storage Account. Use this when simulating scenarios where a user or service principal has been directly granted blob storage access, rather than reaching it through a managed identity.
Certificate Management¶
BadZure automatically handles certificate lifecycle:
- Generates self-signed X.509 certificates with 1-year validity
- Creates unique certificate and key file names to prevent conflicts
- Stores certificates in private blob containers
- Registers certificates with target applications via Terraform
Variations¶
By Identity Type¶
A user account with Storage Blob Data Reader role. Simulates a compromised user with overly broad storage access.
graph LR
U(("Compromised<br/>User")) -->|"Blob Data<br/>Reader"| SA(("Azure Storage<br/>Account"))
SA -->|"download cert"| APP(("Privileged<br/>Application"))
A service principal with Storage Blob Data Reader role. Simulates a compromised pipeline with excessive storage permissions.
graph LR
SP(("Compromised<br/>Service Principal")) -->|"Blob Data<br/>Reader"| SA(("Azure Storage<br/>Account"))
SA -->|"download cert"| APP(("Privileged<br/>Application"))
By Assignment Type¶
Storage Blob Data Reader is assigned directly to the identity.
graph LR
ID(("Compromised<br/>Identity")) -->|"Blob Data<br/>Reader"| SA(("Azure Storage<br/>Account"))
SA -->|"download cert"| APP(("Privileged<br/>Application"))
The identity is a member of a security group with Storage Blob Data Reader access.
graph LR
U(("Compromised<br/>Identity")) -->|"member of"| G(("Security<br/>Group"))
G -->|"Storage Blob<br/>Data Reader"| SA(("Azure Storage<br/>Account"))
SA -->|"download cert"| APP(("Privileged<br/>Application"))
The identity owns a security group with Storage Blob Data Reader access. As group owner, the attacker can add themselves as a member to inherit the group's privileges.
graph LR
U(("Compromised<br/>Identity")) -->|"owner of"| G(("Security<br/>Group"))
G -->|"Storage Blob<br/>Data Reader"| SA(("Azure Storage<br/>Account"))
SA -->|"download cert"| APP(("Privileged<br/>Application"))
Configuration Examples¶
User with direct storage access, application has Global Administrator role:
attack_paths:
storage_theft_basic:
enabled: true
privilege_escalation: StorageCertificateTheft
method: AzureADRole
entra_role: 62e90394-69f5-4237-9190-012177145e10 # Global Administrator
Service principal with Graph API permissions:
attack_paths:
storage_theft_sp:
enabled: true
privilege_escalation: StorageCertificateTheft
initial_access: service_principal
method: APIPermission
api_type: graph
app_role:
- 06b708a9-e830-4db3-a914-8e69da51d44f # AppRoleAssignment.ReadWrite.All
- 19dbc75e-c2e2-444c-a770-ec69d8559fc7 # Directory.ReadWrite.All
Group-based assignment:
attack_paths:
storage_theft_group:
enabled: true
privilege_escalation: StorageCertificateTheft
assignment_type: group_member
method: APIPermission
api_type: graph
app_role: 06b708a9-e830-4db3-a914-8e69da51d44f # AppRoleAssignment.ReadWrite.All
Tip
Make sure your tenant configuration includes at least one Storage Account (storage_accounts: 1) when using this attack path.