XZ Utilsバックドア(CVE-2024-3094)
ほぼ全Linuxが載せる圧縮ライブラリに、2年かけて信頼を得たメンテナがsshd認証を破るバックドアを仕込んだ。CVSS10.0の攻撃がなぜ検知網をすり抜け、性能の違和感1つで暴かれたのかを解剖する。
- CVE-2024-3094はxz-utils 5.6.0/5.6.1のliblzmaへ仕込まれたCVSS 10.0のバックドア。ビルド時に悪意コードを注入し、sshdのRSA署名検証を乗っ取る。
- 攻撃者は約2年で共同保守者となり、Gitでなく配布tarballへ細工したm4を混入。x86-64・glibc・rpm/deb系だけで発火し、IFUNC経由でGOTを書き換えた。
- Andres Freundがsshdの約500msのCPU増とvalgrind異常を追って発見した。教訓は単一保守者リスク、再現可能ビルド、配布tarball検証の重要性だ。
何が起きたか(影響範囲・深刻度)
2024年3月29日、MicrosoftのエンジニアでPostgreSQLの開発者でもあるAndres Freundが、広く使われる圧縮ユーティリティ xz-utils のバージョン5.6.0および5.6.1にバックドアが仕込まれていることを公表しました。割り当てられたのが CVE-2024-3094、CVSSスコアは最高値の 10.0(Critical) です。xzが提供する共有ライブラリ liblzma は事実上あらゆるLinuxディストリビューションに存在し、systemd をはじめ無数のソフトウェアが依存します。バックドアの狙いは、この依存の連鎖を辿って OpenSSHのsshd に到達し、リモートからの認証を迂回して未認証コード実行を可能にすることでした。
不幸中の幸いは、影響を受けた5.6.0/5.6.1がまだ 開発版・テスト版チャネル(Debian sid、Fedora Rawhide/40 beta、openSUSE Tumbleweed、Arch等)に留まっていた点です。DebianやUbuntuの安定版、RHELなど本番系には未到達で、発覚も攻撃者が意図した「安定版への浸透」の直前でした。それでも、もし数週間から数か月見逃されていれば、世界中のサーバーのSSHが静かに破られるという、ソフトウェア史上最悪級のサプライチェーン侵害になり得ました。
XZ事件はバグの混入ではなく、長期間の社会工学で信頼を獲得した人物による計画的な悪意コードの埋め込みです。攻撃者「Jia Tan」(アカウント名 JiaT75)は数年がかりでプロジェクトの共同メンテナの地位に就いた後、配布物にのみ細工を施しました。
脆弱性の原理(なぜ起きたか)
技術的な核心は「悪意コードをどこに隠し、どうやってビルド時にだけ復元し、いかにしてsshdへ橋渡ししたか」の3段です。
1. ソースには置かず、テストデータに隠す。 gitリポジトリのソースコードを読んでも悪意ある処理は見つかりません。ペイロードは、圧縮の異常系を試すための「壊れたテストファイル」を装った2つのバイナリ(tests/files/bad-3-corrupt_lzma2.xz と good-large_compressed.lzma)の中に、暗号化・難読化された形で紛れ込ませてありました。バイナリのテストデータはレビューされにくいという盲点を突いています。
2. 配布tarballにだけ仕掛けを混ぜる。 多くのプロジェクトはgitの内容とリリースtarballが一致しません。tarballは autoconf で生成した configure などを含むためです。攻撃者はこの差分を悪用し、リリースtarballの build-to-host.m4 というm4マクロにだけ起動スクリプトを仕込みました。gitには存在しないので、GitHub上のコードレビューでは決して見えません。
# ビルド時、configureが埋め込まれたm4マクロを実行し、
# 「壊れたテストデータ」から段階的にスクリプトを復元する(概念図)
tr で文字を置換 → xz -d で復号 → シェルスクリプトを取り出す
# 復元スクリプトは環境を厳しく検査してから発火する:
# - x86-64 アーキテクチャか
# - GCC + GNU ld のツールチェーンか
# - rpm または deb をビルドしているか(=主要ディストロの公式ビルド)
条件に合致した場合のみ、ビルドの過程で悪意あるオブジェクトコードが liblzma に静かにリンクされます。ソースからの手動ビルドや、条件に合わない環境では発火しないため、追跡がきわめて困難でした。
3. IFUNCを悪用してsshdへ橋渡しする。 ここが設計の巧妙さです。sshdはxzに直接依存しませんが、多くのディストロではsystemdの通知機能(sd_notify)のために libsystemd とリンクされ、その libsystemd が liblzma を引き込みます。バックドアはGNU IFUNC(indirect function、CPU機能に応じて実装を実行時選択する仕組み)のリゾルバを乗っ取り、動的リンカがシンボルを解決する初期化フェーズで自らを割り込ませます。そしてsshd内の関数ポインタ、とりわけRSA公開鍵検証を担う RSA_public_decrypt に相当する経路を GOT(Global Offset Table)書き換え ですげ替えました。
IFUNCリゾルバは通常のコンストラクタ(.init_array)より早い、動的リンクのシンボル解決時に呼ばれます。攻撃者はこの早い実行タイミングを使い、監査ツールが動く前にsshdのプロセス空間へフックを差し込みました。正規の性能最適化機構が、そのまま侵入経路に転用された点が教訓的です。
エクスプロイトの流れ(概念)
横にスクロール
すり替えられた検証経路は、SSHハンドシェイクで提示される公開鍵(証明書)フィールドを覗き、攻撃者だけが持つ Ed448秘密鍵 で署名された特定のペイロードが埋め込まれているかを検査します。正規のクライアントの通信は素通りさせ、鍵照合に通った場合のみ、埋め込まれたコマンドをsshdの権限(通常root)で実行します。手順を概念レベルで示します。
- 攻撃者は自分のEd448秘密鍵で、実行させたいコマンドを含むペイロードに署名する。
- 細工したSSHクライアントで、標的のsshdへ接続し、そのペイロードを証明書に相当するフィールドへ載せて送る。
- バックドアが署名を検証。攻撃者の公開鍵で正しく検証できた場合のみ発火する。
- 認証プロセスをすべて迂回し、埋め込みコマンドをrootで実行する。
正しい秘密鍵を持つのは攻撃者だけなので、これは実質的に 本人しか使えない鍵付き裏口 です。パスワードもSSH鍵登録も不要で、ログにも通常のログイン失敗として残りません。ここでは実際のペイロード生成手順や署名フォーマットの詳細は扱いません。防御と理解が目的です。
バックドアは無効化スイッチ(環境変数による停止)や、意図しない環境での誤発火を避ける自己検査を備えていました。sshdの応答が約500ms遅くなるという副作用こそが、皮肉にも発見の糸口になりました。
修正と対策
根本対策は明快で、汚染された5.6.0/5.6.1を捨て、クリーンな系列へ戻すこと です。各ディストロは緊急に5.4系(例: 5.4.6)へダウングレードするか、パッチ済みのビルドへ差し替えました。GitHubはtukaani-project/xzのリポジトリを一時凍結し、Jia Tanのアカウントは停止されました。CISAやディストロ各社は該当バージョンの即時確認と切り戻しを勧告しました。
- バージョン確認:
xz --versionが5.6.0/5.6.1を示す環境を洗い出し、5.4系または修正版へ戻す。 - ビルドの脱汚染: 対策は単にライブラリを入れ替えるだけでなく、汚染された環境で生成された成果物を信用せず、クリーンなツールチェーンで作り直すこと。
- 依存の見直し: sshdへ不要な依存(systemd通知のためだけのliblzma引き込み)を減らす動きも生まれた。攻撃の橋渡し経路そのものを断つ発想です。
| 層 | この攻撃が突いた前提 | 取るべき対策 |
|---|---|---|
| ソースレビュー | gitのコードだけ見れば安全という思い込み | リリースtarballとgitの差分を検証し、生成物の由来を追う |
| テストデータ | バイナリのテストファイルは無害という油断 | バイナリ資産もレビュー対象化・生成手順の明文化 |
| ビルド再現性 | 配布物を各自がブラックボックスでビルド | reproducible builds でビット単位の再現を検証 |
| 人的信頼 | 長期貢献者は信頼できるという前提 | 重要変更の複数人レビュー・単一メンテナ依存の解消 |
教訓(一般化できる原則)
XZ事件が突きつけたのは、コードの欠陥ではなく 信頼のサプライチェーン の脆さです。原理として一般化できる原則を挙げます。
- 単一メンテナリスクは技術的リスクである。 xzは長年ほぼ1人の作者(Lasse Collin)が支えていました。攻撃者はまず偽アカウント群を使って「もっと活発なメンテナが必要だ」という圧力を作り出し、燃え尽きた作者から権限を引き出しました。重要なOSSほど、バス係数(bus factor)1の状態はセキュリティ上の欠陥だと捉えるべきです。
- 信頼は時間をかけて乗っ取られる。 攻撃者は2年以上、正当な貢献を積み上げてから牙を剥きました。「過去の貢献が善良だから今後も安全」は成り立ちません。権限昇格そのものを監査対象にする必要があります。
- ビルドは監査可能でなければならない。 ソースだけでなく、ソースから成果物への変換過程が攻撃面です。reproducible builds は、配布バイナリが公開ソースから決定的に再現できることを保証し、tarballへの後付け混入を検知可能にします。
- 異常検知は性能の違和感から始まる。 発見者は機能ではなく「sshdが妙に重い(約0.5秒のCPU増)」というプロファイル上の逸脱を無視しませんでした。可観測性は運用効率だけでなく、侵害の早期発見にも効きます。
同様に低レベルの信頼境界を突く攻撃としては、CPUの投機的実行を悪用するSpectre/Meltdownがあります。認証・多層防御の設計はセキュリティ、動的リンクやIFUNCの仕組みはOS、依存管理とビルドの再現性はプログラミングの各トピックも参照してください。
脆弱性の解剖の記事ガイド
XZ Utilsバックドア(CVE-2024-3094)を実務で読む
TL;DRは入口です。実際に選ぶ・使う段階では、何を解決するか、何と比較するか、導入後にどこで詰まるかまで見る必要があります。
解決すること
サプライチェーン攻撃
比較で見る軸
難易度: advanced / カテゴリ: 脆弱性の解剖 / タグ数: 6
導入後に効く点
攻撃者は約2年で共同保守者となり、Gitでなく配布tarballへ細工したm4を混入。x86-64・glibc・rpm/deb系だけで発火し、IFUNC経由でGOTを書き換えた。
先に潰すリスク
用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。
- 難易度
- advanced
- カテゴリ
- 脆弱性の解剖
- タグ数
- 6
判断チェックリスト
- 自社の用途が「サプライチェーン攻撃 / XZ Utils」に近いか確認する。
- 強みである「CVE-2024-3094はxz-utils 5.6.0/5.6.1のliblzmaへ仕込まれたCVSS 10.0のバックドア。ビルド時に悪意コードを注入し、sshdのRSA署名検証を乗っ取る。」が本当に評価軸になるか確認する。
- 注意点の「用語だけ覚えても、設計・実装・運用でどこに効くかを確認しないと判断を誤る。」を運用で吸収できるか確認する。
- 公開値や仕様値は、対象プラン・対象機種・対象リージョンまで確認する。
- 既存システム、ID、ネットワーク、監視、バックアップとの接続方法を先に洗い出す。
- 小さく試してから、本番移行、権限設計、障害時手順、コスト監視を決める。