AWS CodeBuild - Untrusted PR Webhook Bypass (CodeBreach-style)

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Dieser Angriffsvektor tritt auf, wenn ein öffentlich zugänglicher PR-Workflow mit einem privilegierten CodeBuild-Projekt verbunden ist, das schwache Webhook-Kontrollen hat.

Wenn ein externer Angreifer CodeBuild dazu bringen kann, seine Pull Request auszuführen, kann er in der Regel eine beliebige Codeausführung im Build (Build-Skripte, Dependency-Hooks, Testskripte usw.) erreichen und anschließend auf Geheimnisse, IAM-Anmeldeinformationen oder Source-Provider-Anmeldeinformationen pivotieren.

Warum das gefährlich ist

CodeBuild-Webhooks werden für Nicht-EVENT-Filter mit Regex-Pattern ausgewertet. Im ACTOR_ACCOUNT_ID-Filter bedeutet das, dass ein schwaches Pattern mehr Benutzer matchen kann als beabsichtigt. Wenn unvertrauenswürdige PRs in einem Projekt gebaut werden, das privilegierte AWS-Rollenberechtigungen oder GitHub-Zugangsdaten besitzt, kann dies zu einer vollständigen Supply-Chain-Kompromittierung führen.

Wiz zeigte eine praktische Angriffskette, bei der:

  1. Eine Webhook-Actor-Allowlist einen unverankerten Regex verwendete.
  2. Ein Angreifer eine GitHub-ID registrierte, die als Superstring einer vertrauenswürdigen ID matchte.
  3. Eine bösartige PR CodeBuild auslöste.
  4. Die Ausführung von Build-Code genutzt wurde, um Speicher auszudumpen und Source-Provider-Anmeldeinformationen/Token wiederherzustellen.

Fehlkonfigurationen, die externe PR-Codeausführung ermöglichen

Im Folgenden sind hochriskante Fehler und wie Angreifer jeden einzelnen ausnutzen:

  1. EVENT-Filter erlauben nicht vertrauenswürdige Trigger
  • Häufig riskante Events: PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED, PULL_REQUEST_REOPENED.
  • Andere Events, die gefährlich werden können, wenn sie mit privilegierten Builds verknüpft sind: PUSH, PULL_REQUEST_CLOSED, PULL_REQUEST_MERGED, RELEASED, PRERELEASED, WORKFLOW_JOB_QUEUED.
  • Schlecht: EVENT="PUSH, PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED" in einem privilegierten Projekt.
  • Besser: PR-Kommentar-Approval verwenden und Trigger-Events für privilegierte Projekte minimieren.
  • Missbrauch: Angreifer öffnet/aktualisiert eine PR oder pusht in einen von ihnen kontrollierten Branch, und ihr Code wird in CodeBuild ausgeführt.
  1. ACTOR_ACCOUNT_ID-Regex ist schwach
  • Schlecht: unverankerte Muster wie 123456|7890123.
  • Besser: exakte Anchoring-Übereinstimmung ^(123456|7890123)$.
  • Missbrauch: Regex-Overmatch erlaubt nicht autorisierten GitHub-IDs, Allowlists zu passieren.
  1. Andere Regex-Filter sind schwach oder fehlen
  • HEAD_REF
  • Schlecht: refs/heads/.*
  • Besser: ^refs/heads/main$ (oder eine explizite Liste vertrauenswürdiger Branches)
  • BASE_REF
  • Schlecht: .*
  • Besser: ^refs/heads/main$
  • FILE_PATH
  • Schlecht: keine Pfad-Einschränkungen
  • Besser: riskante Dateien ausschließen wie ^buildspec\\.yml$, ^\\.github/workflows/.*, (^|/)package(-lock)?\\.json$
  • COMMIT_MESSAGE
  • Schlecht: Trust-Marker mit losem Match wie trusted
  • Besser: Verwenden Sie die Commit-Nachricht nicht als Vertrauensgrenze für die Ausführung von PRs
  • REPOSITORY_NAME / ORGANIZATION_NAME
  • Schlecht: .* in org/global Webhooks
  • Besser: nur exakte Repo/Org-Übereinstimmungen
  • WORKFLOW_NAME
  • Schlecht: .*
  • Besser: nur exakte Workflow-Namen (oder dieses Feld nicht als Vertrauenskontrolle verwenden)
  • Missbrauch: Angreifer konstruiert Ref/Path/Message/Repo-Kontext so, dass permissive Regexes erfüllt werden und Builds ausgelöst werden.
  1. excludeMatchedPattern wird falsch verwendet
  • Das Setzen dieses Flags kann bei falscher Nutzung die beabsichtigte Logik invertieren.
  • Schlecht: FILE_PATH '^buildspec\\.yml$' mit excludeMatchedPattern=false, obwohl beabsichtigt war, buildspec-Änderungen zu blockieren.
  • Besser: dasselbe Pattern mit excludeMatchedPattern=true, um Builds zu verweigern, die buildspec.yml betreffen.
  • Missbrauch: Verteidiger denken, sie verweigern riskante Events/Pfade/Actor, aber sie erlauben sie tatsächlich.
  1. Mehrere filterGroups erzeugen unbeabsichtigte Bypässe
  • CodeBuild wertet Gruppen als OR aus (eine bestehende Gruppe reicht aus).
  • Schlecht: eine strenge Gruppe + eine permissive Fallback-Gruppe (z. B. nur EVENT=PULL_REQUEST_UPDATED).
  • Besser: entferne Fallback-Gruppen, die keine Actor-/Ref-/Path-Einschränkungen durchsetzen.
  • Missbrauch: Der Angreifer muss nur die schwächste Gruppe erfüllen.
  1. Kommentar-Approval-Gate deaktiviert oder zu permissiv
  • pullRequestBuildPolicy.requiresCommentApproval=DISABLED ist am unsichersten.
  • Zu breit gefasste Approver-Rollen reduzieren die Kontrolle.
  • Schlecht: requiresCommentApproval=DISABLED.
  • Besser: ALL_PULL_REQUESTS oder FORK_PULL_REQUESTS mit minimalen Approver-Rollen.
  • Missbrauch: Fork/Drive-by-PRs laufen automatisch ohne Approval eines vertrauenswürdigen Maintainers.
  1. Keine restriktive Branch-/Pfad-Strategie für PR-Builds
  • Fehlende Defense-in-Depth mit HEAD_REF + BASE_REF + FILE_PATH.
  • Schlecht: nur EVENT + ACTOR_ACCOUNT_ID, keine Ref/Path-Kontrollen.
  • Besser: exakte ACTOR_ACCOUNT_ID + BASE_REF + HEAD_REF + FILE_PATH Einschränkungen kombinieren.
  • Missbrauch: Angreifer verändert Build-Inputs (buildspec/CI/Dependencies) und erlangt beliebige Befehlsausführung.
  1. Öffentliche Sichtbarkeit + Offenlegung der Status-URL
  • Öffentliche Build-/Check-URLs verbessern die Recon-Fähigkeit des Angreifers und erleichtern iteratives Testen.
  • Schlecht: projectVisibility=PUBLIC_READ mit sensiblen Logs/Configs in öffentlichen Builds.
  • Besser: Projekte privat halten, sofern kein starker Business-Need besteht, und Logs/Artefakte bereinigen.
  • Missbrauch: Angreifer entdeckt Projektmuster/-verhalten und verfeinert Payloads und Bypass-Versuche.

