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

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks

当一个面向公众的 PR 工作流 连接到具有弱 webhook 控制的 特权 CodeBuild 项目 时,会出现这种攻击向量。

如果外部攻击者能让 CodeBuild 执行他们的 pull request,通常可以在构建过程中获得 任意代码执行(构建脚本、依赖钩子、测试脚本等),然后横向攻击以获取 secrets、IAM 凭证或源提供商凭证。

Why this is dangerous

CodeBuild 的 webhook 过滤器(对于非 EVENT 过滤器)使用 regex 模式进行评估。在 ACTOR_ACCOUNT_ID 过滤器中,这意味着弱模式可能匹配比预期更多的用户。 如果在具有特权 AWS 角色权限或 GitHub 凭证的项目中构建不受信任的 PR,这可能演变为完整的供应链妥协。

Wiz 展示了一个实际的链条,其中:

  1. 一个 webhook actor allowlist 使用了 未加锚点的 regex
  2. 攻击者注册了一个 GitHub ID,作为受信任 ID 的 superstring 被匹配。
  3. 一个恶意 PR 触发了 CodeBuild。
  4. 构建中的代码执行被用来转储内存并恢复源提供商凭证/令牌。

Misconfigurations that allow external PR code execution

下面是高风险的错误以及攻击者如何滥用每一种:

  1. EVENT filters allow untrusted triggers
  • 常见的高风险事件:PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED, PULL_REQUEST_REOPENED.
  • 其他如果与特权构建关联也可能变得危险的事件:PUSH, PULL_REQUEST_CLOSED, PULL_REQUEST_MERGED, RELEASED, PRERELEASED, WORKFLOW_JOB_QUEUED.
  • 不良示例:在特权项目中使用 EVENT="PUSH, PULL_REQUEST_CREATED, PULL_REQUEST_UPDATED"
  • 更好:对特权项目使用 PR 评论审批并尽量减少触发事件。
  • 滥用:攻击者打开/更新 PR 或向其控制的分支 push,他们的代码在 CodeBuild 中执行。
  1. ACTOR_ACCOUNT_ID regex is weak
  • 不良示例:像 123456|7890123 这样的未锚定模式。
  • 更好:使用精确匹配锚定 ^(123456|7890123)$
  • 滥用:regex 过度匹配允许未授权的 GitHub ID 通过允许列表。
  1. Other regex filters are weak or missing
  • HEAD_REF
    • 不良示例:refs/heads/.*
    • 更好:^refs/heads/main$(或显式的受信任列表)
  • BASE_REF
    • 不良示例:.*
    • 更好:^refs/heads/main$
  • FILE_PATH
    • 不良示例:没有路径限制
    • 更好:排除高风险文件,例如 ^buildspec\\.yml$, ^\\.github/workflows/.*, (^|/)package(-lock)?\\.json$
  • COMMIT_MESSAGE
    • 不良示例:像 trusted 这样宽松匹配的信任标记
    • 更好:不要将提交信息用作 PR 执行的信任边界
  • REPOSITORY_NAME / ORGANIZATION_NAME
    • 不良示例:在 org/全局 webhook 中使用 .*
    • 更好:仅精确匹配仓库/组织
  • WORKFLOW_NAME
    • 不良示例:.*
    • 更好:仅精确的 workflow 名称匹配(或避免将其作为信任控制)
  • 滥用:攻击者构造 ref/路径/提交信息/仓库上下文以满足宽松的 regex 并触发构建。
  1. excludeMatchedPattern is misused
  • 错误设置此标志可能会将意图逻辑反转。
  • 不良示例:使用 FILE_PATH '^buildspec\\.yml$' 并将 excludeMatchedPattern=false,而本意是阻止对 buildspec 的更改。
  • 更好:对同一模式使用 excludeMatchedPattern=true 来拒绝触及 buildspec.yml 的构建。
  • 滥用:防御者以为他们阻止了高风险事件/路径/actor,实际上却允许了。
  1. Multiple filterGroups create accidental bypasses
  • CodeBuild 将组作为 OR 进行评估(通过任一组即可)。
  • 不良示例:一个严格组 + 一个宽松的回退组(例如只有 EVENT=PULL_REQUEST_UPDATED)。
  • 更好:移除不强制 actor/ref/path 约束的回退组。
  • 滥用:攻击者只需满足最弱的组。
  1. Comment approval gate disabled or too permissive
  • pullRequestBuildPolicy.requiresCommentApproval=DISABLED 是最不安全的。
  • 过于宽泛的批准者角色会降低控制力度。
  • 不良示例:requiresCommentApproval=DISABLED
  • 更好:使用 ALL_PULL_REQUESTSFORK_PULL_REQUESTS 并限制批准者角色。
  • 滥用:fork/drive-by PR 自动运行,无需受信任维护者批准。
  1. No restrictive branch/path strategy for PR builds
  • 缺少通过 HEAD_REF + BASE_REF + FILE_PATH 的纵深防御。
  • 不良示例:只有 EVENT + ACTOR_ACCOUNT_ID,没有 ref/path 控制。
  • 更好:结合精确的 ACTOR_ACCOUNT_ID + BASE_REF + HEAD_REF + FILE_PATH 限制。
  • 滥用:攻击者修改构建输入(buildspec/CI/依赖)并获得任意命令执行。
  1. Public visibility + status URL exposure
  • 公开的构建/检查 URL 提高了攻击者的侦察和迭代测试能力。
  • 不良示例:projectVisibility=PUBLIC_READ,且在公开构建中有敏感日志/配置。
  • 更好:除非有强烈的业务需求,否则保持项目私有,并对日志/构件进行清理。
  • 滥用:攻击者发现项目模式/行为,然后调整有效载荷和绕过尝试。

