Azure Penetration Testing: Objectives, Methodology and Use Cases

Like other cloud services, Azure is a prime target for attackers. This is due to its growing popularity and strategic importance for businesses.

To reduce the risk of security breaches, it is essential to implement robust security measures. It is also important to understand the types of attack and assess their potential impact.

There are several ways of assessing the security of an Azure infrastructure. In this article, we present the ‘offensive’ approach, which we believe to be the most effective: Azure cloud penetration testing (or Azure pentesting). We detail the principles and objectives, as well as the methodology for an Azure audit through a concrete use case.

Comprehensive Guide to Azure Pentesting

What is Azure Penetration Testing?

An Azure penetration test aims to assess the security of services and resources hosted in an Azure cloud environment.

This type of audit simulates cyber attacks to identify exploitable weaknesses in the infrastructure and configurations of Azure resources, such as virtual machines, databases, web applications and containers.

The aim is to discover potential vulnerabilities, measure their impact and propose corrective measures to strengthen the security of the target system.

Scope of an Azure Penetration Test

The scope of an Azure penetration test can be adapted to suit the specific needs of your organisation.

It is possible to test all the services and configurations of your Azure infrastructure or to focus on the most critical elements.

Thus, the tests cover (non-exhaustive list):

  • Virtual machines: identification of poorly secured services, out-of-date software or configuration errors.
  • Databases: unauthorised access, poor permissions management, data leaks, etc.
  • Storage services: exposure of sensitive data, poor access management, file share configurations, etc.
  • Identity and access management: analysis of roles and permissions, broken access control, etc.
  • Hosted web applications and APIs: application vulnerabilities inherent in this type of system (injections, RCE, etc.).

Perform a penetration test with Vaadata

Azure Penetration Testing Methodology

To present the methodology of an Azure penetration test, let’s put ourselves in the shoes of an attacker seeking to compromise the company ‘VaadataLab’.

We will begin by presenting the Azure tools, techniques and concepts that can be used to gather information and compromise critical business data, by exploiting configuration weaknesses in Azure.

We will then examine the measures that VaadataLab could have implemented to protect itself.

For all types of offensive audit, the reconnaissance phase is essential. The aim is to gain a better understanding of the target infrastructure.

As part of an Azure penetration test, this involves determining which Azure services are being used (App services, Key Vault, CosmosDB, etc.).

In Azure, each service has its own domain. For example, as soon as a web app is created, an associated domain of the form <subdomain>.azurewebsites.net is also created.

Tools such as MicroBurst (specific to Azure) or Cloud Enum (multi-cloud) facilitate this reconnaissance. These tools use dictionaries and apply permutation rules to find services that may belong to the target company.

In our example, we will use the MicroBust tool with the following command:

Invoke-EnumerateAzureSubDomains -Base vaadatalab -Permutations .\permutations.txt

The -Base argument defines the keyword on which the various permutations will be performed in order to discover Azure resources. As for the -Permutations argument, this is a wordlist used to perform the permutations.

Identifying VaadataLab resources

Here we discover that VaadataLab has :

  • 3 web apps or ‘Function Apps’: ‘staging-vaadatalab’, ‘vaadatalabprod’ and ‘vaadatalab’.
  • 3 Continuous Deployment Services (SCM) for application deployment.
  • 1 storage Account ‘vaadatalabprod8a07’.

NB: an Azure Storage Account contains all the Azure Storage objects: blobs, files, queues and tables. In addition, the source code of Function Apps can be stored in a Storage Account.

The reconnaissance phase can go even further. For example, the tenant ID of a domain can be retrieved, as well as the list of domain names associated with a tenant, extending the reconnaissance to these domains. It is also possible to check the existence of an email address. This can be used, for example, to run phishing campaigns.

We won’t dwell on these points in this article.

We now have a clearer view of VaadataLab’s Azure infrastructure.

To compromise this infrastructure from web applications, we first need to identify a vulnerability that allows arbitrary commands to be executed or files to be read on the underlying system.

The aim is to recover secrets that can be used to compromise a ‘Service Principal’. This represents the identity of the resource in the tenant.

There are two ways of authenticating with a Service Principal from a compromised application. The first is to find an ‘identifier:secret’ pair in a configuration file. The second involves sending an HTTP request to the MSI_ENDPOINT using IDENTITY_HEADER as the secret.

The MSI_ENDPOINT is the environment where the ‘Managed identities’ service is exposed. This service provides applications with an identity that is automatically managed in Microsoft Entra ID. With this identity, applications can obtain Microsoft Entra tokens without managing identification information. This information is often available in server environment variables.

Auditing hosted applications

Let’s take a closer look at the 3 web applications discovered during the reconnaissance phase.

They look very similar, and we seem to be dealing with an application from a company specialising in the sale of plastic ducks.

VaadataLab website

