- Microsoft の Andres Freund が Debian システムの SSH の性能異常 を追跡していたところ、ほぼすべての Linux/Unix 系環境で使われる xz Utils に仕込まれたバックドアを発見した
- 悪意あるコードは xz Utils 5.6.0 と 5.6.1 に含まれており、特定の秘密鍵を持つ攻撃者が SSH ログイン証明書にコードを隠し、バックドアのあるデバイス上で実行できるよう設計されていた
- 攻撃者は GitHub のソースではなく リリース tarball、テストファイル、ビルドスクリプト、glibc の IFUNC を利用して、liblzma 経由で sshd の認証ルーチンをフックしようとした
- バックドアは amd64/x86_64、glibc、Debian または Red Hat 系のパッケージビルド条件を確認しており、Fedora Rawhide、Fedora 41、Debian testing/unstable/experimental、openSUSE Tumbleweed/MicroOS、Kali Linux の一部期間のリリースに含まれていた
- Jia Tan という開発者ペルソナは数年にわたって xz Utils の保守に関与しており、この事件は CVE-2024-3094 として追跡され、Binarly の検査ページや xzbot のような検出・分析ツールが登場した
発見と影響範囲
- Andres Freund は Microsoft で PostgreSQL 関連の作業をしていた開発者兼エンジニアで、Debian システムで SSH ログイン が CPU を過剰に消費し、valgrind エラーを出す現象を調査している中で異常の兆候を見つけた
- 原因は xz Utils の更新であり、Freund は Open Source Security List で、この更新が圧縮ソフトウェアに意図的に仕込まれた バックドア だと公表した
- xz Utils は Linux を含むほぼすべての Unix 系 OS でロスレスデータ圧縮と展開を提供し、レガシーな .lzma 形式 もサポートする
- Filippo Valsorda はこれを「公に説明されたサプライチェーン攻撃の中でも最も巧妙に実行された事例かもしれず、広く使われるライブラリの悪意ある有能で権限を持つ upstream という悪夢のようなシナリオだ」と評価した
バックドアが狙った動作
- 悪意あるコードは xz Utils 5.6.0 と 5.6.1 に追加され、ソフトウェアの動作方法を変えた
- バックドアはリモート SSH 接続に使われる実行ファイルである sshd を操作する
- あらかじめ定められた暗号鍵を持つ者は、SSH ログイン証明書に任意のコードを隠してアップロードし、それをバックドアのあるデバイス上で実行できる
- 実際にアップロードされたコードは確認されておらず、攻撃者がどのようなコードを実行しようとしていたのかは不明である
- 理論上は、暗号鍵の窃取やマルウェアの導入を含め、ほぼあらゆる操作が可能だったと考えられる
圧縮ライブラリが SSH に到達した経路
- ライブラリは、自身とリンクされた実行ファイルの内部動作を操作できる
- OpenSSH の代表的な sshd 実装は、デフォルトでは liblzma とリンクしていない
- Debian と複数の Linux ディストリビューションは、sshd を systemd と接続するパッチを追加していた
- systemd は起動中に複数のサービスを読み込むプログラムである
- systemd は liblzma にリンクされている
- この接続経路のため、xz Utils が sshd に影響を与えられた
数年にわたる準備の痕跡
- 2021 年、JiaT75 というユーザーがオープンソースプロジェクトに最初に知られているコミットを残した
- libarchive プロジェクトで safe_fprint 関数を、以前からより安全でないと知られていた変種に置き換える変更であり、当時は誰も気づかなかった
- 2022 年、JiaT75 は xz Utils のメーリングリストにパッチを提出した
- ほどなくして、新規参加者の Jigar Kumar が、Lasse Collin は xz Utils を十分な頻度または速さで更新していないと圧力をかけた
- Dennis Ens と他の新規参加者たちも、Collin に追加のメンテナーを受け入れるよう圧力をかけた
- 2023 年 1 月、JiaT75 は xz Utils に最初のコミットを残し、Jia Tan という名前で xz Utils の業務にさらに深く関与した
- oss-fuzz の Collin の連絡先を自分の連絡先に変更した
- oss-fuzz テスト中に IFUNC 機能 を無効化し、その後 xz Utils に入る悪意ある変更を検出できないようにする変更を要求した
- 2024 年 2 月、Tan は xz Utils 5.6.0 と 5.6.1 のコミットを行い、この更新がバックドアを実装した
- その後、Tan または別の人物が Ubuntu、Red Hat、Debian の開発者に対し、その更新を OS にマージするよう求めた
含まれたディストリビューションと実行条件
- Tenable によれば、バックドア版または関連更新は次のリリースに入っていた
- Fedora Rawhide: Fedora Linux の開発ディストリビューション
- Fedora 41
- Debian testing, unstable, experimental: 5.5.1alpha-0.1 から 5.6.1-1
- openSUSE Tumbleweed と openSUSE MicroOS: 3 月 7 日から 3 月 28 日までの間にバックドア入り xz バージョンを含む
- Kali Linux: 3 月 26 日から 3 月 28 日までの間、xz-utils 5.6.0-0.2 を含む
- Sam James の分析によると、悪意あるスクリプトはビルド対象が amd64/x86_64 か、linux-gnu という名前を使うか、GCC と GNU ld を使うかを確認していた
- また、Debian パッケージビルドか、あるいは RPM_ARCH が x86_64 かどうかも確認していた
- 攻撃は、amd64 システムで glibc を使用し、Debian または Red Hat 派生ディストリビューションをビルドする環境を狙ったものとみられる
- 他のシステムが脆弱かどうかは、当時の時点では不明だった
実装方式と隠蔽手法
- Sam James は、バックドアが複数の構成要素で成り立っていたと整理している
- upstream が配布したリリース tarball は GitHub のコードと同一ではない
- リリース tarball の build-to-host.m4 は GitHub upstream のものと大きく異なる
- git リポジトリの tests/ フォルダには細工されたテストファイルがある
tests/files/bad-3-corrupt_lzma2.xz
tests/files/good-large_compressed.lzma
- build-to-host.m4 が呼び出したスクリプトが悪意あるテストデータを展開し、ビルド過程を改変する
- glibc の IFUNC が OpenSSH 認証ルーチンを実行時にフックまたはリダイレクトするために使われる
- HD Moore は、最終的なバックドア段階が amd64 上でライブラリをビルドし、Debian または RPM パッケージを作成するときにのみ実行されることを確認した
- 研究者たちの分析によれば、SSH 公開鍵検証の過程で特定の fingerprint 関数と公開鍵が一致すると、公開鍵を実際に検証する前に事前共有鍵で鍵の内容を復号する
- 復号された内容は、特定の形式に合致した場合
system に直接渡される
- fingerprint が一致しない、または復号された内容が形式に合わない場合は通常の鍵検証に戻るため、利用者が違いに気づくのは難しい
Akamai が整理した実行チェーン
- Akamai の研究者は、バックドアが xz GitHub リポジトリではなく ソースコード tarball リリース にのみ含まれており、検出を避けようとしたとみている
- バックドアは複数のコミットにまたがって構成された
- ビルド過程で IFUNC を使い、マルウェアがシンボル解決関数を横取りできるようにした
- テストファイルの中に難読化された共有オブジェクトを隠した
- ライブラリのビルド過程で共有オブジェクトを抽出するスクリプトを実行した
- プロセス権限を制限するセキュリティ機能である landlocking を無効化した
- 実行チェーンは複数段階にわたる
build-to-host.m4 がライブラリビルド中に実行され、bad-3-corrupt_lzma2.xz を bash スクリプトとしてデコードする
- この bash スクリプトが
good-large_compressed.lzma をより複雑な方法でデコードし、別のスクリプトを作る
- そのスクリプトが
liblzma_la-crc64-fast.o 共有オブジェクトを抽出し、それを liblzma のコンパイル過程に追加する
- この共有オブジェクトは liblzma にコンパイルされ、通常の関数名解決過程を置き換える
- 悪意あるライブラリは OpenSSH の
RSA_public_decrypt 関数ポインタを自作の悪意ある関数に置き換えられる
- Filippo Valsorda の分析によると、この悪意ある関数は認証クライアントの証明書からコマンドを抽出し、脅威アクター本人であることを確認したうえで
system() に渡し、認証前のリモートコード実行を達成する
Jia Tan と残る疑問
- Jia Tan について知られている情報は非常に少ない
- この開発者ペルソナは、ここ数年で数十の他のオープンソースソフトウェアにも関与している
- Jia Tan というユーザー名の背後に実在の人物がいたのか、完全に作られた人物なのかは不明である
- 追加の技術分析は、Filippo Valsorda の Bluesky スレッド、Kevin Beaumont の分析、Freund の金曜公開資料で確認できる
CVE と確認ツール
- この脆弱性の追跡識別子は CVE-2024-3094 である
- Binarly の xz.fail ページは IFUNC 実装を検出し、挙動分析に基づいている
- 類似のバックドアが他の場所に仕込まれた場合でも、不変条件を自動検出できる
- xzbot は分析と実験用の機能を提供する
1件のコメント
Hacker News のコメント
目的は、標準化されたテストフレームワークを使って XZ のテストを書きやすくすることだった
まだテストされていない機能が多く、長期的なプロジェクトの安定性のためにテストを増やす助けになる、と Jia が 2022-06-17 に書いていた内容
かなり前から準備されてきた変更だったということ
ライブラリが
RSA_public_decryptに割り込めるようにしたリンク機構については、あまり議論されていないように思うプロセス分離のような話は多いが、その関数呼び出しのリダイレクトについての話は少ない
SSH から入ってくるコードのような中核的な構成要素をライブラリと階層的な信頼モデルでリンクして、「自分が呼び出す場所では信頼するが、別の呼び出し地点に自ら割り込むことは許さない」といったモデルを作れるのではないかと思う
回避方法があるから意味がないという「セキュリティ・バイ・オブスキュリティ」的な反射反応を招くかもしれないが、それでも攻撃面の縮小と見なせる
ただし OS には複数のセキュリティコンテキストが重なっている。XZ バックドアに関しては主にモジュールレベルの capability ベースのセキュリティだが、プログラムレベルの capability、メモリレベルの分離(ページング)、マイクロアーキテクチャレベルの分離などもある
これらの要素を連携させつつ性能も出すのはかなり難しく、Unix 系がこのモデルへ移行するにはプロセスという概念自体を置き換える必要があるため、事実上不可能に見える
これが XZ のテストを壊し、突然そのテストを無効化しようとロビー活動するアカウントが現れ、その結果エクスプロイトが可能になった
./configure && make実行時)に C ファイルをこっそり書き換えて ifunc resolver にパッチを当て、同梱された悪意あるオブジェクトを呼び出すようにするもの破損したオブジェクトファイルは
nowリンカフラグとともにリンクされ、ライブラリのロード時に ifunc が即座に解決される。この時点ではプロセスのリンクテーブルがまだ書き込み可能なので、パッチ済みの resolver が呼び出されるまさにここが重要で、ライブラリがロードされるときにメモリ内の
RSA_public_decrypt関数をそのまま横取りできたバックドア注入過程を非常によく分析した記事: https://research.swtch.com/xz-script
dlopenを使う変更をマージした: https://github.com/systemd/systemd/pull/31550その意味では、より安全なリンク方法だ
ltraceが呼び出すシンボルを監視する方法で十分なのか気になるなぜ「ほぼ」世界中を感染させかけた、と表現するのか分からない
少なくともかなり人気のある Linux ディストリビューション 3 つ、Arch、Gentoo、openSUSE Tumbleweed が数週間にわたってバックドアを配布しており、Tumbleweed では確実に動作していた
数週間バックドア入りの SSH だったのだから、「ほぼ」というには弱い
deb/rpm 対象でのみ動作したので、実質的には本番環境に届く前に止められた形だ
だから問題ないという意味ではなく、これが RHEL や Debian/Ubuntu stable に入るほど長く発見されなかったなら、銀行や医療機関のようなところで通知を受けることになっていただろう
認証前のリモートコード実行であれば、ネットワークを強く制限し、フローログをきちんと備えているところでない限り、「影響を受けていない」とは言いにくかったはず
xz-5.6.1-1とxz-5.6.1-2のliblzma.so.5.6.1をcmp -lで比較すると、ごく小さな差しかない勧告文を書く前には、これを知らなかったのだと思う
https://github.com/QubesOS/qubes-issues/issues/9067#issuecom...
ただし、それを裏づけるデータをどう得ればよいかは分からない
今後 12 か月以内に似たような何かが実環境で見つかることに 101ドル賭けてもいい
メンテナーたちが互いの過去のコミットを疑いながら調べ始めるだろうから
重要だがあまり知られておらず、メンテナーがごく少ないコードベースを見ればいい
もし自分がこういうものを持っていてうまく動作していたなら、後から別のアカウントで「発見」して修正させたと思う
今回の件から得た個人的な結論はいくつかある
第一に、ソースリポジトリとは異なるコードを含むソース配布 tarballはよくなく、避けるべきだ。別の大きなサプライチェーン攻撃である event-stream も似た点を利用していた
その結果として、自動生成された成果物は常にコミットされるべきだ
第二に、コードレビューで誰もが Page Down で飛ばしてしまう自動生成成果物は問題だ。こうしたファイルがリポジトリにあるなら、誰かが改ざんしていないか確認する自動テストも必要で、古い自動生成ファイルを放置しないようにもしてくれる
第三に、1 と 2 の帰結として autotools は悪く、autotools 文化も悪い
第四に、Libsystemd はエコシステムにとって問題だ。これを言うと systemd 嫌いと片付けられるが、大きく複雑で依存関係が多く、ほとんどのプログラムはそのごく一部しか使わない。すべてのサービスが初期化通知のためにこれへ依存するよう促すのは正気ではない
第五に、コード再利用は常に良いことで、小さな機能のために大きなライブラリへ依存してもよい、という文化があるが、それは事実ではない。依存関係はメンテナンス負担でありセキュリティリスクでもあり、取り込む機能と天秤にかける必要がある
第六に、ディストリビューションのメンテナーがパッケージに大きなパッチを当てるのも問題だ。実際のメンテナーが見ていないライブラリやアプリケーションの、広く使われる事実上のフォークが生まれてしまう
第七に、開発者の立場では OSS が財政的に持続可能にならなければならない。Liblzma と xz-utils は数千万のインストールがあるはずなのに、メンタルヘルスの問題を抱えるメンテナー 1 人に頼っていた
第八に、言いたくはないが、今はコードレビューやメンテナンス権限の移譲において地政学的な考慮もしなければならない
Jia Tan が本名だという証拠もなく、実在の人物だという証拠すらない
プロジェクトがアジア系のように聞こえる名前の貢献を受け入れなくなったら、次の攻撃では Richard Jones という名前を使えばいいだけだ
BSD の世界から来ると systemd は衝撃的で、怪物のようで、あちこちに触手を伸ばしている
消費者も無邪気だが、ソフトウェア業界自体もセキュリティ脅威に対して無邪気だ
ソーシャルなエクスプロイトはコードのエクスプロイトの一部だ
FOSS の「コードを見る目は多いほどよい」という原則は正しいが、その目が訓練された目である場合に限って機能する。FOSS には業界からの物質的支援が必要だ
MSFT のエンジニアがこのエクスプロイトを見つけたが、それでも Fedora 41、openSUSE、Kali の一般公開版には入っていた
開発ツールチェーンとテストプロセスは、セキュリティをテストするように設計されたことがない。SolarWinds も参考になる: https://www.wired.com/story/the-untold-story-of-solarwinds-t...
リリース成果物に入っているのは autoconf スクリプトだけではない
バイナリ blob をリリースアーカイブに入れる理由は多い。ゲームリソース、ファームウェアイメージ、テストケースなどがある。mpv がプロプライエタリなエンコーダで生成したメディアファイルの一部をテストケースとして含めているという話もあったが、それは悪いことではなく良いことだ
よく保守されている sqlite はどこでも使われており、優れたテストスイートもある。リリースごとに tarball を 1 つではなく、コンパイル段階ごとに 2 つ配布している。これをやめるのは簡単だろうが、パッケージメンテナーの仕事を増やすだけで、セキュリティ改善には役立たない
Debian が選別された tarball からビルドするのは、人が選別し、よく知られた鍵で署名するからだ。もちろん git からビルドすることもできるが、それで状況が改善するかは不確かだ。すべてのプロジェクトがリリースタグに署名しているわけでもなく、署名していたとしても自動化されている可能性の方が高い
私たちは変更がまず upstream メンテナーに、次にパッケージメンテナーにレビューされることを望んでおり、この 2 者が互いに無関係であることを好む
今回は腐敗した upstream メンテナーがそのプロセスを攻撃したが、だからといって upstream メンテナーをなくすべきだという意味ではない。ここ数年、この構造のおかげで複数のバックドアの試みが防がれており、慎重な検討なしに捨てるようなプロセスではない
以前から言われてきた改善の方向性はそのままだ。再現可能なビルドをさらに追求し、可能なら攻撃対象領域とビルドの複雑さを下げるべきであり、メンテナーを信頼しつつ作業は検証しなければならない
むしろその点で困惑しており、libsystemd なしで単純なデータグラムを実装する方法についてのドキュメントを追加している
liblzma と xz-utils のインストール数は数千万よりはるかに多いはずだ。Python、PHP、Ruby など多くの言語が libxml2 に依存しており、libxml2 は liblzma を使っている。他にも依存関係は多い
地政学的な考慮はメンテナーの仕事ではない。OSS は保証なしで提供される
さらに「Jia Tan」は完全に偽物だった可能性がある。コミットのタイムスタンプを見ると、同じ日でもタイムゾーンが東欧からアジアへ変わっている。少なくともアイデンティティゲームをしていたのは明らかだ
この問題を発見した人が Azure Postgres で働く Microsoft エンジニアだったとは知らなかった
ありがとう Microsoft、これで Azure が好きになった
この問題がそのように発見されたからだ
そのうえで問題のライブラリを調べ、偽のペルソナがプロジェクトを掌握する似たような外れ値を探す必要がある
こうしたエラーを無視するのが一般的な慣行のように見える
こういう見せ方は本当に我慢ならない
xz の元のメンテナーは、Jia Tan に直接会うどころか、少なくとも通話すらせずに責任を引き渡したように見える
メールや GitHub だけでやり取りするのがよくあることなのか気になる
今回の件以降、一部のオープンソースプロジェクトのメンテナーはもっと慎重になりそう
自分も、実際の相手が誰なのかまったく知らないまま、テキストだけでやり取りしてライブラリのメンテナンスを引き継いだり引き渡したりしたことがある
ただし今回の件から「メンテナーはもっと慎重になるべきだ」と結論づけるのは完全に間違っていると思う
人々が自分のプロジェクトに取り込むものに対する責任は、メンテナーではなく、そのプロジェクトで作業している人たちにある
メンテナーを信頼するか、信頼しないかのどちらかであり、ライブラリに依存し始めた瞬間、誰を信頼するのかを継続的に更新していくことに暗黙のうちに同意しているようなもの
何百万もの企業が、無給のオープンソース開発者の作業にただ乗りしている
だから彼らが去り、問題が起きるのは驚くことではない
その人の意図について、どんな信頼が上乗せされたというのか
GitHub スター 100 個から 3 万個まで、さまざまな規模のオープンソースプロジェクト 6 件ほどに参加したが、誰とも通話したことはなく、テキストベースのコミュニケーションが標準だった
しかし、個人的に知っているからといって問題が必ず解決するわけではない
ずいぶん前に匿名で、とあるオープンソースプロジェクトに関わったことがあるが、ここで名前は明かしたくない。リードプログラマーには、かなりよく知っているように見える共同メンテナーがいた
その共同メンテナーは、私や後から来た他のメンテナーたちを継続的にガスライティングし、見下し、ごく小さなバグで責め立てて離脱させた。侮辱を取り除いても、教育的な Linus Torvalds 式の叱責とは違っていた
リードメンテナーは、その主張の技術的な核心には同意していたため、彼を助長した
数年後、その共同メンテナーはプロジェクトを敵対的に乗っ取ろうとしたが、思った通りには進まなかった。その後まもなく複数の私的な書簡が公開され、彼が常にそれを望んでおり、他のメンテナーをガスライティングしていたのもその目標の一部だったことが明らかになった
2 人が互いに知り合いであっても、こういうことは起きた
みんなこのバックドアは早期に見つかったと思っているが、すでに目的を達成していた可能性もある
特に標的が Kali や Debian のようなローリングリリース系ディストリビューションを使う開発者だった場合はあり得る
週の初めに SSH トラフィックを少し見たが、その時点ではあまり気にしていなかった
もちろん、これは見当違いかもしれない: https://www.nubi-network.com/news.php?id=21
「Lasse Collin が xz Utils を十分な頻度または速さで更新していなかった」という類いのミームは誤りだった
SSH がなぜ xz を使うのか分からない
そうする必要があるのか? 本当にそんなに重要なのか?
OpenSSH が起動通知を提供するために libsystemd を取り込み、libsystemd が liblzma を取り込んでいた。通常、liblzma のコードが OpenSSH の中に入ることはない
しかし libsystemd の依存関係としてビルドされるため、ビルドスクリプトは libsystemd および OpenSSH と同じ環境で実行される
攻撃ペイロードは、liblzma のテストディレクトリ内に、圧縮テストケースを装った難読化されたバイナリ blob として隠されていた
git のソースから lzma をコンパイルし、autotools でビルドスクリプトを生成する場合には怪しいことは何もなかった。しかしディストリビューションのパッケージャーが使うソース tarball では autotools がすでに実行されており、攻撃者は自動生成された読みにくいスクリプト出力を差し替えていた
そのスクリプトは、liblzma が OpenSSH と同じ環境でコンパイルされているか、そして
.debまたは.rpmパッケージに入るようにコンパイルされているかを確認し、両方が真なら攻撃ペイロードを OpenSSH に埋め込んだその後ペイロードは、OpenSSH が init スクリプトで通常どおり起動されたのか手動実行されたのか、一般的なデバッグツールが存在するかなど複数の検査を行い、デバッグツールがなく「自然な」起動に見える場合にだけ、実行中のプロセスにアタッチした
実行中は秘密鍵検証に hook を掛け、正しい秘密鍵でログインが試みられると、受信パケットの残りを
systemで呼び出し、root 権限のリモートコード実行を提供した