Home/ATT&CK Technique/Cloud Storage Object Discovery
ATT&CK Technique

Cloud Storage Object Discovery

T1619 · discovery

Adversaries may enumerate objects in cloud storage infrastructure. Adversaries may use this information during automated discovery to shape follow-on behaviors, including requesting all or specific objects from cloud storage. Similar to File and Directory Discovery on a local host, after identifying available storage services (i.e.

Cloud Infrastructure Discovery) adversaries may access the contents/objects stored in cloud infrastructure. Cloud service providers offer APIs allowing users to enumerate objects stored within cloud storage. Examples include ListObjectsV2 in AWS and List Blobs in Azure .

IaaS

Actors Using This

1

Atomic Tests

4
Executable Atomic Red Team test cases for exercising this technique in a lab. Copy a command, run it on the listed platform, confirm your detections fire.
shiaas:awsAWS S3 Enumeration
This test will enumerate all the S3 buckets in the user account and lists all the files in each bucket.
for bucket in "$(aws s3 ls | cut -d " " -f3)"; do aws s3api list-objects-v2 --bucket $bucket --output text; done
powershelliaas:azureAzure - Enumerate Storage Account Objects via Shared Key authorization using Azure CLI
This test enumerates all existing storage accounts and tries to fetch for each account the contained storage account objects. The access to storage objects is only possible if Shared Key authorization is enabled (e.g this is the case per default for storage objects creaded by Azure Function Apps). Requirements: - The test is intended to be executed in interactive mode (with -Interactive parameter) in order to complete the az login command when MFA is required. - The EntraID user must have the role "Storage Account Contributor", or a role with similar permissions. Output format: Csv file that contains the found storage account objects - Columns: ResourceGroup, StorageAccountName, FileShareName, ContainerName, BlobName, TableName, QueueName - The content of these columns is filled out depending on the object. Not-required columns are left empt. Example: For a blob object the ResourceGroup, StorageAccountName, ContainerName, BlobName are filled out, the other fields are left empty.
az login    # Login to Azure

# Get all storage accounts in the subscription
$storageAccounts = az storage account list --query "[].{name:name, resourceGroup:resourceGroup}" --output json | ConvertFrom-Json

$storageAccountObjects = @()
$downloadedFunctionFiles = @()

foreach ($account in $storageAccounts) {
    Write-Output "`nFound storage account $($account.name)"

    $storageAccountObjects += [PSCustomObject]@{
        ResourceGroup      = $account.resourceGroup
        StorageAccountName = $account.name
        FileShareName      = ""
        ContainerName      = ""
        BlobName           = ""
        TableName          = ""
        QueueName          = ""
    }

    $allowSharedKeyAccess = az storage account show --name $account.name --resource-group $account.resourceGroup --query "allowSharedKeyAccess"
    
    if ($allowSharedKeyAccess -eq "false") {    # $allowSharedKeyAccess could be true or null
        Write-Output "Shared key access is disabled for this storage account."
    } else {
        $connectionString = az storage account show-connection-string --name $account.name --resource-group $account.resourceGroup --query connectionString --output tsv
        
        $fileShares = az storage share list --connection-string $connectionString --query "[].name" --output json | ConvertFrom-Json
        foreach($fileShare in $fileShares) {
            Write-Output "Found file share: $($fileShare)"
            $storageAccountObjects += [PSCustomObject]@{
                ResourceGroup      = $account.resourceGroup
                StorageAccountName = $account.name
                FileShareName      = $fileShare
                ContainerName      = ""
                BlobName           = ""
                TableName          = ""
                QueueName          = ""
            }
        }

        $containers = az storage container list --connection-string $connectionString --query "[].name" --output json | ConvertFrom-Json
        foreach($container in $containers) {
            Write-Output "Found container: $($container)"
            $storageAccountObjects += [PSCustomObject]@{
                ResourceGroup      = $account.resourceGroup
                StorageAccountName = $account.name
                FileShareName      = ""
                ContainerName      = $container
                BlobName           = ""
                TableName          = ""
                QueueName          = ""
            }

            $blobs = az storage blob list --connection-string $connectionString --container-name $container --query "[].name" --output json | ConvertFrom-Json

            foreach($blob in $blobs) {
                Write-Output "Found blob: $($blob)"
                $storageAccountObjects += [PSCustomObject]@{
                    ResourceGroup      = $account.resourceGroup
                    StorageAccountName = $account.name
                    FileShareName      = ""
                    ContainerName      = $container
                    BlobName           = $blob
                    TableName          = ""
                    QueueName          = ""
                }
            }
        }
        
        $tables = az storage table list --connection-string $connectionString --query "[].name" --output json | ConvertFrom-Json
        foreach($table in $tables) {
            Write-Output "Found table: $($table)"
            $storageAccountObjects += [PSCustomObject]@{
                ResourceGroup      = $account.resourceGroup
                StorageAccountName = $account.name
                FileShareName      = ""
                ContainerName      = ""
                BlobName           = ""
                TableName          = $table
                QueueName          = ""
            }
        }
        
        $queues = az storage queue list --connection-string $connectionString --query "[].name" --output json | ConvertFrom-Json
        foreach($queue in $queues) {
            Write-Output "Found table: $($table)"
            $storageAccountObjects += [PSCustomObject]@{
                ResourceGroup      = $account.resourceGroup
                StorageAccountName = $account.name
                FileShareName      = ""
                ContainerName      = ""
                BlobName           = ""
                TableName          = ""
                QueueName          = $queue
            }
        }
    }
}

# Store file lists to csv file
$storageAccountObjects | Export-Csv -Path "#{output_file}" -NoTypeInformation
Write-Output "`nDownloaded storage account objects to #{output_file}"

