群晖DiskStation漏洞利用:从CVE-2024-10442到远程代码执行

群晖DiskStation漏洞利用:从CVE-2024-10442到远程代码执行

原创 GKDf1sh 山石网科安全技术研究院 2025-06-03 09:11

图片

群晖DiskStation漏洞利用:从CVE-2024-10442到远程代码执行 -2



如何从简单的空字节写入漏洞演变为远程代码执行的致命攻击?



图片

在网络安全领域,每一个新发现的漏洞都可能成为攻击者手中的利刃。2024年10月,安全研究人员在群晖科技(Synology)的DiskStation DS1823xs+型号设备上发现了一个严重的安全漏洞(CVE-2024-10442)[1],允许攻击者以root用户身份远程执行代码。这一发现不仅揭示了群晖DiskStation在安全性上的潜在风险,也对广泛部署该设备的组织和个人用户敲响了警钟。

图片

一、背景

10月份,作者参加了Pwn2Own Ireland 2024,并利用了一个漏洞成功攻破了群晖DiskStation DS1823xs+,实现了以root权限执行远程代码。目前该漏洞已被修复,漏洞编号为CVE-2024-10442。

DiskStation是群晖科技(Synology)推出的一款广受欢迎的NAS(网络附加存储)产品系列。在过去几次Pwn2Own活动中,它也曾被成功攻破过几次,但在去年的活动(Pwn2Own Toronto 2023)中未被成功攻破。2024年的Pwn2Own Ireland,有三个攻击案例成功了,并且每支队伍都利用了不同的漏洞。

本文将详细介绍作者研究Synology DiskStation的过程,以及为此次比赛编写漏洞利用程序的经历。

图注:准备向Synology DiskStation发起攻击——Pwn2Own Ireland 2024

图片

二、审计软件包


如前所述,在过去一两年的Pwn2Own活动中,群晖DiskStation均未被选手攻破。因此,2024年ZDI(Zero Day Initiative)特别将一些非默认但由Synology官方开发的软件包纳入比赛目标范围:

对于目标群晖DiskStation来说,以下这些软件包被安装在目标上,并且属于比赛范围内:
– MailPlus

  • Drive

  • Virtual Machine Manager

  • Snapshot Replication

  • Surveillance Station

  • Photos

这里的“软件包”指的是可通过Synology管理界面(DiskStation Manager)中的“套件中心”(Package Center)便捷安装的可选附加应用/服务等。

这也意味着更大的攻击面。由于这是这些软件包首次被纳入比赛范围,作者推测它们可能存在相对基础的安全漏洞——毕竟这些组件此前可能未经过充分的安全性审查。事实也证明这一判断完全正确。

作者首先研究的是Virtual Machine Manager(虚拟机管理器),通过物理设备上的内置“套件中心”直接安装该软件包。

群晖DiskStation漏洞利用:从CVE-2024-10442到远程代码执行 -6

随后,作者通过SSH登录测试设备的Shell接口,利用netstat
命令枚举新增的网络监听端口。结果显示,大部分服务仅绑定于本地回环接口(localhost-only),但有一个服务例外,它以root权限运行着:

/var/packages/ReplicationService/target/sbin/synobtrfsreplicad  --port 5566

该服务实际属于Replication Service(复制服务),它是Virtual Machine Manager的依赖组件(同时也是Snapshot Replication的依赖组件)。考虑到其高权限级别及与服务通信的便捷性,作者对其产生了浓厚兴趣。

群晖DiskStation漏洞利用:从CVE-2024-10442到远程代码执行 -7

下一步是分析二进制文件。由于作者在真实设备上安装了该服务,因此可通过SSH直接提取相关文件。

另一种方法是直接从Synology官网下载[2]DSM(系统核心操作系统)及软件包的安装文件。随后使用专用解压工具[3]解析Synology自定义的存档格式,提取其中的软件包、固件镜像或更新文件。需要注意的是,此类工具本质上是基于Synology官方共享库的FFI封装器(FFI wrapper),这些库文件可从真实设备中提取,或通过分离工具[4]从DSM固件中分离。

图片

三、寻找漏洞

在获取到二进制文件后,开始分析监听端口5566的TCP服务。主程序synobtrfsreplicad
仅是一个用于调用libsynobtrfsreplicacore.so.7
中功
能的驱动程序适配层。

