新たに公開されたリモートコード実行(RCE)の連鎖攻撃はGitLab CEおよびEEに影響を及ぼします。この攻撃は、Ruby向けに広く使われるC言語ベースのネイティブJSONパーサー「Oj」に存在する2つのメモリ破損バグのみで構成されています。
Depthfirstが報告したこれらの脆弱性は、研究者らがGitLabのノートブック差分レンダラーとの関連性を突き止めるまで、Oj内で約5年間も発見されずに潜んでいました。
この攻撃連鎖の起点は、一見わかりやすい攻撃対象からは程遠い場所にあります。それがGitLabのJupyter Notebook差分表示機能です。ユーザーが.ipynbファイルをコミットすると、GitLab組み込みのipynbdiffgemがOj::Parser.usual.parseを使ってノートブックのJSONを解析し、人間が読める形式の差分を生成します。
この呼び出しは、gitアカウントで動作するPumaワーカープロセス内でOjのネイティブC拡張に到達します。プッシュ権限を持つ認証済みのプロジェクトメンバーであれば、特別な権限や管理者権限、被害者側の操作を一切必要とせずにこの脆弱性を悪用できます。
書き込みプリミティブ(範囲外書き込み): Ojのネスト深度トラッカーは、境界チェックのない固定1,024バイトのスタック配列を使用していました。配列を深くネストさせると、配列の末尾を超えて0x01バイトが前方向に書き込まれ続け、最終的にバッファポインタ(buf.head)が破損します。
研究者のYuhang氏は、4,001桁の数値と446要素の配列を組み合わせて細工することで、これをアロケータ支援型の「ヒープグルーミング」手法へと発展させました。jemallocを欺き、攻撃者が制御するデータをOjの内部コールバックポインタ(p->start)の位置に配置させたのです。
読み取りプリミティブ(ヒープポインタの漏洩): Ojのキー長処理に存在する別のバグにより、サイズの大きいJSONオブジェクトのキー値が64ビットサイズから16ビットフィールドへと切り詰められてしまいます。この結果、Ojは内部Key構造体の生バイトを29バイト漏洩させ、その中には有効なヒープポインタも含まれており、GitLabがレンダリングした差分出力を通じて漏れ出してしまいます。
この漏洩したポインタにより、研究者らはヒープの「目印」を得ることができました。GitLabのPumaワーカーはプリロード式のクラスタモードで動作するため、フォークされたワーカー同士は同一のライブラリベースアドレスを共有します。
Yuhang氏は、漏洩したアドレスを測定済みの変位範囲と比較することで、コールバック制御型のプローブ手法を用いて数分のうちにlibc/librubyのベースアドレスをブルートフォースで割り出しました。
ASLR(アドレス空間配置のランダム化)を突破し、コールバックポインタの制御も確立した後、字句順に並べた2つの悪意あるノートブックファイルを単一の差分リクエストで送信します。1つ目のファイルで破損したポインタを準備状態にし、同じリクエスト内の次の解析呼び出しでそれを発動させることで、制御フローをsystem()関数へと乗っ取り、gitユーザー権限で任意のコマンドを実行できるようになります。
同じOj監査からは、パーサー・ローダー・ダンパーの各APIにまたがるバッファオーバーフロー、use-after-freeバグ、整数オーバーフローを含む合計9件のCVEが発見されました。この事実は、「メモリセーフ」とされるRuby gem内部のネイティブC拡張が、依然として十分に検証されていない攻撃対象であり続けていることを浮き彫りにしています。
SOC調査の死角を解消し、ANY.RUNを使って脅威の早期封じ込めを実現することで、対応コストと業務への影響を軽減できます。
翻訳元: https://cyberpress.org/gitlab-rce-chain-exploits/