xz utils 2024年 配布物に仕込まれた裏口

2年かけて共同の保守者になった者が、裏口の本体を試験のファイルとしてリポジトリに入れ、それを起動する仕掛けを配布の束にだけ入れた。リポジトリを読んでも、束を読まずに信じても気付けない。止める所は、束とタグの差、ビルドの再現、入口に結ぶ依存の数にある。

CVE-2024-3094。CVSS 3.1 の基本値は10.0、CWE-506 埋め込まれた悪意あるコード[3]。影響は XZ Utils 5.6.0 と 5.6.1[2]。公表は2024年3月29日[1]。開発元は2024年5月29日に裏口を除いた 5.6.2 を出した[16]。2026年11月時点の公開資料で書いています。

要点

  • 本体は、試験用の壊れた圧縮ファイルに見せかけてリポジトリに入っていた。起動する仕掛けは配布の束の中の m4 のファイルにだけあり、リポジトリには無かった。
  • 束を作って署名したのは、2022年から共同の保守者として働いていた者だった。署名は、誰が作ったかを示すだけで、中身が安全なことを示さない。
  • sshd に届いたのは、配布元が sshd に systemd への通知の当て布をして libsystemd を結び、その libsystemd が liblzma を結んでいたためである。
  • 見つけたのは、ログインが遅い、valgrind が誤りを出す、という振る舞いの違和感だった。安定版の配布の多くに届く前に止まった。
  • 根本の守りは、タグから作る、束とタグの差を確かめる、ビルドを再現できるようにする、入口のプロセスに結ぶ依存を減らす、の4つ。

何が起きたか

2021年の最初の修正案から、2022年の共同の保守、2024年2月の仕込み、3月の公表までの4つの段 1 信頼を得る 2021年10月から 小さな修正案を送る 保守の交代を迫る声 2 権限を得る 2022年から 共同の保守者 版を出し、署名する 3 仕込む 2024年2月から3月 試験のファイルと 5.6.0、5.6.1 の束 4 見つかる 2024年3月29日 ログインの遅さから 公の一覧へ報告 1と2に2年余り。3から4は約5週間 配布元の開発版と試験版に入り、安定版の多くには入らなかった
図1 仕込みまでの段と、見つかるまでの長さ
日付出来事
2021年10月29日Jia Tan の名前で、xz-devel の一覧に最初の修正案が届く。.editorconfig を足すだけの小さな案[9]
2022年6月7日一覧に、新しい保守者が来るまで進まない、今の保守者は関心を失った、という投稿が届く[10]
2022年6月8日保守者の Lasse Collin が返信する。無償の趣味の作業で、長く続く心の不調などで手が回らないこと、Jia Tan と一覧の外で作業しており、より大きな役割を持つかもしれないことを書く[11]
2022年6月29日Lasse Collin が、Jia Tan は実質的にすでに共同の保守者だと書く[12]
2022年11月30日README の連絡先が、保守者 Lasse Collin と Jia Tan の2人に届く宛先に変わる[13]
2023年3月18日5.4.2 のタグを Jia Tan が付けて署名する[14]
2024年2月23日Jia Tan が、試験用のファイルを足すコミットを入れる。この中に本体が隠されていた[15][1]
2024年2月24日5.6.0 を出す[16]。束は Jia Tan が作り、署名した[2]
2024年3月9日5.6.1 を出す[16]
2024年3月29日Andres Freund が oss-security の一覧に公表する[1]。Red Hat が CVE-2024-3094 を割り当て、NVD に載る[3]。CISA、Debian、Red Hat、openSUSE が同じ日に告知を出す[4][6][7][8]
2024年4月1日JPCERT/CC が CyberNewsFlash で注意を呼びかける[5]
2024年5月29日開発元が、点検の記録の1.0版と、裏口を除いた 5.6.2 を出す[2][16]
  • Jia Tan が触れられたのは GitHub に置いた物だけで、tukaani.org の本体のサイトと git.tukaani.org のリポジトリには Lasse Collin だけが触れられた、と開発元は書く[2]。束を GitHub から配っていたため、これで足りた。
  • 保守の交代を迫った投稿者が何者かは、開発元も公的機関も公表していない。