该服务是一个基于L
inux的forking server,主进程持续调用accept()
并通过fork
创建子进程来处理每个新连接的客户端。随后,子进程运行一个基础命令循环(command loop),解析接收到的消
息:

每条命令采用简单的二进制格式,包含操作码(opcode)和可选的变长数据负载

unsigned cmd    // 命令操作码unsigned seq    // 序列号unsigned lenchar data[len]

为了解析此类命令消息,定义了两个全局结构体:

1.一个用于存储命令本身;

2.另一个类似环形缓冲区(ring-buffer-esque)的结构,可容纳最多3个变长命令负载:

struct {    unsigned char sector;      // 环形缓冲区索引    char bufs[3][65536];       // 3 个负载的缓冲区    unsigned buf_lens[3];      // 每个负载的实际长度} g_recvbuf;struct {    ReplicaCmdHeader header;    // 操作码、序列号、长度    char *data;                // 指向 g_recvbuf 中某个缓冲区} g_cmd;

命令循环的核心逻辑如下:

void runcmdloop() {    while(1) {        g_cmd.data = g_recvbuf.bufs[g_recvbuf.sector];        int err = recvcmd(&g_cmd);        if (err) break;        // 错误则退出循环        g_cmd.data[g_cmd.header.len] = 0; // 在负载末尾添加空字符终止符        // ... 处理命令 ...    }}// 接收消息头和负载的函数int recvcmd(ReplicaCmd* cmd) {    int err = raw_tcp_recv(cmd->header, 12); // 先接收前 12 字节头    if (err) return err;    if (cmd->header.len > 0x10000) return err; // 若负载长度过大则返回错误    // 接收实际负载数据    err = raw_tcp_recv(cmd->data, cmd->header.len);    // ...}

若攻击者提供的负载长度超出限制(如大于0x10000),recvCmd

直接返回错误码(即非零值)而不接收任何数据。然而,其返回值被设计为0(表示无错误),这一行为存在矛盾——实际上,当检测到无效的头长度时本应触发错误。回到调用方后,由于未感知到错误,程序继续正常执行,将任意大的头长度值用于在负载末尾写入空字节。

对于初始概念验证(POC),可通过netcat

送全为’A’
的数据包(至少12字节),以经典方式触发漏洞。此时:
– 若未通过gdb
附加服务调试,设备上不会显示任何异常

  • 故障信息既未记录到syslog
    ,也未出现在DSM日志中;

  • 由于服务器采用forking mode运行,服务功能亦不会中断。

此漏洞允许重复向共享库的BSS段(数据段)中任意偏移量写入空字节(null byte),类似于CTF题目中的常见技巧。尽管漏洞本身较为简单,但其利用过程颇具挑战性。

此外,由于所有防护机制(如ASLR、DEP)均启用,作者优先将其转化为信息泄露漏洞(info leak)

图片

四、forking server

在深入分析前,需明确我们面对的是一个
forking server
,其特性对绕过ASLR(地址空间布局随机化)具有重要意义。每当服务器通过fork()
创建子进程处理客户端请求时,子进程会继承父进程的完整地址空间布局。即使子进程崩溃,也不会导致整个服务中断——只需重新连接即可触发新子进程的创建,相当于重置状态并获得一次新的尝试机会。这种机制类似于“时间循环”,每次连接都能以累积方式逐步推断地址空间的细节。

从高层次来看,漏洞利用的迭代流程通常包含以下步骤:

1.猜测目标值(如内存地址)

2.让程序基于猜测值执行操作
,若猜测错误则触发异常行为(如地址无效导致崩溃)

3.观察程序行为判断猜测是否正确

4.若

功,则确认目标值;否则重复上述流程。

这一思路将在后续分析具体二进制文件时得到体现。

图片

五、功能概述

由于当前漏洞发生在输入解析阶段,作者尚未深入分析程序的核心功能,但这些功能将在后续构建漏洞利用链时发挥关键作用。

从网络读取命令后,服务通过switch-case
语句处理不同的操作码(opcode)。部分需要输入的操作码会从变长的命令负载中解析数据。作者遍历了所有可用操作码及其功能:
– CMD_DSM_VER
:无输入,返回DSM版本号

  • CMD_SSL
    :初始化SSL连接

  • CMD_TEST_CONNECT / CMD_NOP / CMD_COUNT / CMD_CLR_BKP / CMD_SYNCSIZE / CMD_END
    :无需特殊输入

  • CMD_VERSION
    :输入整数,用于设置连接的兼容版本

  • CMD_TOKEN
    :输入字符串”token”,需存在于磁盘上的JSON文件中;该命令会初始化全局变量 std::string g_token

  • CMD_NAME
    :输入字符串”name”,可能触发btrfs相关操作,并/或利用g_token
    修改JSON文件

  • CMD_SEND
    :输入原始数据,代理至文件描述符(疑似预置的btrfs命令管道)

  • CMD_UPDATE / CMD_STOP
    :输入token字符串,用于删除JSON中的对应条目

显然,许多代码路径依赖于提供有效的”token”。该token需预先存在于/usr/syno/etc/synobtrfsreplica/btrfs_snap_replica_recv_token
的JSON文件中。此JSON文件以键值对形式存储属性,其中token是键:

{    "<token>": {"<attribute>": value, ... other attributes ...},    ... other tokens ...}

推测某些外部服务会分发此类token并写入文件,但具体实现尚不明确。

然而,有一个代码路径可能被非预期地利用:CMD_NAME
操作码使用当前g_token
并向JSON写入属性,其行为有两个关键点:

1.未验
g_token是否已初始化
(即是否调用过CMD_TOKEN
);

2.若token尚未作为键存在,则创建新键并写入属性

通常情况下,未初
始化的g_token
为空字符串,但在内存破坏(memory 
corruption)场景下,这一限制失效,将在后续分析中看到这一特性的实际应用价值。

图片

六、ASLR Oracle


(一)释放伪造的堆块

图片

作者的原始漏洞是一个空字节写入(null byte write)
,攻击者可以通过提
供任意偏移量向命令负载缓冲区写入空字节。由于偏移量为无符号整数,只能覆盖位于负载缓冲区之后的内存区域。

负载缓冲区后紧跟的是共享库BSS段中g_recvbuf
全局变量的三个0x10000 字节缓冲区之一。除了少量std::string
实例外,此处没有其他全局变量。std::string
的结构如下:

struct std::string {    char* ptr; // 对于短字符串,指向 inline_buffer    unsigned long length;    char inline_buffer[16];}

默认构造函数会将长度设为0,并将ptr
指向inline_buffer
。换句话说,BSS中的std::string
实例会拥有指向自身BSS地址(加上偏移量16)的指针。

如果利用空字节写入漏洞,将某个std::string
指针的低2字节置零,则前一个0x10000字节的负载缓冲区足以保证该指针指向缓冲区内某一位置(尽管具体偏移未知)。由于ASLR的粒度为页级(12位),此偏移量的熵值集中在4位(即可能为0x0000
,0x1000
,…,0xf000

其中一个可篡改的全局字符串是_gSnapRecvPath
,其可通过CMD_NAME
命令重新赋值。当重新分配std::string
时,若ptr
不指向inline_buffer
,则会对旧值调用delete
。这允许对伪造的堆块调用free
,而负载缓冲区的内容可控。

当free
被触发时,若伪造的堆块大小合法,则会被放入glibc的tcache;若大小非法(如零),则调用abort
导致进程崩溃。这一行为构成了第一个“Oracle”(验证机制),结合forking server的特性,现在可以遍历所有16种可能的偏移量:

1.在负载缓冲区填充至猜测偏移处,随后放置伪造的堆块元数据(仅伪造大小
);

2.触发两次空字节写入,将_gSnapRecvPath
的指针

2字节置零;

3.使用CMD_NAME
释放被篡改的ptr
,若连接保持活跃且收到响应,则猜测偏移正确;若连接关闭(即触发abort
),则继续尝试下一偏移。

通过此流程,解析了一个ASLR熵值的nibble(半字节),并可靠地将伪造堆块放入tcache。

(二)泄露Token

图片

tcache是由自由堆块组成的单链表,每个堆块包含next

针。由于glibc的加
固机制,该指针的实际存储方式为:

chunk->next = (&chunk->next >> 12) ^ next

在此案例中,tcache初始为空(next=0
),因此写入的值为&chunk->next >> 12
——即将BSS段指针右移12位后存入负载缓冲区。目前需要找到一种方法泄露此值。

在伪造堆块被释放后,作者将第二个全局std::string
(g_token
)的指针低2字节置零,使其指向与_gSnapRecvPath
相同的位置(即右移后的BSS指针)。结合CMD_NAME
的功能(将未初始化的g_token
写入JSON文件),此时JSON中会记录右移后的BSS指针值。

此外,可在写入磁盘前多次触发空字节写入,截断该指针的不同片段。例如,若指针为0x766554433
,则可逐段写
入33、3344


整的3344556607

一旦JSON包含泄露的指针值,即可调用CMD_TOKEN
验证token是否存在。

根据返回的错误码差异,可
实施逐字节暴力破解:

1.循环遍历指针的每5个字节(b从0到4);

2.截断指针至当前长度b+1,写入JSON;

3.遍历可能的字节值(0-0xff)发送CMD_TOKEN
请求,观察响应确定正确字节;

4.重复直至完整解析右移后的
BSS指针。

最终,我们获得了共享库的基地址,进而推导出所有 mmap 映射(包括 libc)的地址。

图片

七、劫持控制流


在获取地址泄露后,我们已准备好构建最终载荷以劫持程序控制流。

现在已能通过CMD_SEND
在负载缓冲区中释放伪造堆块,并通过后续命令任意篡改其内容。此时可标准利用tcache链表机制:

1.篡改伪造堆块的next
指针为任意地址;

2.申请与伪造堆块相同大小的对象,malloc
会返回伪造堆块并将tcache头指
针更新为该任意地址;

3.再
次申请

同大小对象,malloc
将返
回任意地址。

幸运的是,CMD_TOKEN
处理逻辑恰好匹配这一模式。当两次分配完成后,包含用户输入参数的std::string
被析构,触发对受控字符串的delete
调用。

由此形成以下攻击策略:

1.将伪造

tcache
堆块next
指针指向共享库GOT表中delete
的入口地址
附近

2.发送CMD_TOKEN
命令,其处理流程会从被篡改的tcache分配两次内存,最终将delete
的GOT条目覆盖为system
函数地址;

3.后续析构函数调用delete
时,实际执行system
并传入受控的输入字符串。

至此,攻击者可直接执行/bin/sh
并将标准输入/输出重定向至当前连接的客户端套接字(无需反向连接)。

完整漏洞利用代码已公开。

图片

八、漏洞修复



漏洞被编号为CVE-2024-10442。群晖于2024年11月5日(Pwn2Own Ireland事件发生于10月22日)快速发布针对复制服务的补丁。补丁修改了recvCmd
函数,当检测到头部长度过大时返回错误码而非0:

if (cmd->header.len > 0x10000)    return 1; // 替代原先的 return 0

调用方据此检测错误并终止无效命令的处理流程。

图片

九、总结

****## 尽管此漏洞易于发现,但利用过程颇具挑战性。空字节写入的原始能力较弱,更接近CTF风格的题目设计,而tcache操控与暴力破解Oracle的组合也延续了此类题目的特征。

更值得关注的是,即使漏洞存在于非默认安装的组件中,其暴露于网络且以root权限运行的特性仍构成重大风险。考虑到Synology是广泛用于消费级与企业场景的NAS设备,且设备常暴露于互联网环境,此类简单漏洞的存在令人担忧。

图片

十、相关链接


[1]https://blog.ret2.io/2025/04/23/pwn2own-soho-2024-diskstation/

[2]https://www.synology.com/en-us/support/download

[3]https://github.com/K4L0dev/Synology_Archive_Extractor

[4]https://github.com/technorabilia/syno-extract-system-patch

图片

山石网科是中国网络安全行业的技术创新领导厂商,由一批知名网络安全技术骨干于2007年创立,并以首批网络安全企业的身份,于2019年9月登陆科创板(股票简称:山石网科,股票代码:688030)。

现阶段,山石网科掌握30项自主研发核心技术,申请560多项国内外专利。山石网科于2019年起,积极布局信创领域,致力于推动国内信息技术创新,并于2021年正式启动安全芯片战略。2023年进行自研ASIC安全芯片的技术研发,旨在通过自主创新,为用户提供更高效、更安全的网络安全保障。目前,山石网科已形成了具备“全息、量化、智能、协同”四大技术特点的涉及
基础设施安全、云安全、数据安全、应用安全、安全运营、工业互联网安全、信息技术应用创新、安全服务、安全教育等九大类产品服务,50余个行业和场景的完整解决方案。

图片