GitHubのハンドル名「KillaBoi」を名乗る研究者が、「Steal My Bitcoin」キャプチャ・ザ・フラッグ(CTF)チャレンジ向けのPython製概念実証コード(PoC)を公開しました。このPHPの攻略チェーンは、メモリアドレスをリークさせたうえで、内部のクリーンアップ処理をコマンド実行へと誘導する仕組みです。
ただし、公開された証拠から裏付けられるのは秘密鍵の取得までです。懸賞として提示されていたビットコインを実際に盗み出したことは確認されていません。KillaBoiによると、本番環境への試行は2026年10月25日15時47分38秒(UTC)に行われました。
最終的なレスポンスには、PHPのメモリ枯渇エラーに続いて、チェックサムが有効なウォレットインポート形式(WIF)の秘密鍵が含まれていました。しかし、この鍵からは懸賞として提示されたアドレスを導出できませんでした。KillaBoiは、この食い違いについてチャレンジの作成者がメール上で認めたと述べています。
この手法が標的とするのは、セッションのアップロード進捗の処理です。リポジトリの説明によると、深くネストしたファイルフィールド名を含むマルチパートリクエストを送ると、約250 KiBというリクエストのネットワーク上の大きさからは想像できないほど多くのメモリをPHPが確保します。
処理が進むと、最終的に設定上限である128 MiBのPHPメモリ制限を使い果たします。重要なのは、致命的エラーそのものではありません。
KillaBoiの報告によると、解析が中断されると、常駐ワーカー内に古いセッション状態が残ります。このプロセスが別の接続を処理する際に、後続のリクエストがその状態に遭遇する可能性があります。
2つの情報を検証した後、PoCは最後のマルチパートリクエストを送信します。このリクエストには、偽造したPHPのHashTable、重なり合うコールフレームのデータ、コマンドを含む文字列が入っています。
再びメモリ制限エラーが発生するとクリーンアップ処理が走り、改ざんされたデストラクタのコールバックによって、実行がzif_systemへ誘導されます。zif_systemは、PHPがsystem()を処理する内部ハンドラです。
公開された再現手順では、実行の成否を確認するために、新たに生成したランダムなマーカー、IDコマンドの出力、解決されたprint-flag実行ファイルのSHA-256ダイジェストを用います。
出力は通常のプロセスの標準出力ではなく、受け付け済みのアクティブなソケットを通じて返されます。1回の試行で使うHTTPリクエストは最大20回で、自動リトライは行いません。
文書化されたDockerの検証環境は、Alpine版のPHP 8.4.26、nginx、ワーカー数4で構成したPHP組み込みCLIサーバーで構成されています。研究者は、バイナリのレイアウト、メモリ確保の挙動、ワーカー構成が結果を左右すると強調しています。実際、同じバージョンのDebian版PHP-FPMビルドでは、スクリプトのコードポインタによるフィンガープリント検査に失敗します。
報告された10回の検証環境での試行のうち、7回は実行の成功を確認できました。2回は最終段階まで到達したものの実行マーカーは得られず、1回はヒープ情報の取得に失敗しました。
これらの結果は、この特定の環境におけるワーカー選択の競合状態を反映したものです。PHPの環境全般に当てはまる成功率ではありません。
このリポジトリでは、CVE番号、公式な「重大」の深刻度評価、影響を受けるバージョンの範囲は示されていません。実証された最大の成果は、調整済みの検証環境でのコード実行と、本番のチャレンジで秘密鍵を取得したという報告にとどまります。
本番への試行では、送信リクエストとレスポンスヘッダーの完全な記録が残されていませんでした。さらに、取得した鍵は懸賞のアドレスと一致しませんでした。したがって、今回の公開内容をビットコイン窃取の実証と呼ぶのは、公開されている証拠を過大に評価することになります。
16,000以上のSOCチームがANY.RUNを導入し、脅威調査の効率化と手作業の削減を実現しています。チームで試してみる
翻訳元: https://cyberpress.org/critical-php2shell-flaws/