通った道筋

リポジトリの試験のファイルに本体があり、配布の束の m4 だけに起動の仕掛けがあり、配布元のビルドで liblzma に組み込まれ、libsystemd を通じて sshd に読み込まれる git リポジトリ コードと試験のファイル 試験のファイルに本体 起動の仕掛けは無い 配布の束 tar リポジトリの中身と生成物 書き換えた m4 保守者が作って署名 配布元のビルド configure の終わりで 条件が合えば本体を liblzma に組み込む GitHub が自動で作るソースの束には、m4 の変更が無い 包みとして配る sshd のプロセスの中。配布元が当て布をした場合 sshd root で待ち受ける 結ぶ libsystemd 起動の通知のため 結ぶ liblzma 改変された版
図2 裏口が sshd に届くまでの道筋
段何があったか
リポジトリ本体の大部分は、難読化した試験のファイルとして git に入っていた[1]。2024年2月23日のコミットは、壊れた xz や lzma の試験のファイルを足すという名目だった[15]。5.6.0 では、これらのファイルはどの試験にも使われていなかった[1]。開発元は、これらのファイルは、git に一度も入らなかった起動の仕掛けが無ければ害が無いと書く[2]。
配布の束束の m4/build-to-host.m4 に、configure の終わりで難読化したスクリプトを走らせる行が足されていた。この行は元にした m4 の上流には無く、xz の git ではこの m4 を使っていない[1]。束は Jia Tan が作り、自分の鍵で署名していた[2]。
配布元のビルド仕掛けが働くのは、x86-64 の Linux で、GCC と GNU のリンカを使い、Debian か RPM の包みを作るビルドの中だけだった[1]。NVD の説明では、偽装した試験のファイルから作り置きのオブジェクトを取り出し、liblzma の特定の関数を書き換える[3]。
実行時OpenSSH の上流は liblzma を使わない。Debian ほか複数の配布元は、systemd への通知のため sshd に当て布をしており、libsystemd が liblzma に依存していた[1]。こうして root で動く sshd の中に、改変した liblzma が読み込まれた。
リポジトリを読んでも見えない

本体は読めない2進のファイルで、起動の仕掛けは git に無い。コードを差分で読む点検は、どちらも拾えない。git を読む人は束を見ず、束を取り込む人は git との差を見ない。その隙間に置かれた。

どう見つかったか

見つけたのは Andres Freund である。Debian の開発版の sid で、数週間にわたり ssh のログインが CPU を多く使い、valgrind が誤りを出すことに気付き、perf と gdb で追った[1]。

存在しない利用者で手元へ ssh したときの時間は、改変の前が0.299秒、後が0.807秒 改変の前 0.299 秒 改変の後 0.807 秒 ssh nonexistant@localhost の real の時間。Freund の公表の数字
図3 気付くきっかけになったログインの遅れ
  • 差は0.5秒ほどで、利用者が体感で気付く大きさではない。同じ機械で同じ操作を測り続けていたから、違いとして見えた。
  • valgrind の誤りと一部の環境での異常終了は、裏口が想定したスタックの配置と実際が違うために起きていた。5.6.1 では、この誤りを直すという名目の変更が入った。開発版で試験を回していたことが、2つ目の手がかりになった[1]。
  • Freund の公表の時点で、5.6.0 と 5.6.1 はほとんどの配布元の安定版に入っておらず、入っていても多くは試験版だった[1]。

影響と配布元の対応

配布元影響を受けた版対応
Debiantesting、unstable、experimental の 5.5.1alpha-0.1 から 5.6.1-1。安定版は影響が知られていない[7]上流の 5.4.5 の中身に戻した 5.6.1+really5.4.5-1[7]
FedoraRawhide と Fedora Linux 40 の試験版。RHEL はどの版も影響なし[6]Rawhide の利用をすぐ止め、5.4 系へ下げる[6]
openSUSETumbleweed と MicroOS に3月7日から28日まで。Leap と SLE には無い[8]20240328 以降の版へ上げて再起動。ssh を外へ開いていたなら入れ直し、資格情報を全部回す[8]
全般XZ Utils 5.6.0 と 5.6.1CISA は 5.4.6 のような侵害の無い版へ下げ、侵害の跡を探すよう勧めた[4]