Based on our experience, we will tackle the ‘staging-vaadatalab’ application first. In general, staging environments should not be exposed on the Internet. They are development environments, which are often more vulnerable.

This is where we come into line with the methodology used in web penetration testing to discover and exploit vulnerabilities.

By chance, the fuzzing carried out on the staging environment uncovered a file called ‘test’, which looks promising.

Command injection exploitation

Injection tests on a form on the website revealed a command injection vulnerability. This allowed us to execute commands on the underlying system.

The first step is to retrieve the environment variables. Since the underlying system is Windows, this can be done with the following command:

echo $MSI_ENDPOINT $IDENTITY_ENDPOINT
Staging environment test page

We now have everything we need to compromise the application’s Service Principal.

To do this, we simply need to run the following command on the underlying system:

curl $MSI_ENDPOINT?resource=https://management.azure.com&api-version=2017-09-01" -H secret:$IDENTITY_HEADER

This command sends an HTTP request to the ‘managed identities’ service and retrieves a JWT associated with the application’s Service Principal.

We can then use this JWT and the privileges associated with the account to move laterally in the Azure infrastructure.

Retrieving an access token associated with the staging-vaadatalab account

Let’s start by listing the resources accessible by our application’s Service Principal, using the following powershell code:

# Connection with the compromise Web app account
$access_token = "<access_token_management>"
Connect-AzAccount -AccessToken $access_token -AccountId 02861316-6d42-4d55-b2f7-542af2fb9915
Get-AzResource

So we can see that we can access a Key Vault named ‘keyvaultvaadatalab1’.

List of resources accessible with the staging-vaadatalab account

A Key Vault is a service for centralising and storing passwords, connection strings, certificates, secret keys and so on. It also simplifies the management of application secrets and allows integration with other Azure services.

So it’s a safe bet that sensitive information is stored in this Key Vault. But having access to a resource does not mean that you can do everything with it. Azure (like other cloud services) offers a high level of granularity in terms of the permissions that can be given to one resource over another.

We therefore need to list the permissions we have on the Key Vault. This can be done using the following powershell code:

$access_token = "<access_token_management>"
Connect-AzAccount -AccessToken $access_token -AccountId 02861316-6d42-4d55-b2f7-542af2fb9915
$KeyVault = Get-AzKeyVault
$Token = (Get-AzAccessToken).Token
$SubscriptionID = (Get-AzSubscription).Id
$ResourceGroupName = $KeyVault.ResourceGroupName
$KeyVaultName = $KeyVault.VaultName
$URI = "https://management.azure.com/subscriptions/$SubscriptionID/resourceGroups/$ResourceGroupName/providers/Microsoft.KeyVault/vaults/$KeyVaultName/providers/Microsoft.Authorization/permissions?api-version=2022-04-01"

$RequestParams = @{
    Method  = 'GET'
    Uri     = $URI
    Headers = @{
        'Authorization' = "Bearer $Token"
    }
}

(Invoke-RestMethod @RequestParams).value

This script queries the Azure Management REST API to retrieve the privileges that the ‘staging-vaadatalab’ application has on the ‘keyvaultvaadatalab1’ Key Vault.

List of privileges on the ‘keyvaultvaadatalab1’ Key Vault

In the context of Azure Key Vault permissions, permissions are generally defined in terms of actions on the resource and actions on the data in the resource.

Actions

Actions define the operations that the client is authorised to perform on a resource.

In our case, the action specified is Microsoft.KeyVault/vaults/read; this means that the user has the right to read the metadata of an Azure Key Vault. This generally includes operations such as retrieving information about the vault (name, location, tags, etc).

DataActions

DataActions are actions specific to the data in the key vault. They define the operations authorised on the secrets and keys stored in the key vault. In this example, 4 dataActions are defined:

  • Microsoft.KeyVault/vaults/keys/read: Allows the metadata of keys stored in the vault to be read.
  • Microsoft.KeyVault/vaults/keys/decrypt/action: Allows the keys stored in the vault to be decrypted.
  • Microsoft.KeyVault/vaults/secrets/readMetadata/action: Allows the metadata of secrets stored in the key vault to be read.
  • Microsoft.KeyVault/vaults/secrets/getSecret/action: Authorises the recovery of secret values stored in the key vault.

Retrieving the secrets

This will allow us to retrieve the value of all the secrets in the Key Vault and analyse what we can do with them.

But first, we need to retrieve another specific access_token to perform actions on the data in the Key Vault.

To do this, we again exploit code injection on the application to retrieve an access_token with the following command:

curl "<MSI_ENDPOINT>?resource=https://vault.azure.net&api-version=2017-09-01" -H secret:"IDENTITY_HEADER"

We can now list all the secrets in the Key Vault using the following PowerShell script:

