Exploiting and defending anonymous access in Azure
Many cloud-related security breaches start with a compromised user identity. Once an attacker gets a foot in the door using the compromised credential, they can gather intelligence to move further in the attack chain or look for opportunities to escalate privileges. However, in not so rare cases, reserchers or attackers have been able to exploit service misconfigurations to gain initial access without having to compromise an identity to begin with.
The Azure platform has over 190 services the last time I counted (this depends really on what you count as a service E.g. do you count blob as a separate service or just the storage account?). Most of these services require some form of authentication for access — a method for the caller to prove their identity with a verifiable token. This can either be identity-based using Azure AD or Active Directory as in the case of Azue Files or key-based using a long lived access key or short-lived access token.
However, there are a few exceptions that allows the configuration of unauthenticated and unauthorized access. The most common ones that I’ve seen are the Azure Blob Container and the Azure Container registry!
Azure Blob Storage Container
The Azure Blob Storage Container is the equivalent of the S3 bucket in AWS. Cloud engineers and administrators have the option to configure anonymous read access on a container level (which allows for object listing) or on an object level.
This is to make it easier to support use cases like static web hosting or content hosting for public sites. The downside is that sensitive information is sometimes placed in those storage containers! You can see examples here, here and here.
Using service discovery, guessing and DNS bruteforce techniques, containers and objects can be located publicly and exploited for intel gathering or credential hunting as part of an attack chain.
If the anonymous access level is configured at the container level, there are two main unknowns that can be discovered, guessed or brute-forced — the account name and the container name. If the anonymous access level is configured at the object level, there are three main unknowns that can be discovered, guessed or brute-forced — the account name, the container name and the object name.
http://
[ACCOUNT_NAME]
.blob.core.windows.net/[CONTAINER_NAME]
/[OBJECT_NAME]
The Invoke-EnumerateAzureSubDomains
and Invoke-EnumerateAzureBlobs
functions of MicroBurst can be used for this. There is a hands-on exercise that coveres this exact scenario in this new book if you’ll like to see this in action — https://amzn.to/2Vt0Jjx (co-authored with Karl Fosaeen).
Azure Container Registry
Another Azure service that allows the configuration of unauthenticated access is the container registry. The purpose is to allow for unauthenticated image pull from the registry. This configuration can only be done in the command line using Azure CLI
With ACR — the name of the registry and the name of the image is what is needed to attempt an anonymous pull. These two unknowns could be guessed or bruteforced. The image tag is not required as if none is specified, the image with the tag called “latest” will be pulled by default.
docker pull
[ACCOUNT_NAME]
.azurecr.io/[IMAGE_NAME]
It is not uncommon to find further credentials in container images that can be used to further an attack chain.
In my experience, the container registry anonymous pull scenario usually happens when cloud engineers enable this option either to troubleshoot an issue with image pull OR to workaround a limitation but then they forgot to set it back to false.
Protecting Anonymous Access in Azure
So how is this protected?
1. Understand the supported access options of an Azure service before adoption! These are the two that I’ve encountered in my own work but there could be other Azure services that can also be configured for anonymous access!
2. Audit your environment for resources with anonymous access enabled. To identify anonymous blob containers and objects, you can use BlobHunter — a free tool created by CyberArk to perform authenticated audits for this use case. Many cloud security posture management platforms like Prisma Cloud, Security Center would also do this on a more wider and continuous basis.
2. Disable the option to configure “anonymous access” where possible. Thankfully, both services mentioned in this blog allows for this. This can either be done on the resource level or centrally using Azure policy.
Here is a screenshot to disable public or anonymous access for blob storage containers and objects (Azure Portal → Storage Account → Configuration → Blob public access)
And here is a screenshot of the Azure CLI command to disable anonymous pull for a container registry
In many cases, we can also disable centrally using Azure Policy. There is a built-in policy for blob storage that is currently in preview (see screenshot below). I don’t like the use of the term “public access” here as public access is still allowed even if you disable it — only that all requests needs to be authenticated.
There is no built-in policy to assess anonymous container registries but one can be constructed to assess the value of the anonymousPullEnabled
property. Here’s a sample assessment using Prisma Cloud’s RQL.
config from cloud.resource where cloud.type = ‘azure’ AND api.name = ‘azure-container-registry’ AND json.rule = anonymousPullEnabled equals true
4. Audit resource logs for anonymous access usage. As the saying goes — trust but verify. SecOps teams can also monitor for anonymous access usage in event logs to uncover blind spots that may have been missed when organization standards were implemented.
5. Use private endpoints for PaaS services that supports them. This reduces at least some risk by adding an extra layer of defense with network isolation. Blob containers and ACR supports this.