版の確かめ方 包みの管理の命令で見る

dpkg -l xz-utils liblzma5   # Debian 系
rpm -q xz-libs              # Fedora 系
rpm -q liblzma5             # openSUSE
xz --version                # 疑わしい版を自分で動かすことになる

JPCERT/CC は、侵害された版を使っている恐れがあるため、xz の命令で版を確かめず、包みの管理の命令を使うよう求めた[5]。openSUSE は、裏口の作りが巧みで、入ったかどうかを機械の上で見つけるのはおそらくできないと書いた[8]。疑わしい版を動かしていた機械は、調べて安心するより、入れ直して鍵を回す方を先にする。

どこで止められたか

保守、配布の束、配布元のビルド、依存の結び方、運用の5つの段に、それぞれ止める所を置く 保守 配布の束 配布元のビルド 依存の結び方 運用 1 保守者を1人にしない 支えを得て、急かす声で権限を渡さない 2 束とタグの差を見る git に無い変更は、それだけで止める理由 3 タグから作り、再現する 束を使わない。別の人が作っても同じになるか 4 入口に結ぶ依存を減らす sshd が圧縮の部品まで読み込む形にしない 5 振る舞いの違いを測る この件で実際に効いたのはここだけ
図4 段ごとの止める所
止める所この件で限り
保守者を1人にしない保守者は1人で、無償で、手が回らないと一覧に書いていた[11]。そこへ交代を迫る投稿が重なり、手伝いを申し出た者が共同の保守者になった[10][12]人を増やしても、増えた人が悪意を持てば同じ。権限を渡す前の確かめと、1人で版を出せない形が要る
束とタグの差を見るm4 の変更は git に無く、束にだけあった[1]。比べれば差として出たautotools の束は生成物を含むので、差がもともと多い。生成物を作り直してから比べる
タグから作り、再現するGitHub が自動で作るソースの束には、この行が無かった[1]。タグから作っていれば仕掛けは働かない本体は git にあった。git の中身を信じる限り、次の手口では git に入れられる
入口に結ぶ依存を減らす上流の OpenSSH は liblzma を使わない。配布元の当て布で sshd に届いた[1]依存を減らすのは届く道を減らすだけで、部品の悪意を消さない
振る舞いの違いを測るログインの0.5秒の遅れと valgrind の誤りで見つかった[1]偶然に近い。遅れが出ないよう作られていたら見つからなかった

この件のあと、上流の側でも入口の依存が減った。OpenSSH 9.8 は2024年7月1日に、libsystemd に依存しない独自の実装で systemd へ通知する機能を入れた[17]。systemd 256 は、liblzma などを、ふつうの共有ライブラリの依存から、要るときに dlopen で読む形に変えた[18]。

守り方

根本の直し方
  • 部品は、配布の束ではなく署名したタグから作る。束を使うときは、同じ版のタグと中身を比べ、git に無い変更があれば取り込まない。
  • ビルドを再現できるようにする。再現できるビルドとは、同じソース、同じ環境、同じ手順から、誰が作っても全部の成果物がビット単位で同じになることを言う[19]。作った人と別の人が作って一致を確かめれば、1人の作る人に裏切られても気付ける。
  • 版は意図して選んで固定し、出たばかりの版を本番に入れない。この件の版は、配布元の開発版と試験版にしか届かなかった[1]。
  • 認証の入口になるプロセスに結ぶ依存を減らす。sshd のような root で外を待ち受けるプロセスが、何の共有ライブラリを読み込んでいるかを ldd で棚卸しし、要らない物を外す。
  • 自社が頼る部品の保守の体制を見る。保守者が1人か、無償か、急に新しい人が権限を得ていないか。頼るなら、資金か人で支える。

束とタグを比べる 架空の部品 libfoo 2.1.0

curl -sO https://downloads.example.com/libfoo/libfoo-2.1.0.tar.gz
tar xzf libfoo-2.1.0.tar.gz
git clone --quiet --branch v2.1.0 https://git.example.com/libfoo.git libfoo-tag
git -C libfoo-tag verify-tag v2.1.0     # タグの署名を確かめる
autoreconf -fi libfoo-tag               # 生成物をタグから作り直す
diff -r -q --exclude=.git libfoo-tag libfoo-2.1.0