# Print lists that have been stored as csv file
$storageAccountObjects | Format-Table -Property ResourceGroup, StorageAccountName, FileShareName, ContainerName, BlobName, TableName, QueueName -AutoSize -Wrap
powershelliaas:azureAzure - Scan for Anonymous Access to Azure Storage (Powershell)
Upon successful execution, this test will test for anonymous access to Azure storage containers by invoking a web request and outputting the results to a file. The corresponding response could then be interpreted to determine whether or not the resource/container exists, as well as other information. See https://ninocrudele.com/the-three-most-effective-and-dangerous-cyberattacks-to-azure-and-countermeasures-part-2-attack-the-azure-storage-service
try{$response = invoke-webrequest "https://#{base_name}.blob.core.windows.net/#{container_name}/#{blob_name}" -method "GET"}
catch [system.net.webexception]
{if($_.Exception.Response -ne $null)
{$Response = $_.Exception.Response.GetResponseStream()
$ReadResponse = New-Object System.IO.StreamReader($Response)
$ReadResponse.BaseStream.Position = 0
$responseBody = $ReadResponse.ReadToEnd()}
else {$responseBody = "The storage account could not be anonymously accessed."}}
"Response received for #{base_name}.blob.core.windows.net/#{container_name}/#{blob_name}: $responsebody" | out-file -filepath #{output_file} -append
powershelliaas:azureAzure - Enumerate Azure Blobs with MicroBurst
Upon successful execution, this test will utilize a wordlist to enumerate the public facing containers and blobs of a specified Azure storage account. See https://www.netspi.com/blog/technical/cloud-penetration-testing/anonymously-enumerating-azure-file-resources/ .
import-module "PathToAtomicsFolder\..\ExternalPayloads\Invoke-EnumerateAzureBlobs.ps1"
Invoke-EnumerateAzureBlobs -base #{base} -permutations "#{wordlist}" -outputfile "#{output_file}"

Mitigations

1
MITRE ATT&CK mitigations - vendor-agnostic guidance for reducing exposure to this technique.
M1018User Account Management

User Account Management involves implementing and enforcing policies for the lifecycle of user accounts, including creation, modification, and deactivation. Proper account management reduces the attack surface by limiting unauthorized access, managing account privileges, and ensuring accounts are used according to organizational policies.

Enforcing the Principle of Least Privilege
  • Implementation: Assign users only the minimum permissions required to perform their job functions. Regularly audit accounts to ensure no excess permissions are granted.
  • Use Case: Reduces the risk of privilege escalation by ensuring accounts cannot perform unauthorized actions. Implementing Strong Password Policies.
  • Implementation: Enforce password complexity requirements (e.g., length, character types). Require password expiration every 90 days and disallow password reuse.
  • Use Case: Prevents adversaries from gaining unauthorized access through password guessing or brute force attacks. Managing Dormant and Orphaned Accounts.
  • Implementation: Implement automated workflows to disable accounts after a set period of inactivity (e.g., 30 days). Remove orphaned accounts (e.g., accounts without an assigned owner) during regular account audits.
  • Use Case: Eliminates dormant accounts that could be exploited by attackers. Account Lockout Policies.
  • Implementation: Configure account lockout thresholds (e.g., lock accounts after five failed login attempts). Set lockout durations to a minimum of 15 minutes.
  • Use Case: Mitigates automated attack techniques that rely on repeated login attempts. Multi-Factor Authentication (MFA) for High-Risk Accounts.
  • Implementation: Require MFA for all administrative accounts and high-risk users. Use MFA mechanisms like hardware tokens, authenticator apps, or biometrics.
  • Use Case: Prevents unauthorized access, even if credentials are stolen. Restricting Interactive Logins.
  • Implementation: Restrict interactive logins for privileged accounts to specific secure systems or management consoles. Use group policies to enforce logon restrictions.
  • Use Case: Protects sensitive accounts from misuse or exploitation.
Tools for Implementation Built-in Tools
  • Microsoft Active Directory (AD): Centralized account management and RBAC enforcement.
  • Group Policy Object (GPO): Enforce password policies, logon restrictions, and account lockout policies.
Identity and Access Management (IAM) Tools
  • Okta: Centralized user provisioning, MFA, and SSO integration.
  • Microsoft Azure Active Directory: Provides advanced account lifecycle management, role-based access, and conditional access policies.
Privileged Account Management (PAM)
  • CyberArk, BeyondTrust, Thycotic: Manage and monitor privileged account usage, enforce session recording, and JIT access.

Detection Coverage

1/6 layers
Coverage across standard detection surfaces. Rows marked none have no rule of that type mapped. Some are real blind spots worth closing; others are simply not applicable to this technique (e.g. YARA matches malware files, not network behaviour).
Behavioral / log (Sigma) 1
Analytics (MITRE CAR) none
Runtime / container (Falco) none
File / malware (YARA) none
Network (Suricata/Snort) none
Vuln scan (Nuclei) none

Comply & Defend

Intelligence Graph · click any node to traverse
CVETechnique ActorTool Family
drag to reposition · click any node to traverse · button top-right enlarges
External lookups - second-class, for what we don’t hold ourselves
Vulnerabilities
CISA KEV catalog
CWE weaknesses
CAPEC attack patterns
Package vulnerabilities
Threat intelligence
Threat actors
Tools & malware
ATT&CK techniques
IOCs
Detection & defense
Sigma rules
YARA rules
Atomic Red Team tests
D3FEND countermeasures
Compliance
NIST 800-53
ISO 27001:2022
SOC 2 TSC
PCI-DSS v4.0
CIS Controls v8.1
About
All capabilities
Live statistics
Data sources
Privacy policy
Terms of service
threatengine.sh  ·  Open-source threat intelligence platform  ·  100+ authoritative sources  ·  Every fact traces to its origin