Overview
This is the second part of XM Cyber series about privilege escalation and lateral movement on Microsoft Azure. Some of the attacks that are shown in this blog are based on Azure fundamentals, explained more fully in Part 1 of this series.
In this blog (Part 2), we show different types of attacks against Azure IaaS resources and examples of how adversaries attack Azure Active Directory (AD) applications.
Before we begin, we need to go over some Azure Active Directory fundamentals.
Note: If you are already familiar with Azure Active Directory and have read the first part of this series, you can jump ahead to the section on Attacking Azure Active Directory.
Azure Active Directory RBAC
Azure AD is the identity and access management service used by Azure. This service allows users and applications to sign in and access OneDrive, Office 365, and other Azure-based resources.
Azure AD roles allow you to grant granular permissions to your users, groups, identities, and service principles. It’s a bit confusing, but there are two different role-based access controls related to Azure — Azure AD roles and Azure RBAC roles.
Azure AD roles control access to Azure AD resources such as users, groups, and applications using the Azure Active Directory Graph API while Azure RBAC roles control access to Azure resources via Azure Resource Manager.
Azure AD RBAC, like the Azure Resource Manager, consists of 3 parts:
- Role definition
- Scope
- Role Assignment
Role definition comprises a group of permissions, with two types of roles — built-in and custom.
Built-in roles are predefined and cannot be changed. There are many built-in roles, plus custom roles to meet special requirements beyond the built-in ones. At the time of writing this blog, custom role definitions aren’t sufficiently mature (not fully supported for users), and therefore not covered in this blog. Moreover, when referring to attacks against Azure AD, we will refer to the role and not the specific permission involved.
Role Assignment grants to a user/group/identity/service principal the permissions in role definition on a specific scope.
Applications (App Registration) vs. Service Principals (Enterprise applications)
It is easy to confuse Azure Applications and Azure Service Principals. Let’s try to clarify the differences:
Applications are created in Azure AD to allow API access to Microsoft 365 or other applications data by third-party apps. The Azure AD API supports single- and multi-tenant applications.
In order to allow applications to make calls to the Azure Active Directory API, permissions need to be configured for the application using the Graph API. There are two different types of permissions assigned to applications:
- Delegated permissions — allows applications to perform API queries to access or modify data on behalf of a signed-in user.
- Application permissions — allows an application to perform API queries in order to access or modify data without a signed-in user.
Service Principals are representations of an application in a tenant. For every tenant, there are multiple service principals that represent applications not managed directly (for example, the Microsoft Teams service principal is a Microsoft teams application managed on a Microsoft tenant).
In the next section, we will explore attacks against Azure Applications.
Note: During our research, we discovered that this type of attacks works only on particular service principals, which we didn’t fully enumerate. Therefore, we decided not to cover service principals attacks in this blog, but to concentrate only on application attacks.
Attacking Azure Active Directory
Attacking Azure Applications
All of the attacks below utilize the same technique- adding password(s) to an Azure AD application. We will explore multiple means for adding those credentials.
Any valid user/identity can perform reconnaissance on Azure AD applications. However, Service Principals cannot recon applications by default — they need to possess one (or more) of the following application permissions
- Application.Read.All
- Application.ReadWrite.All
- Directory.Read.All
With those permissions, you can list applications in the tenant using the Azure az ad command
az ad app list
Reset Application Password From AD Roles
An attacker possessing one of the following AD roles
- Company Administrator
- Application Administrator
- Cloud Application Administrator
can reset the password for the application with the captured from the previous output using the command
az ad app credential reset --id
Application Owners
Application ownership is a simple way to gain management rights for all aspects of Azure AD configuration for a specific application or service principal. An attacker that compromises a user that is an application owner can compromise the owned application by resetting the application password using the same command mentioned in the previous attack.
Application Permissions
An application with the API permission Application.ReadWrite.All can add passwords for applications using the following REST API:
POST /applications/{id}/addPassword
Attacking Azure Resource Manager
Automation Accounts
Azure Automation accounts support automation of various tasks in Azure Resource Manager. Using Automation Accounts Runbooks, you can execute scripts to manage tenant resources across all regions and subscriptions in the tenant.
Creating an Automation account using the Azure portal results in creating a Run As account automatically. This account creates a service principal in Azure Active Directory, including a valid certificate, and assigns the Contributor role to the service principal. It grants the runbooks executing under this Automation account full control over Azure Resource Manager resources in the subscription.
An attacker with permissions to create/modify a runbook in an Automation account configured with an Azure Run As account and possessing a valid certificate has full control over all resources under the subscription.
Recon
An attacker possessing a stolen access key with the permission Microsoft.Automation/automationAccounts/read can list the Automation accounts in the environment using the command
az automation account list -g
Compromise
Next, an attacker will attempt to create and run a new runbook under this account. With the permissions Microsoft.Automation/automationAccounts/runbooks/write and Microsoft.Automation/automationAccounts/jobs/write for an automation account, he or she can create a new runbook using the following Rest API:
PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Automation/automationAccounts/{automationAccountName}/runbooks/{runbookName}?api-version=2015-10-31{ "properties": { "logVerbose": false, "logProgress": true, "runbookType": "PowerShellWorkflow", "publishContentLink": { "uri": "runbook content URI", "contentHash": { "algorithm": "SHA256", "value": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" } }, "description": "Description of the Runbook", "logActivityTrace": 1 }, "name": "RunBookName", "location": "East US 2" } Note: There are also CLI commands to create runbooks, but currently those commands require different permissions.
After creating the runbook, the attacker must create a job from the runbook, use the REST API or the CLI:
REST API
PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Automation/automationAccounts/{automationAccountName}/jobs/{jobName}?api-version=2017-05-15-preview{ "properties": { "runbook": { "name": "TestRunbook" }, "parameters": { "key01": "value01", "key02": "value02" }, "runOn": "" } }
CLI Command
az automation runbook start --automation-account-name -g -n
Azure Key Vault Secrets & Keys
The Azure Key Vault provides secure storage for secrets (such as passwords and database connection strings), certificates, and various key types.
To perform operations on secrets, keys, and certificates in a key vault, a key vault access policy needs to be configured, to determine which operations are allowed for a given service principal, user, or group.
Recon
An attacker possessing the permission Microsoft.KeyVault/vaults/read can list the key vaults in the environment using the command
az keyvault list
To list the keys/secrets in this key vault, the key/secret policy “List” is required. Using the command
az keyvault list --vault-name
the attacker can list all the key vaults keys/secrets.
Compromise
The secret policy “Get” in the key vault will allow the attacker to show the key vault secrets values using the following CLI command
az keyvault secret show --vault-name -n
The key policy “Decrypt” allows an attacker to use the key vault keys for data decryption, using the following command
az keyvault key decrypt --algorithm {RSA-OAEP, RSA-OAEP-256, RSA1_5} --value --id
As demonstrated, different access policies allow the attacker to perform different operations over the key vault.
Another interesting attack vector lies in the ability to modify key vault access policy. The required role definition permission for this attack path is Microsoft.KeyVault/vaults/accessPolicies/write.
This permission allows the attacker to create a new policy for the desired key vault using the following Rest API:
PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.KeyVault/vaults/{vaultName}/accessPolicies/{operationKind}?api-version=2019-09-01{ "properties": { "accessPolicies": [ { "tenantId": "00000000-0000-0000-0000-000000000000", "objectId": "00000000-0000-0000-0000-000000000000", "permissions": { "keys": [ "encrypt" ], "secrets": [ "get" ] } }] } }
This permission allows an attacker to perform any operation on the key vault.
Databases
Azure supports multiple database types. The databases we investigated include Azure MySQL, Azure PostgreSQL, Azure SQL and Azure Cosmos DB. The management and configuration of Azure MySQL, Azure PostgreSQL, and Azure SQL are quite similar so we will focus only on Azure MySQL and Azure CosmosDB.
Recon
To obtain a listing of Azure MySQL and Azure CosmosDB databases in a subscription, the permissions Microsoft.DBforMySQL/servers/read (for MySQL) and Microsoft.DocumentDB/databaseAccounts/read (for CosmosDB) are required.
An attacker can use the command az mysql server list to list MySQL databases and az cosmosdb list for Azure Cosmos DB.
Compromise
An attacker will next log into the discovered database(s). Possessing the permissions Microsoft.DBforMySQL/servers/read and Microsoft.DBforMySQL/servers/write he or she will be able to reset MySQL user password using the following command
az mysql server update -n -p -g
With the permission Microsoft.DocumentDB/databaseAccounts/listKeys/action, an attacker can retrieve Cosmos DB access keys using the command
az cosmosdb keys list -n -g
The permission Microsoft.DocumentDB/databaseAccounts/listConnectionStrings/action will also allow the attacker to obtain the access keys using the command
az cosmosdb keys list --type connection-strings -n -g
These access keys grant users full control of Cosmos DB resources in an account.
Access to the database
By default, Microsoft prevents access to an Azure MySQL Database until the creation of Firewall or VNET rules to manage access to it. In order for an attacker to connect to the database, just a password isn’t sufficient; he or she would also have to compromise a machine with access to the database and connect to it.
With the permission Microsoft.DBforMySQL/servers/firewallRules/write, the simplest option for an attacker will be to add a new Firewall rule with its IP address using the following Rest API:
PUT https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.DBForMySQL/servers/{serverName}/firewallRules/{firewallRuleName}?api-version=2017-12-01{ "properties": { "startIpAddress": "0.0.0.0", "endIpAddress": "255.255.255.255" } }
Then, he or she will be able to connect to the database locally (if the database has public network access).
Conversely, Azure Cosmos DB is by default accessible from the internet using a valid authorization token. If the default configuration wasn’t changed, an attacker with valid permissions can authenticate to the database from any IP address. Otherwise, he or she must take the same steps described for Azure MySQL (connect the database from a machine with access or add a new firewall rule).
Remediation
In the previous blog, we demonstrated different attack vectors on Azure resources. The remediations highlighted in Part 1 are also relevant here. Let’s detail some additional remediation advice specific to the attack vectors explained in this blog:
- Review Azure Active Directory role assignments and ensure principals possess only the required roles to perform their assigned tasks.
- Consider deleting unnecessary owners from applications if that ownership isn’t necessary.
- When granting API permissions to Azure applications, provide the applications only the minimum required permissions necessary.
- Limit Run As account permissions for automation accounts using the Update-AutomationRunAsAccountRoleAssignments.ps1 script. This script changes an existing Run As account service principal to use a custom role definition.
- Review key vault access policies and delete unnecessary policies to prevent unintentional use of keys, secrets and certificates.
- Review database firewall and virtual network rules and minimize network access to your databases as much as possible, to limit attackers with the right permissions from connecting to them.
Summary
Microsoft Azure is a cloud platform with multiple interesting features.
It’s easy to become confused by the various azure RBAC permissions models. This confusion can cause misconfiguration within cloud environments that can open multiple attack vectors, placing your infrastructure at risk. The various attack vectors described in this series, while presenting high risk and serious consequence to your critical assets, are easily remediated with attention to detail around permissions, roles, and other configuration options.
Zur Ulianizky is Head of Research, XM Cyber
Hila Cohen is Security Researcher, XM Cyber
References
- https://docs.microsoft.com/en-us/rest/api/automation/runbook/createorupdate — Create or update runbooks
- https://docs.microsoft.com/en-us/rest/api/automation/job/create — Create new runbook job
- https://docs.microsoft.com/en-us/azure/automation/manage-runas-account — Manage run as accounts
- https://docs.microsoft.com/en-us/azure/automation/automation-create-standalone-account — Create Azure automation account
- https://docs.microsoft.com/en-us/cli/azure/ext/automation/automation — Automation account cli commands
- https://docs.microsoft.com/en-us/azure/key-vault/secrets/about-secrets — About key-vault secrets
- https://docs.microsoft.com/en-us/azure/key-vault/keys/about-keys — About key-vault keys
- https://docs.microsoft.com/en-us/azure/key-vault/general/assign-access-policy-portal — Assigning key-vault access policy
- https://docs.microsoft.com/en-us/rest/api/keyvault/vaults/updateaccesspolicy — Vaults — Update Access Policy
- https://docs.microsoft.com/en-us/cli/azure/keyvault — key-vault cli commands
- https://docs.microsoft.com/en-us/azure/cosmos-db/how-to-configure-firewall — Configure IP firewall for Cosmos db
- https://docs.microsoft.com/en-us/azure/mysql/concepts-firewall-rules — Azure Database for MySQL server firewall rules
- https://docs.microsoft.com/en-us/cli/azure/mysql — mysql cli commands
- https://docs.microsoft.com/en-us/cli/azure/cosmosdb — cosmosdb cli commands
- https://docs.microsoft.com/en-us/rest/api/mysql/firewallrules/createorupdate — Create or update MySQL firewall rules
- https://docs.microsoft.com/en-us/azure/active-directory/roles/custom-overview — Azure AD RBAC overview
- https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-permissions-and-consent — Permissions and consent in the Microsoft identity platform
- https://docs.microsoft.com/en-us/azure/active-directory/develop/single-and-multi-tenant-apps — Tenancy in Azure Active Directory
- https://docs.microsoft.com/en-us/graph/api/application-list — List applications