# 出力
Files libfoo-tag/m4/build-helper.m4 and libfoo-2.1.0/m4/build-helper.m4 differ
Only in libfoo-2.1.0: ChangeLog
  • 生成物は autotools の版で変わるので、差がすべて悪意とは限らない。差が出たファイルを1つずつ読み、説明の付かない差があれば、その束は使わない。
  • 比べて差を読む手間がかかるなら、束を使わずタグから作る方が早い。署名は、作った人を確かめる手段で、中身の安全の証明ではない。この件の束も、保守者の鍵で正しく署名されていた[2]。
緩和の策
  • 同じ操作の時間、CPU、メモリを測り続け、版を上げた前後で比べる。sshd のログインの時間のような入口の数字は、特に見る。
  • 開発版と試験版を、本番と切り離した所で先に動かし、valgrind やサニタイザで試験を回す。この件では、ここで出た誤りが手がかりになった[1]。
  • リポジトリに入る2進のファイルは、何のための物か、どう作ったかを添えさせる。作り方の分からない試験のファイルと、どの試験からも使われない試験のファイルを受け入れない。
  • 疑わしい版を動かした機械は、入れ直し、その機械から取れた資格情報を全部回す[8]。

AIが書く依存の変更

AIのコーディングの道具は、依存の版を上げ、ロックファイルを書き換え、試験のファイルを足す差分を、ためらわずに作る。この件の2つの入口は、どちらもその差分の形をしていた。

  • 試験のファイルを足すコミットは、2進のファイルの追加だけで、コードの差分として読める所が無い[15]。AIに差分を点検させても、2進のファイルの中身は読まれない。作り方を説明できない2進のファイルは、誰が足したかに関わらず止める。
  • 版を上げる差分は、版の数字とハッシュが変わるだけに見える。新しい版の束とタグの差、保守者の交代、公開からの日数は、差分に現れない。AIが出した版の上げは、人がその版の出どころを確かめてから入れる。
  • 存在しない部品の名前を先に登録される型と、足す差分で止めて確かめる手順は、AIが持ち込む部品の危険で扱う。

型としての整理は A03 ソフトウェアサプライチェーンの不備 の型2と型3に当たり、取り込む物を使う直前に確かめる考え方は A08 ソフトウェアまたはデータの完全性の不備 にある。

参照

  1. backdoor in upstream xz/liblzma leading to ssh server compromise Andres Freund、oss-security、2024年3月29日
  2. XZ Utils backdoor Lasse Collin、tukaani.org、2025年1月17日更新
  3. CVE-2024-3094 NIST NVD
  4. Reported Supply Chain Compromise Affecting XZ Utils Data Compression Library, CVE-2024-3094 CISA、2024年3月29日
  5. XZ Utilsに悪意のあるコードが挿入された問題 CVE-2024-3094 について JPCERT/CC CyberNewsFlash、2024年4月1日
  6. Urgent security alert for Fedora Linux 40 and Fedora Rawhide users Red Hat、2024年3月29日
  7. DSA 5649-1 xz-utils security update Debian、2024年3月29日
  8. openSUSE addresses supply chain attack against xz compression library openSUSE、2024年3月29日
  9. PATCH xz: Added .editorconfig file for simple style guide encouragement xz-devel、2021年10月29日
  10. Re: XZ for Java xz-devel、2022年6月7日
  11. Re: XZ for Java Lasse Collin、xz-devel、2022年6月8日
  12. Re: XZ for Java Lasse Collin、xz-devel、2022年6月29日
  13. Change the bug report address tukaani-project/xz、2022年11月30日のコミット
  14. v5.4.2 tukaani-project/xz、2023年3月18日のタグ
  15. Tests: Add a few test files tukaani-project/xz、2024年2月23日のコミット
  16. NEWS tukaani-project/xz
  17. OpenSSH 9.8 release notes OpenSSH、2024年7月1日
  18. systemd NEWS CHANGES WITH 256 systemd、2024年6月
  19. Definitions Reproducible Builds