# List all secrets in the keyvault
$access_token = "<access_token_management>"
$keyvault_access_token = "<access_token_keyvault>"
Connect-AzAccount -AccessToken $access_token -KeyVaultAccessToken $keyvault_access_token -AccountId 3329fea7-642e-4c09-b1ad-d8edbe140267

$KeyVault = Get-AzKeyVault
$SubscriptionID = (Get-AzSubscription).Id
$ResourceGroupName = $KeyVault.ResourceGroupName
$KeyVaultName = $KeyVault.VaultName

$secrets = Get-AzKeyVaultSecret -VaultName $keyVaultName

foreach ($secret in $secrets) {
    $secretName = $secret.Name
    $secretValue = (Get-AzKeyVaultSecret -VaultName $keyVaultName -Name $secretName -AsPlainText)
    Write-Output "$secretName : $secretValue"
} 

One of the secrets is called host-masterkey-master. This is very reminiscent of the ‘master key’ of a Function App.

Azure Functions is a serverless solution that allows less infrastructure to be managed and saves on costs. Instead of worrying about deploying and maintaining servers, Azure provides all the up-to-date resources needed to keep applications running.

Each Function App has a masterkey that enables administrative actions to be performed, such as reading the source code of the Function App, adding code, and so on.

We can therefore test this masterkey on the ‘vaadatalabprod’ function App discovered during the reconnaissance phase in order to access the source code of the various functions.

To do this, we can query the function App’s virtual storage space (VFS) via the endpoint https://<function-app>.azurewebsites.net/admin/vfs/home/site/wwwroot/.

The following PowerShell code is used to perform this action:

$URL = "https://vaadatalabprod.azurewebsites.net/admin/vfs/home/site/wwwroot/"

$Params = @{
"URI" = $URL
"Method" = "GET"
"Headers" = @{
"Content-Type" = "application/octet-stream"
"x-functions-key" = "<master-key>"

}

}

Invoke-RestMethod @Params -UseBasicParsing 
Files in the ‘vaadatalabprod’ Function App

The result is the list of functions, which means that the masterkey is indeed that of the ‘vaadatalabprod’ Function App.

Now it’s time to read the source code of the functions, looking for secrets for example.

At this stage, it is also possible to add a function that contains arbitrary code. This can be used to drop code to retrieve an access_token in order to compromise the main service of the ‘vaadatalabprod’ Function App; and to repeat the analysis of resources accessible by the Function App to potentially compromise other resources.

Let’s take a closer look at the ManageDuckOrdersProd function, which appears to be dedicated to production.

In fact, the __init__.py file in the ManageDuckOrdersProd function contains a secret for accessing the CosmosDB production database.

Azure offers relational database services. CosmosDB is a NoSQL database managed entirely by Azure.

The __init__.py file contains a string connection enabling access to the MongoDB vaadatalab1-server.mongo.cosmos.azure.com database.

Retrieving the connection string from the MongoDB database in the ManageDuckOrdersProd function

With this connection String, we can access all the production data contained in the CosmosDB.

The following simple Python script can be used to retrieve all the data:

from pymongo import MongoClient

connection_string = "<connection_string> »
db_name = "vaadatalab1-cosmosdb"
collection_name = "Production"
client = MongoClient(connection_string)

db = client[db_name]
collection = db[collection_name]
documents = collection.find()

for doc in documents:
    print(doc)

client.close()
Retrieving all data from the production database

It’s now time to look at the steps VaadataLab could have taken to avoid such a scenario.

The reconnaissance phase revealed that the staging environment was exposed on the Internet. And these environments should not be publicly accessible. VaadataLab could limit access to the staging environment by restricting IP addresses.

In addition, installing a WAF would make it more difficult to exploit vulnerabilities. However, the security of the application should not rely solely on the WAF.

Let’s now look at the Azure infrastructure. In our scenario, the staging environment had read access to all the secrets in the ‘keyvaultvaadatalab1’ Key Vault, including the masterkey for the production Function App.

The principle of least privilege must apply. The question to ask is: ‘Does my staging application really need access to the masterkey of the production Function App?’ The answer is probably no.

It is therefore essential to limit the staging application’s access to what is strictly necessary. Azure even recommends using one Key Vault per application, per environment and per region.

It is also possible to restrict access to Function Apps and Key Vault. It is unlikely that it will be necessary to expose a Key Vault on the Internet. Azure makes it possible to restrict access to Key Vault to specific IP addresses or to use virtual network service endpoints to restrict access to a defined virtual network.

Finally, it is not advisable to leave hard-coded secrets in the code of an application. We recommend storing the connection string in a Key Vault rather than leaving it in the Function App.

Perform an Azure Penetration Test with Vaadata, a Company Specialised in Offensive Security

It is important to assess the level of resistance of your Azure infrastructure to the attacks described in this article.

This assessment can be carried out using one of the audits we offer. Whether black-box, grey-box or white-box, we can identify all the vulnerabilities in your Azure infrastructure and help you fix them.