Token leakage from memory

Wiz 的报告解释了源提供商凭证存在于构建运行时上下文中,并且在构建被攻破后可以被窃取(例如通过 memory dumping),如果权限范围过大则可导致仓库接管。

AWS 在漏洞披露后引入了加固,但核心教训依然是:永远不要在特权构建上下文中执行不受信任的 PR 代码,并假定攻击者控制的构建代码会尝试窃取凭证。

For additional credential theft techniques in CodeBuild, also check:

AWS Codebuild - Token Leakage

Finding CodeBuild URLs in GitHub PRs

如果 CodeBuild 将提交状态报告回 GitHub,CodeBuild 构建 URL 通常出现在:

  1. PR 页面 -> Checks 选项卡(或 Conversation/Commits 中的状态行)。
  2. Commit 页面 -> 状态/检查部分 -> Details 链接。
  3. PR commits 列表 -> 点击附加在提交上的检查上下文。

对于公共项目,该链接可能会向未认证用户暴露构建元数据/配置。

脚本:在 PR 中检测 CodeBuild URL 并测试它们是否看起来是公开的 ```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”

已在以下环境测试通过:
```bash
bash /tmp/check_pr_codebuild_urls.sh carlospolop codebuild-codebreach-ctf-lab 1

快速审计检查表

# 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

检查每个项目是否存在:

  • webhook.filterGroups containing PR events.
  • ACTOR_ACCOUNT_ID patterns that are not anchored with ^...$.
  • pullRequestBuildPolicy.requiresCommentApproval equal to DISABLED.
  • Missing branch/path restrictions.
  • High-privilege serviceRole.
  • Risky source credentials scope and reuse.

加固建议

  1. 要求 PR 构建的评论审批(ALL_PULL_REQUESTSFORK_PULL_REQUESTS)。
  2. If using actor allowlists,锚定正则并保持精确匹配。
  3. Add FILE_PATH restrictions to avoid untrusted edits to buildspec.yml and CI scripts.
  4. 将受信任的发布构建与不受信任的 PR 构建分离到不同的项目/角色。
  5. Use fine-grained, least-privileged source-provider tokens(prefer dedicated low-privilege identities)。
  6. 持续审计 webhook filters 和 source credential 的使用。

References

Tip

学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE) 学习和实践 Azure 黑客技术:HackTricks Training Azure Red Team Expert (AzRTE)

支持 HackTricks