Token leakage from memory

Wiz’ Write-up erklärt, dass Source-Provider-Anmeldeinformationen im Build-Runtime-Kontext vorhanden sind und nach einer Build-Kompromittierung gestohlen werden können (zum Beispiel durch Memory-Dumping), was bei breiten Berechtigungen eine Übernahme des Repositories ermöglicht.

AWS führte nach der Offenlegung Härtungsmaßnahmen ein, aber die Kernlektion bleibt: Führe niemals unvertrauenswürdigen PR-Code in privilegierten Build-Kontexten aus und gehe davon aus, dass vom Angreifer kontrollierter Build-Code versuchen wird, Anmeldeinformationen zu stehlen.

Für zusätzliche Techniken zum Diebstahl von Anmeldeinformationen in CodeBuild siehe auch:

AWS Codebuild - Token Leakage

Finding CodeBuild URLs in GitHub PRs

Wenn CodeBuild den Commit-Status an GitHub zurückmeldet, erscheint die CodeBuild-Build-URL normalerweise in:

  1. PR page -> Checks tab (oder die Statuszeile in Conversation/Commits).
  2. Commit page -> Status/Checks-Bereich -> Details-Link.
  3. PR commits list -> klicke auf den Check-Kontext, der an einen Commit angehängt ist.

Bei öffentlichen Projekten kann dieser Link Build-Metadaten/-Konfigurationen für nicht authentifizierte Benutzer offenlegen.

Skript: CodeBuild-URLs in einer PR erkennen und testen, ob sie öffentlich aussehen ```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”

Getestet mit:
```bash
bash /tmp/check_pr_codebuild_urls.sh carlospolop codebuild-codebreach-ctf-lab 1

Schnelle Audit-Checkliste

# 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

Prüfe jedes Projekt auf:

  • webhook.filterGroups die PR-Ereignisse enthalten.
  • ACTOR_ACCOUNT_ID-Muster, die nicht mit ^...$ verankert sind.
  • pullRequestBuildPolicy.requiresCommentApproval gleich DISABLED.
  • Fehlende Branch-/Pfad-Einschränkungen.
  • serviceRole mit hohen Rechten.
  • Riskanter Umfang und Wiederverwendung von source credentials.

Härtungsempfehlungen

  1. Erfordern Sie Kommentarfreigabe für PR-Builds (ALL_PULL_REQUESTS oder FORK_PULL_REQUESTS).
  2. Wenn actor allowlists verwendet werden, verankern Sie die Regexes und halten Sie sie exakt.
  3. Fügen Sie FILE_PATH-Einschränkungen hinzu, um nicht vertrauenswürdige Änderungen an buildspec.yml und CI-Skripten zu verhindern.
  4. Trennen Sie vertrauenswürdige Release-Builds von nicht vertrauenswürdigen PR-Builds in unterschiedliche Projekte/Rollen.
  5. Verwenden Sie fein granulare, least-privileged source-provider-Tokens (vorzugsweise dedizierte Identitäten mit geringen Rechten).
  6. Überprüfen Sie kontinuierlich Webhook-Filter und die Nutzung von source credentials.

Referenzen

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks