Attacking and Defending Azure Storage Blobs

──────────────────────────────────────────────────────────────────────────────────

As more organizations adopt cloud technologies, more attackers recognize the value of data stored in these environments. However, many organizations fail to realize just how important the security of their data is...until they find it on the dark web! This blog will present a scenario from start to finish of how not* to abuse your Azure storage blobs.

Introduction

Before we get into the meat and potatoes, we should probably establish what cloud storage actually is. To put it simply, much like the rest of the cloud, cloud storage is just someone else's computers that has the data you store at any given time. So when you purchase an Azure Storage Blob from Microsoft, they'd store that data on one, or a few of their servers depending on your region and availability tier you select.

Azure has two (well three if we are getting technical) types of storage you can purchase. Blob, and General Purchase (which contains Blob and a few other types: File, Queue, and Table). We are only going to care about Blob Storage for this blog, but they all function similarly enough on the front-end.

Blob Storage is, at its core, designed to store massive amounts of unstructured data. In traditional file systems, we are used to seeing documents, images, and executables - blob storage can include those, but is more intended for data that doesnt have a defined type such as archives, log files, banking information, health information, etc.

Below is an image of what blob storage looks like in the Azure Portal.

Azure Blob Storage

Anatomy of Blob Storage

To understand the absolute minimum needed for a theoretical attacker to target a storage blob, they'd only have to need to collect a storage account, a container, and blob name in order to access data.

Storage Account: basically a username. this is also the thing that has authorization to access blobs

Container: think of this as a folder that has the blobs

Blob: the actual data stored in the container

There are three types of blob data: Block, Append, and Page. Block is the one we care about and will be targetting and this simply stores text and binary data, much like we are accustomed to.

Azure Blob Storage Hierarchy
──────────────────────────────────────────────────────────────────────────────────

Attacking Storage Blobs

I believe the best defenders are good attackers, and good defenders make for better red teamers and pentesters, so we will be covering both sides in this post, starting with attack.

And as an attacker, there always has to be some sort of thing that motivates them to put in the effort. So, why would an attacker care about Azure Storage Blobs?

Attackers can abuse public-facing blobs as an easy target for data exfiltration, or gathering credentials or information that can be used to gain entry into a network, or piviot from within. More commonly, attackers can gain access to particularly, juicy, sensitive data as more of a late-stage objective, once they have already gained access to the internal network and have recovered credentials. This is when financially-motivated attackers are likely to ransom data, and even sell it on the dark web to the highest bidder. Some other threat actors even take over blob storage as a hosting domain for their evil infrastructure and malwares. Vigilantes with the right permissions and the wrong incentives can even delete all of the data stored in the blob.

Moreover, storage blobs are valuable targets that threat actors frequently target and exploit their way into.

Finding a Target

*Obvious Disclaimer Ensure you have proper authorization before doing any non-passive reconnaissance and other testing. Don't do illegal things!

Step #1 - Reconnissance

An attacker performing reconnissance to identify vulnerable target blobs needs to find three things: a storage account, a container, and a blob name.

We went over what those are in Anatomy of Blob Storage. Three things sound easy enough!

Accessing the Target

In file systems we are accustomed to, like the File Explorer in Windows, we open the application, click on the folder that stores our document, then open the file we want to see. If we have something like a NAS, we first, make sure to point the folder we open to the computer that is hosting that data. Accessing Azure Storage Blobs is very similar to that.

All we need is a URL that is unique to the blob we want to access, and plop it in a browser such as Chrome, Firefox, Safari, etc.

This endpoint is comprised of the three components we need to identify.

http://{storage-account}.[blob|file|table|queue].core.windows.net/{container}/{file}

So if our storage account name is "bonzibuddy", the container we want to access is "peedy-pictures", and the blob we want to target is "flexing.png", our URL would look like this:

http://bonzibuddy.blob.core.windows.net/peedy-pictures/flexing.png

We can also get a bit fancier and use the Azure Storage REST API, Azure PowerShell, Azure CLI, and any other client library that supports it.

The operations we use to access the blob using the REST API is mapped to the operations we are used to graphically -

 Get Container Properties
 List Containers (in a storage account) 
 List Blobs (in a container)
 Get Blob  (retrieve data)

Finding a Target

Much like finding any other public-facing web page on the internet, we can use some more traditional tactics such as Google Dorking and DNS Enumeration.

Google Dorking is a syntax that anyone can use to filter a search by specifying criteria for the results we want to see.

For example, if we wanted to find all the public-facing Azure Storage Blobs that has xlsx or csv files with the word "password" in them, we could use the following Google Dork:

site:*.blob.core.windows.net ext:xlsx | ext:csv password

With DNS enumeration, we can use a script such as DNScan to brute-force query Microsoft's public DNS records for common blobs to target.

python dnscan.py -d blob.core.windows.net -w subdomains.txt

There are also custom tools out there, such as MicroBurst that package a lot of this reconnissance work for automagic results.

Invoke-EnumerateAzureBlobs –Base

Blob Storage Permissions

The results we saw in our open reconnaissance were only available to us because they had either "Blob" or "Container" level permissions set.

Blob: public read access for blobs only. Blobs => anonymous read Container data => access via authorized request.

Container: public read access for containers and blobs. Container and blob data => anonymous read (excluding container permission settings/metadata)

Private: no public read access. Blobs and containers => access via authorized request. This means we'd need a shared key from a storage account, or a Shared Access Signature (SAS) URI generated to view the data.

TLDR; only containers with the Public read access will allow unauthorized requests. This would mean an attacker needs to know the full URL of the blob to access blob data with Blob level permissions configured.

Not-so-Stealthy Enumeration

Assuming we had identified a storage account named "bonzibuddy" in the previous step, we can move right along in finding the rest of the information.

Step #2 - Enumeration

Like any other webpage, there are attackers out there that like to throw scans at the wall that is the internet and hope something sticks. These attackers might have a bit of a tough time due to some anti-scanning measures Microsoft built in to Azure Storage.

Although, making a wordlist is easy - there really aren't any restrictions for what the URL can or cannot have beyond properly escaping some special characters and not exceeding a reasonable amount of characters.

An attacker can use a page enumeration tool such as gobuster to identify container names and blob names using a wordlist.

gobuster dir -u http://bonzibuddy.blob.core.windows.net -w wordlist.txt
gobuster dir -u bonzibuddy.blob.core.windows.net -w /usr/share/wordlists/dirb/big.txt -x xlsx,png

When an empty container is hit, the page would return a 400 error, and when a container with blob permissions is hit, it would return a 404 error, making identifying good targets harder.

As we know, enumerating this method is not stealthy, the web server will be flooded with requests.

Enumerating the Target

Let's imagine we have access to a tool like Azure CLI and want to blend in with the environment a bit more.

Using the Azure CLI, we can list storage accounts:

az storage account list

The key associated with a storage account:

az storage account keys list --account-name bonzibuddy

And then we can list the containers in the storage account:

az storage container list --account-name bonzibuddy --account-key {key}

And finally, list the blobs in the container:

az storage blob list --account-name bonzibuddy --account-key {key} --container-name peedy-pictures

Complete the Mission

Now that we identified the container name and blob to target, we can now complete our mission!

Using the Azure CLI, we can download the blob to our local machine:

az storage blob download --account-name bonzibuddy --account-key {key} --container-name peedy-pictures --name flexing.png --file flexing.png

Using a tool like Microburst, we could do the same thing:

Invoke-WebRequest –Uri https://storageaccount.blob.core.windows.net/peedy-pictures/flexing.png –OutFile flexing.png

If we had downloaded a bunch of bulk data, we can use a tool like DumpsterDiver to find some more juicy bits like keys and sensitive information.

DumpsterDiver.py -p [PATH_TO_FOLDER] --min-key 66 --max-key 66 --entropy 5.1
DumpsterDiver.py -p [PATH_TO_FOLDER] --min-pass 10 --max-pass 15 --pass-complex 8

There is also always good ole grep

And that's it! That is all an attacker needs to do to "attack" an Azure Storage Blob.

──────────────────────────────────────────────────────────────────────────────────

Defending Azure Storage Blobs

Now that we know how an attacker can target Azure Storage Blobs, we can now discuss how to defend against these attacks.

When investigating a potential compromise, we need to gather information that will help us understand the extent of the compromise and identify the source of the attack. This information can be used to determine the appropriate response to the attack and prevent future attacks.

We need to find the affected storage account (to cycle keys and SAS URIs), the blob data accessed/modified (for the extent of the compromise), and the container with the permissions issue (to fix the ACL). Then for attribution, we need to find the source IP of the activity and the time the activity occured to investigate correlated events.

In Azure we can leverage the Activity logs contained in the Monitor portal that are configured by default. The extent these go to document events around storage blobs is...limited.

For instance, in the attacks we just completed in our example, the only events that are logged by default is the "List Storage Account Keys" event.

Defending Azure Storage Blobs

If we pay close attention, we can identify the source, time, and effected storage account, however making a concrete assertion that the activity was bad is difficult with this information alone.

As we poke around the portal a bit more, we can stumble into the 'Failure Insights' page, which suprisingly gives us some solid logs to piviot off of. We can gather the full request URI, the authentication type (anonymous or if an account was used), operation performed against the blobs, as well as time and source.

Defending Azure Storage Blobs

Like the name implies, only failed events are logged, so this may require a stroke of luck. Likewise, logs roll quickly without some type of intervention, so it may be difficult to properly investigate later down the line.

Configuring Blob Logs

To save ourselves some grief, we can configure Blob Logs to capture more detailed information about the activity on our storage blobs. This can be done in the Azure Portal under the 'Storage Settings' tab.

Once we have the logs enabled, we can view them in the 'Blob Log' tab. This will give us a more detailed view of the activity on our storage blobs, including the source IP, the time of the activity, and the operation performed.

Once we have the logs enabled, we actually can view them in the blob itself from the "$log" container. This will give us a more detailed view of the activity on our storage blobs, including the source IP, the time of the activity, the operation performed, and even the User Agent used, regardless of result (success/fail).

Since this was a lot, to summarize, we need to configure, at a minimum these settings:

Defending Azure Storage Blobs

In order to get these types of logs:

Defending Azure Storage Blobs

Microsoft Defender for Storage/Cloud

Microsoft Defender for Storage and Cloud make it easier to detect and respond to threats in Azure Storage Blobs. While this costs a pretty penny and may be out of reach for small-size entities, the anomaly and rule-based detections are still worth mentioning for those that employ them.

Some detections include:

──────────────────────────────────────────────────────────────────────────────────

Conclusion

Azure Storage Blobs are a valuable target for attackers, and it is important to understand how they can be targeted and exploited. By understanding how attackers can target them, organizations can better defend against these attacks. By following the defense concepts outlined in this blog, organizations can better protect their Azure Storage Blobs from attackers.

Make sure to turn on those logs and alerting, and avoid anonymous permissions where possible. Once it's too late to configure this, 'List Storage Account Key' events and Failure Insights may be of use in an investigation.