AWS CodeBuild - Contournement de webhook PR non fiable (CodeBreach-style)

Tip

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks

Ce vecteur d’attaque apparaĂźt lorsqu’un workflow PR public est connectĂ© Ă  un projet CodeBuild privilĂ©giĂ© avec des contrĂŽles de webhook faibles.

Si un attaquant externe peut faire exĂ©cuter sa pull request par CodeBuild, il peut gĂ©nĂ©ralement obtenir une exĂ©cution de code arbitraire Ă  l’intĂ©rieur du build (scripts de build, hooks de dĂ©pendances, scripts de test, etc.), puis pivoter vers des secrets, des credentials IAM, ou des credentials du fournisseur de source.

Pourquoi c’est dangereux

Les filtres de webhook CodeBuild sont Ă©valuĂ©s avec des patterns regex (pour les filtres non EVENT). Dans le filtre ACTOR_ACCOUNT_ID, cela signifie qu’un pattern faible peut correspondre Ă  plus d’utilisateurs que prĂ©vu. Si des PR non fiables sont bĂąties dans un projet qui dispose de permissions de rĂŽle AWS privilĂ©giĂ©es ou d’identifiants GitHub, cela peut devenir une compromission complĂšte de la chaĂźne d’approvisionnement.

Wiz a montrĂ© une chaĂźne pratique oĂč :

  1. Une allowlist d’acteurs du webhook utilisait une regex non ancrĂ©e.
  2. Un attaquant a enregistrĂ© un ID GitHub qui correspondait comme un superstring d’un ID de confiance.
  3. Une PR malveillante a déclenché CodeBuild.
  4. L’exĂ©cution du code du build a Ă©tĂ© utilisĂ©e pour dumper la mĂ©moire et rĂ©cupĂ©rer des credentials/tokens du fournisseur de source.

Mauvaises configurations permettant l’exĂ©cution de code de PR externes

Les erreurs à haut risque suivantes et la façon dont les attaquants les abusent :

  1. EVENT filters allow untrusted triggers
  • ÉvĂ©nements risquĂ©s courants : PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED, PULL_REQUEST_REOPENED.
  • Autres Ă©vĂ©nements pouvant devenir dangereux si liĂ©s Ă  des builds privilĂ©giĂ©s : PUSH, PULL_REQUEST_CLOSED, PULL_REQUEST_MERGED, RELEASED, PRERELEASED, WORKFLOW_JOB_QUEUED.
  • Bad: EVENT="PUSH, PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED" dans un projet privilĂ©giĂ©.
  • Better: utiliser une approbation par commentaire pour les PR et minimiser les Ă©vĂ©nements dĂ©clencheurs pour les projets privilĂ©giĂ©s.
  • Abuse: l’attaquant ouvre/met Ă  jour une PR ou pousse sur une branche qu’il contrĂŽle, et son code s’exĂ©cute dans CodeBuild.
  1. ACTOR_ACCOUNT_ID regex is weak
  • Bad: patterns non ancrĂ©s comme 123456|7890123.
  • Better: ancrage exact ^(123456|7890123)$.
  • Abuse: un over-match de la regex permet Ă  des IDs GitHub non autorisĂ©s de passer les allowlists.
  1. Other regex filters are weak or missing
  • HEAD_REF
  • Bad: refs/heads/.*
  • Better: ^refs/heads/main$ (ou une liste explicite de branches de confiance)
  • BASE_REF
  • Bad: .*
  • Better: ^refs/heads/main$
  • FILE_PATH
  • Bad: pas de restrictions de chemin
  • Better: exclure les fichiers Ă  risque comme ^buildspec\\.yml$, ^\\.github/workflows/.*, (^|/)package(-lock)?\\.json$
  • COMMIT_MESSAGE
  • Bad: marqueur de confiance avec un match lĂąche comme trusted
  • Better: ne pas utiliser le message de commit comme frontiĂšre de confiance pour l’exĂ©cution des PR
  • REPOSITORY_NAME / ORGANIZATION_NAME
  • Bad: .* dans les webhooks org/globaux
  • Better: correspondances exactes repo/org uniquement
  • WORKFLOW_NAME
  • Bad: .*
  • Better: correspondances exactes du nom du workflow uniquement (ou Ă©viter cela comme contrĂŽle de confiance)
  • Abuse: l’attaquant construit un ref/chemin/message/contexte de repo pour satisfaire une regex permissive et dĂ©clencher des builds.
  1. excludeMatchedPattern is misused
  • DĂ©finir ce flag incorrectement peut inverser la logique voulue.
  • Bad: FILE_PATH '^buildspec\\.yml$' avec excludeMatchedPattern=false alors que l’intention Ă©tait de bloquer les edits de buildspec.
  • Better: mĂȘme pattern avec excludeMatchedPattern=true pour refuser les builds touchant buildspec.yml.
  • Abuse: les dĂ©fenseurs pensent qu’ils refusent des Ă©vĂ©nements/chemins/acteurs risquĂ©s, mais en rĂ©alitĂ© ils les autorisent.
  1. Multiple filterGroups create accidental bypasses
  • CodeBuild Ă©value les groupes comme un OR (un groupe passant suffit).
  • Bad: un groupe strict + un groupe fallback permissif (par ex., seulement EVENT=PULL_REQUEST_UPDATED).
  • Better: supprimer les groupes fallback qui n’appliquent pas de contraintes actor/ref/path.
  • Abuse: l’attaquant n’a besoin que de satisfaire le groupe le plus faible.
  1. Comment approval gate disabled or too permissive
  • pullRequestBuildPolicy.requiresCommentApproval=DISABLED est le moins sĂ»r.
  • Des rĂŽles d’approbateur trop larges rĂ©duisent le contrĂŽle.
  • Bad: requiresCommentApproval=DISABLED.
  • Better: ALL_PULL_REQUESTS ou FORK_PULL_REQUESTS avec des rĂŽles d’approbateurs minimaux.
  • Abuse: les PRs fork/drive-by s’exĂ©cutent automatiquement sans approbation d’un mainteneur de confiance.
  1. No restrictive branch/path strategy for PR builds
  • Absence de dĂ©fense en profondeur avec HEAD_REF + BASE_REF + FILE_PATH.
  • Bad: seulement EVENT + ACTOR_ACCOUNT_ID, pas de contrĂŽles ref/path.
  • Better: combiner des restrictions exactes ACTOR_ACCOUNT_ID + BASE_REF + HEAD_REF + FILE_PATH.
  • Abuse: l’attaquant modifie les entrĂ©es du build (buildspec/CI/dĂ©pendances) et obtient une exĂ©cution de commande arbitraire.
  1. Public visibility + status URL exposure
  • Les URLs publiques des builds/checks facilitent la reconnaissance et les tests itĂ©ratifs de l’attaquant.
  • Bad: projectVisibility=PUBLIC_READ avec des logs/config sensibles dans des builds publics.
  • Better: garder les projets privĂ©s sauf besoin business fort, et assainir logs/artifacts.
  • Abuse: l’attaquant dĂ©couvre des patterns/comportements du projet, puis affine les payloads et les tentatives de contournement.

Token leakage from memory

Le write-up de Wiz explique que les credentials du fournisseur de source sont prĂ©sents dans le contexte d’exĂ©cution du build et peuvent ĂȘtre volĂ©s aprĂšs compromission du build (par exemple via un dump mĂ©moire), permettant la prise de contrĂŽle du repository si les scopes sont larges.

AWS a introduit des durcissements aprÚs la divulgation, mais la leçon principale reste : ne jamais exécuter du code de PR non fiable dans des contextes de build privilégiés et supposez que le code de build contrÎlé par un attaquant tentera de voler des credentials.

Pour des techniques supplémentaires de vol de credentials dans CodeBuild, voir aussi :

AWS Codebuild - Token Leakage

Finding CodeBuild URLs in GitHub PRs

Si CodeBuild rapporte le statut sur GitHub, l’URL du build CodeBuild apparaĂźt gĂ©nĂ©ralement dans :

  1. PR page -> Checks tab (ou la ligne de statut dans Conversation/Commits).
  2. Commit page -> section status/checks -> lien Details.
  3. PR commits list -> cliquer sur le contexte de check attaché à un commit.

Pour les projets publics, ce lien peut exposer des métadonnées/configuration du build à des utilisateurs non authentifiés.

Script : détecter les CodeBuild URLs dans une PR et tester si elles semblent publiques ```bash #!/usr/bin/env bash set -euo pipefail

Usage:

./check_pr_codebuild_urls.sh <pr_number>

Requirements: gh, jq, curl

OWNER=“${1:?owner}” REPO=“${2:?repo}” PR=“${3:?pr_number}”

for bin in gh jq curl timeout; do command -v “$bin” >/dev/null || { echo “[!] Missing dependency: $bin” >&2; exit 1; } done

tmp_commits=“$(mktemp)” tmp_urls=“$(mktemp)” trap ‘rm -f “$tmp_commits” “$tmp_urls”’ EXIT

gh_api() { timeout 20s gh api “$@” 2>/dev/null || true }

Get all commit SHAs in the PR (bounded call to avoid hangs)

gh_api “repos/${OWNER}/${REPO}/pulls/${PR}/commits” –paginate –jq ‘.[].sha’ > “$tmp_commits” if [ ! -s “$tmp_commits” ]; then echo “[!] No commits found (or API call timed out/failed).” >&2 exit 1 fi

echo “[*] PR commits:” cat “$tmp_commits” echo

echo “[*] Searching commit statuses/check-runs for CodeBuild URLs
”

while IFS= read -r sha; do [ -z “$sha” ] && continue

Classic commit statuses (target_url)

gh_api “repos/${OWNER}/${REPO}/commits/${sha}/status”
–jq ‘.statuses[]? | .target_url // empty’ 2>/dev/null || true

GitHub Checks API (details_url)

gh_api “repos/${OWNER}/${REPO}/commits/${sha}/check-runs”
–jq ‘.check_runs[]? | .details_url // empty’ 2>/dev/null || true done < “$tmp_commits” | sort -u > “$tmp_urls”

grep -Ei ‘codebuild|codebuild.aws.amazon.com|console.aws.amazon.com/.*/codebuild’ “$tmp_urls” || true

echo echo “[*] Public-access heuristic:” echo “ - If URL redirects to signin.aws.amazon.com -> likely not public“ echo “ - If URL is directly reachable (HTTP 200) without auth redirect -> potentially public“ echo

cb_urls=“$(grep -Ei ‘codebuild|codebuild.aws.amazon.com|console.aws.amazon.com/./codebuild’ “$tmp_urls” || true)“ if [ -z “$cb_urls” ]; then echo “[] No CodeBuild URLs found in PR statuses/check-runs.” exit 0 fi

while IFS= read -r url; do [ -z “$url” ] && continue final_url=“$(timeout 20s curl -4 -sS -L –connect-timeout 5 –max-time 20 -o /dev/null -w ‘%{url_effective}’ “$url” || true)“ code=“$(timeout 20s curl -4 -sS -L –connect-timeout 5 –max-time 20 -o /dev/null -w ‘%{http_code}’ “$url” || true)“

if echo “$final_url” | grep -qi ‘signin.aws.amazon.com’; then verdict=“NOT_PUBLIC_OR_AUTH_REQUIRED” elif [ “$code” = “200” ]; then verdict=“POTENTIALLY_PUBLIC” else verdict=“UNKNOWN_CHECK_MANUALLY” fi

printf ‘%s\t%s\t%s\n’ “$verdict” “$code” “$url” done <<< “$cb_urls”

Testé avec :
```bash
bash /tmp/check_pr_codebuild_urls.sh carlospolop codebuild-codebreach-ctf-lab 1

Liste de vĂ©rification rapide pour l’audit

# Enumerate projects
aws codebuild list-projects

# Inspect source/webhook configuration
aws codebuild batch-get-projects --names <project-name>

# Inspect global source credentials configured in account
aws codebuild list-source-credentials

Examinez chaque projet pour :

  • webhook.filterGroups contenant des Ă©vĂ©nements PR.
  • des patterns ACTOR_ACCOUNT_ID qui ne sont pas ancrĂ©s avec ^...$.
  • pullRequestBuildPolicy.requiresCommentApproval Ă©gal Ă  DISABLED.
  • absence de restrictions de branche/chemin.
  • serviceRole Ă  privilĂšges Ă©levĂ©s.
  • portĂ©e et rĂ©utilisation risquĂ©es des identifiants source.

Conseils de durcissement

  1. Exiger l’approbation par commentaire pour les builds PR (ALL_PULL_REQUESTS ou FORK_PULL_REQUESTS).
  2. Si vous utilisez des allowlists d’acteurs, ancrez les regex et gardez-les exactes.
  3. Ajoutez des restrictions FILE_PATH pour éviter des modifications non fiables de buildspec.yml et des scripts CI.
  4. Séparez les builds de release de confiance des builds PR non fiables en projets/rÎles différents.
  5. Utilisez des tokens de fournisseur source à granularité fine et au moindre privilÚge (préférez des identités dédiées à faibles privilÚges).
  6. Auditez en continu les filtres webhook et l’utilisation des identifiants source.

References

Tip

Apprenez & pratiquez AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Apprenez & pratiquez GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Apprenez & pratiquez Az Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Soutenez HackTricks