飞牛 FnOS 定向攻击样本深度分析:一次内核级后门植入与持久化控制的完整解剖
事情是这样的:一台运行飞牛 FnOS 的 NAS 设备,某天凌晨开始持续向外网某 IP 发起加密心跳连接。管理员查了半天,没发现异常进程、没发现异常计划任务、磁盘也没多出可疑文件,要不是出口防火墙做了流量告警,这台机器可能到现在都不会暴露。顺着链路一通排查,最终在系统内核模块目录里挖出了一个伪装成硬件驱动的 .ko 文件——内核级后门,已经运行了将近三个月。
这篇文章就针对这个定向攻击样本做一次完整的技术复盘。说是“定向”,是因为样本针对的目标非常明确:飞牛 FnOS 这个基于 Debian 的 NAS 操作系统。攻击者专门分析了它的内核版本、服务框架和软件包管理机制,量身定制了一套从用户态到内核态的完整入侵链条。对安全从业者来说,这个样本的价值在于它不仅展示了经典的内核 Rootkit 思路,还叠加了针对 NAS 场景的持久化设计,其中的细节非常值得拆开讲清楚。
如果你是做蓝队防守、恶意样本分析、或者对 Linux 内核安全感兴趣,这篇分析应该能给你不少启发。我会从样本的初始突破、内核后门植入、持久化机制、检测思路和应急响应几个层面完整展开,并结合实际操作中的排查经验,尽量把每一个技术决策背后的逻辑都讲明白。
1. 样本整体画像与攻击链设计思路
1.1 攻击目标为什么选择 FnOS 和 NAS 场景
这个样本选择的目标非常聪明——NAS 设备在多数企业里处于“高权限但低关注”的尴尬位置。它存储着大量敏感数据,7x24 小时在线,资源占用偏高也不会引起注意,而且大部分 NAS 管理员对 Linux 内核层面的安全机制并不熟悉。飞牛 FnOS 基于 Debian,普通用户习惯用 Web 管理界面操作,很少会有人去检查内核模块加载情况,这不仅给攻击者留了入侵空间,也给了后门足够的藏匿时间。
从样本的功能设计来看,攻击者对系统相当熟悉。样本不是那种广撒网的自动化攻击工具,而是针对特定内核版本编译、针对特定系统框架设计的定制样本。它采用了模块化设计,一阶段负责初始加载和提权,二阶段(也就是核心的 .ko 文件)负责内核态的持久驻留。样本内部对系统有硬编码的判断逻辑,检测到目标环境不匹配时不会激活恶意行为,这种谨慎的设计也解释了为什么它能在目标机器上安静运行几个月不被发现。
1.2 攻击链路的完整还原
整个攻击链可以梳理成四个阶段。
初始突破阶段,攻击者锁定了 NAS 暴露在管理网段的 Web 管理端口,利用的是管理接口某个旧版本组件的历史漏洞完成 RCE。这个漏洞不属于零日,而是补丁管理疏漏导致的,如果管理员及时更新,整个攻击在第一阶段就会被阻断。通过漏洞拿到的是 www-data 权限,属于低权限 Web 服务账号。
权限提升阶段相对经典——利用系统内核版本的本地提权漏洞,配合一个 C 编写的提权辅助脚本,在十几秒内完成了从低权限用户到 root 的切换。这里有个值得注意的点:攻击者没有直接使用公开的提权 PoC 代码,而是做了混淆和修改,规避了基于特征码的检测规则。
后门植入阶段,这是整个攻击链的核心。攻击者编译并加载了一个恶意内核模块,这个模块同时具备 Rootkit 三件套能力——文件隐藏、进程隐藏、网络连接隐藏。它通过篡改系统调用表挂钩关键函数,并注册了伪装成硬件监控设备的中断处理函数。模块加载后主动清除自身的加载记录,从常规运维视角几乎无法察觉。
持久化控制阶段,模块内置了加密心跳机制,每隔一段时间向固定 IP 发起外连请求,等待攻击者下发指令。指令集包括文件读取、命令执行、流量转发等功能。同时,模块在文件系统和启动链路上分别做了持久化备份,防止模块被卸载之后失去控制权限。
1.3 关键样本指标的横向对比
把样本的核心特征做成一个对照表,可以更直观地看出它和普通 WebShell 类攻击样本的差异。
| 维度 | 常规恶意样本 | 本次 FnOS 定向攻击样本 |
|---|---|---|
| 攻击目标 | 泛化批量扫描,随机命中 | 明确针对 FnOS 系统定制 |
| 驻留位置 | Web 目录 / 用户态进程 | 内核态 LKM 模块 |
| 隐藏能力 | 文件伪装,进程名替换 | sys_call_table 挂钩,三合一隐藏 |
| 通信方式 | HTTP 明文回调 | 自定义加密心跳协议 |
| 持久化设计 | 计划任务 / 开机启动项 | 内核模块 + 用户态守护 + 启动链路 |
| 检测难度 | 常规杀软可查 | 传统文件扫描和端口检查基本失效 |
从这个表能看出来,这个样本在设计思路上已经把“隐蔽持久化”放在最高优先级,而不是追求功能的丰富性。这也符合定向攻击样本的一贯特点——只要控制通道不暴露,功能可以慢慢迭代。
2. 内核级后门植入的完整技术拆解
2.1 恶意内核模块的加载机制与伪装思路
攻击者拿到 root 权限后,首先做的是探测目标系统的内核版本和相关构建配置。恶意内核模块如果版本不匹配,加载时会直接报错,甚至导致内核崩溃。样本编译时采用了 Linux 内核模块的标准构建流程,并复制了对应内核版本的构建配置,确保生成的模块能干净通过校验。
为了让 .ko 文件看起来无害,它在命名和元数据上都花了心思。文件名为hw_monitor_v2.ko,伪装成硬件监控驱动,这类驱动在 NAS 设备上属于常识性存在。模块的module_init入口函数脱掉伪装后,首先执行一段反调试和反沙箱逻辑,检查当前环境是否存在常见调试接口,如果发现可疑环境,就释放内存并停止执行。这个反侦察逻辑,让早期测试人员在沙箱里运行时看到的只是一个加载即退出的“残缺驱动”。
加载执行上,攻击者刻意没有用常规的insmod命令,而是通过内核的模块加载接口直接调用,同时在加载前后对文件路径做了手脚,确保/proc/modules和lsmod命令的输出里看不到这个模块的痕迹。这种“加载即隐藏”的手法,确实比很多只知道挂钩文件操作的 Rootkit 高了一个段位。
2.2 系统调用表篡改与函数挂钩的实现细节
内核模块加载之后,首要任务是挂钩系统调用表,这个过程用到了两个关键技术点。
第一个是定位sys_call_table地址。现代内核默认对系统调用表做了只读保护,模块需要先修改相关寄存器的读写控制位,然后才能改写表项。样本内部内置了针对多版本内核的地址偏移表,加载时会比对当前内核版本并选择对应的偏移量,这是它在多台设备上都能稳定运行的关键。
第二个是挂钩函数的选择。样本挂钩了目录读取类系统调用、文件打开类系统调用、进程枚举类系统调用和网络连接枚举类系统调用。挂钩的核心套路都是同一套逻辑:先调用原始函数获得真实结果,然后对结果做二次过滤——把涉及恶意文件、恶意进程、恶意网络连接的信息从结果中剥离,再把处理后的伪造结果返回给上层调用者。
以目录读取为例,真实函数返回的是一个目录项列表,挂钩函数遍历这个列表,把包含hw_monitor文件名的目录项剔除掉。所有用户态工具包括ls、find、top和ss,拿到的都是过滤后的数据。这种挂钩的实现并不复杂,但效果非常实用——它不需要维护一个独立的隐藏列表,只需要在数据返回路径上做一道手脚。
2.3 更隐蔽的控制通道:中断处理函数和内核线程
样本没有满足于系统调用挂钩,它还用了一个更底层的手段:伪装成硬件监控设备的中断处理。系统里本来就存在大量硬件中断,攻击者通过伪造设备驱动注册了一个原本不存在的硬件中断向量。在实际触发时,设备会收到来自攻击者控制端构造的网络数据包,数据包被打上特殊标记后,会触发中断处理逻辑解析其中的指令并执行。
这个机制相当于在内核态建立了一条与系统调用完全无关的指令接收通道。常规的安全工具可能盯着网络连接、文件行为,但很难想到异常硬件中断会和指令执行扯上关系。样本还专门创建了一个内核线程用于周期性发送心跳,这个线程的进程名伪装成系统内核自带的回收线程,从/proc目录枚举进程时看到的是一个完全正常的名称。
2.4 针对多架构与多场景的兼容设计
考虑到 NAS 设备可能运行在 x86 和 ARM 多类硬件平台上,样本的架构兼容性也做得相当到位。它通过预编译方式同时构建了面向 x86_64 和 ARM64 两种架构的内核模块,植入阶段根据目标系统的实际架构自动选择对应版本。这类设计的成本是开发和维护工作量增加,但对攻击者来说,能覆盖更广的目标群体是划算的。
内核版本兼容性上,样本的地址偏移表覆盖了 FnOS 发行周期内的多个内核版本。如果目标内核版本不在兼容列表内,样本会尝试一种退化方案——通过解析内核符号表动态定位关键函数地址,而不是直接放弃安装。这种“硬编码优先、动态解析兜底”的思路,在实际攻击场景中显著提升了成功率。
3. 持久化控制机制的深度解析
3.1 多层持久化的设计哲学
持久化是所有后门的生命线,一次完整的定向攻击如果没有可靠的持久化机制,前面所有的入侵成果都可能因为一次重启而清零。这个样本在持久化上的设计很典型:不押注在单一机制上,而是做了多层冗余。
第一层是内核模块本身。如果系统不重启,模块会一直在内核里运行。第二层是用户态守护脚本,脚本运行时会周期性检查内核模块是否还在,如果发现模块被卸载,会尝试重新加载。第三层是启动链路的持久化——在内核模块被删除或加载失败的情况下,系统启动时仍然会通过预设的启动脚本重新下载并加载模块。三层机制互相兜底,单一手段的清理很难彻底解决问题。
3.2 用户态守护与自修复逻辑的对抗性
守护脚本的设计有很强的对抗意识。脚本本身没有放在常规的启动目录,而是伪装成系统硬件初始化脚本的一部分,通过增加一条日志轮转配置来隐藏自身存在。脚本每隔一段时间会检查后门模块的存在状态,具体检查方法不是用lsmod——因为该命令的输出已经被挂钩过滤了——而是直接尝试访问模块在内核文件系统中的节点,如果访问失败就说明模块不在,随即触发重新加载逻辑。
这种“丢弃默认命令、改用底层接口验证”的思路值得防守方警惕。不少防守策略假设恶意文件已经写入某个固定位置,只要定期覆盖删除即可,但遇到这种带自修复能力的后门,单纯靠手动清理几乎是做无用功。
3.3 心跳协议与指令下发机制的特点
心跳通信是后门与攻击者保持联系的主要方式。通信协议采用自定义加密格式,底层承载在标准 TCP 连接上,端口号和目标地址都内置在模块中。每次心跳包都包含一个时间戳和一个随机填充字段,用于保证数据包在网络流量中的辨识度极低。
指令下发机制支持三种核心操作:远程命令执行、指定文件读取回传、TCP 流量中转。远程命令执行的结果通过同一加密通道回传,整个过程不会在目标系统上留下常规 shell 操作痕迹。文件读取功能针对的是 NAS 环境中的敏感数据文件,攻击者甚至不需要进入系统就能批量获取。流量中转功能则是把受控机器变成跳板机,用于内网横向移动时隐藏真实来源。
3.4 清理难度评估:为什么常规手段很难根治
尝试清理这个后门时会发现,难点不只是找到并删除文件,而是要面对一个“连锁反应”式的对抗流程。直接尝试卸载内核模块,模块的退出函数会先检查守护脚本是否在运行,如果发现守护脚本被一并清除,模块会选择忽略卸载指令继续驻留。更麻烦的是,模块的内存代码做了校验和完整性检查,如果被尝试修改关键字节,模块会自动触发内核崩溃——这部分是防拆卸机制的一部分。
也就是说,防守方如果想要彻底清理,必须在同一时间窗口内同时完成模块卸载和守护脚本清理,并且要在模块的自我保护机制触发前完成操作。这个操作窗口极短,缺乏经验的操作者很容易在清理过程中直接让系统宕机。
4. 检测识别与安全加固的落地实践
4.1 文件与内核层面的检测思路
针对这类内核级后门,常规的安全软件基本无能为力,因为它们检测的是用户态的可疑行为。最有效率的检测路径是从内核层面入手。
一个值得做的事是对照内核模块的加载记录。虽然攻击者做了加载痕迹清除,但从内核构建信息里比对当前已加载模块列表,依然能发现“模块存在但记录缺失”的异常缺口。定期检查/sys/module目录下的模块节点信息,对比/proc/modules的输出,如果出现两边不一致的情况,说明有模块在试图隐藏自己。
系统调用表完整性校验也是一种有效检测方式。通过对比系统调用表的当前内容与内核符号表中记录的原始地址,可以快速定位被挂钩的调用项。这个方法需要在干净系统上提前建立指纹基线,在安全事件发生后直接对照差异,能极大缩短排查时间。
4.2 网络层面与行为层面的检测方案
网络层面的检测是这个样本的软肋。心跳行为虽然做了加密,但通信模式依然有规律可循:周期性的小包交互、固定的目标 IP、闲时无流量但忙时有突发流量。这些特征在长时间的网络流量记录中相当突出。因此,在部署了流量审计系统的环境里,建议专门针对内网设备检查是否存在周期性的外部连接。
行为层面的检测关注的是系统行为异常。正常的 NAS 设备不会在凌晨持续产生加密外连流量,更不会出现内核模块文件被反复读写的情况。文件完整性监控系统如果覆盖了内核目录,会对 .ko 文件的任何变更给出告警,这是提前发现后门的重要防线。
4.3 面向 FnOS 环境的加固实践清单
针对这类攻击样本,有几条加固措施可以直接落地。
第一条是严格收敛暴露面。NAS 的管理端口不应该直接暴露在不可信网络,尽可能通过带外管理网络或至少加一层访问控制授权。这类定向攻击大多来源于管理端口开放,这一条做好,能挡掉大部分初始突破尝试。
第二条是建立内核模块白名单。生产环境的 NAS 设备所加载的内核模块应该是可预期、可枚举的。定期对/proc/modules做快照,与基线比对,新增模块必须有变更记录支撑,否则就要告警复核。
第三条是日志外发与不可变存储。攻击者清理了本机日志,但如果关键日志实时外发到独立的日志服务器,防守方依然能还原攻击链路。尤其要关注内核日志中关于模块加载的异常信息、认证日志中的异常登录记录。
4.4 典型排查命令与基线比对方法
这里整理一组实操可用的排查命令。
- 检查已加载模块与模块目录的差异:列出模块目录下所有文件再与模块加载列表比对。
- 检查启动链路的异常脚本:重点看启动目录和硬件初始化脚本目录,比对脚本内容与系统默认模板的差异。
- 检查网络连接的可疑外连:过滤出所有外部 IP 的非标准端口连接,与业务白名单交叉比对。
- 检查系统调用表完整性:使用内核调试接口导出当前系统调用表内容,并与已知的干净基线做哈希比对。
这些命令单独看都不复杂,但组合起来能在较短时间内覆盖后门的主要暴露维度。关键在于建立比对基线,没有基线的检查只能靠经验判断,效率会低很多。
5. 应急响应的实操经验与复盘
5.1 发现阶段:从可疑心跳到确认入侵
这次事件的发现源于出口防火墙的流量告警。告警规则本身并不复杂——内网设备持续在每隔固定时间向外网发起小流量连接,目标 IP 不属于业务白名单。值班人员最初以为是系统更新或者是时间同步协议,但进一步检查发现连接持续性和目标地址都不符合正常服务特征,这才启动了应急流程。
初期排查花了较长时间,原因是常规手段全部被后门隐藏机制干扰了。进程列表里没有可疑进程,监听端口里没有可疑端口,文件系统扫描也没有发现异常大文件或近期被修改的可疑文件。直到在内核模块层面做差异比对时,才定位到那个伪装成硬件驱动的恶意模块。整个过程给了一个很重要的教训:当常规排查手段全部指向“干净”时,就应该考虑内核层面是否被做了手脚。
5.2 隔离与取证:如何在保全证据的同时控制影响面
确认内核模块是后门之后,第一优先级是隔离,防止攻击者继续通过后门下发指令。由于心跳是对外连接,断网能直接切断指令通道,但同时也会让防守方失去观察攻击者行为的机会。实际操作中,如果条件允许,优先在网关做精细的流量控制——只阻断与该后门通信 IP 的流量,保留其他对外连接,这样既隔离了威胁,也保留了后续分析的冗余。
取证环节的核心是保全内核模块文件。直接复制.ko文件还不够,模块已经加载进内核内存,运行时的数据结构和挂钩状态需要另外提取。在实际操作中,应优先对内存做完整镜像,再冻结文件系统并复制模块文件。后续分析在独立的分析环境中完成,避免在受害机器上执行过多操作破坏现场。
5.3 清理顺序与自我保护机制避坑指南
清理这个后门,顺序决定成败。正确顺序是先切断外连通道,再清理用户态守护脚本,最后才卸载内核模块。如果先卸载内核模块,守护脚本会在短时间内把它重新加载回来,清理等于白做。更严重的是,如果尝试直接修改模块文件或内存中的关键字节,模块的保护机制可能触发内核崩溃,导致业务中断和数据丢失。
比较稳妥的操作是在系统进入单用户模式后进行处理,尽可能减少干扰因素。单用户模式下大部分用户态服务和脚本不会自动运行,这为清理守护脚本和卸载模块争取了窗口时间。清理完成后,还要对所有账号口令做一轮强制轮换,因为攻击者在驻留期间完全可能通过其他方式获取到凭据。
5.4 复盘视角:这类攻击为何能潜伏这么久
这次攻击能潜伏近三个月,核心原因不在于攻击手法有多么无解,而在于环境的检测盲区太多。NAS 设备的管理员通常更关注存储状态和共享权限,对系统底层的安全事件关注度很低。内核模块加载这种值得告警的事件,在多数环境里既没有监控也没有响应机制。
另一个原因是设备长年运行,系统更新和补丁管理滞后。初始突破利用的漏洞如果及时修复,整个攻击链根本就走不到内核后门这一步。安全工作的本质是平衡成本和风险,把高价值设备的补丁管理、日志监控和异常行为告警做到位,这类深度攻击的生存空间会被大幅压缩。
6. 样本溯源线索与检测特征整理
6.1 模块内部的技术指纹与身份标识
遍历和梳理模块内部细节时,有几个技术指纹非常关键。模块的字符串表里包含一串交叉编译环境路径信息,指向的是模块开发者在构建系统中使用的工作目录。虽然开发者在命名上做了伪装,但构建路径信息仍然暴露了原始开发环境的一部分结构。
模块还内置了一组针对当前系统内核版本的哈希值,用于加载时快速校验内核版本匹配性。通过比对哈希值,可以侧面确认这套样本对目标系统内核版本的适配做过专门研究。这类细节的价值在于,它们可以为追踪溯源提供线索——哪个团队、哪套工具链、哪些系统版本在目标范围内,都能从样本中读到大量隐含信息。
6.2 网络通信特征与威胁情报对接
从网络流量角度提取 IOC(入侵指标),最直接的是心跳连接的目标 IP 和通信端口。这里的端口不是固定的,模块后续版本支持随机化端口策略,这给基于五元组的流量检测带来了一定阻力。建议把检测重点放在行为模式上,尤其是连接的周期规律和包长度的稳定性,这类特征不受端口变化影响。
把模块哈希值和通信行为特征上传到威胁情报平台,可以帮其他组织提前发现自身环境内是否存在同类样本。定向攻击有针对性的特点决定了它是可复用的——同一套样本会被用于攻击多台同类设备,IOC 的共享价值很高。
6.3 构建对应的检测规则集建议
综合样本行为,可以产出至少三类检测规则。内核模块的加载结果与模块目录快照不一致,是后门隐藏行为最明确的上报信号。周期性外连且连接频率、包大小保持稳定的行为模式,高度疑似心跳通信。内核目录中近期出现新增文件且没有对应变更记录,属于重大告警,需优先纳入重点关注清单。
这三类规则都可以用常见的审计工具实现,关键是定期跑、基线要新。安全不是一锤子买卖,也不是装一套产品就万事大吉,环境在变、基线在变、攻击也在变,只有持续运行和更新规则才能真正守住边界。
7. 从单点样本看攻击趋势:设备固件类后门的演进方向
7.1 从 WebShell 到内核态的进化路线
传统 Web 攻击留下的后门多存在于应用层,安全设备基于文件扫描和行为分析就能覆盖绝大多数场景。但当攻击者把后门下沉到内核态之后,用户态的一切检测工具都变成了“不可信数据源”,因为它们拿到的数据已经过了后门挂钩函数的过滤。这种“向下走”的思路,是近年来定向攻击中越来越明显的趋势。
这次样本的进化之处在于对设备特性的利用。NAS 设备本身的硬件监控驱动、内核模块加载行为都是常态,攻击者在这样的背景噪声里做伪装,防守方很难单凭“有模块加载”就判定为恶意。如果没有自动化基线和异常的持续跟踪,这种隐蔽性会让后门存活周期远超传统 WebShell。
7.2 NAS 场景必然成为重点目标
NAS 在家庭和企业中的普及率越来越高,存储的数据价值也越来越高。这类设备本质上是一台常开服务器,有着足够的计算能力、网络带宽和存储空间,但又缺乏常规服务器的安全运维投入。攻击者把 NAS 当成目标,等于同时拿到了“高价值数据 + 稳定跳板”两个收益。
对厂商而言,这类事件提示了设备固件安全和系统基线管理的重要性。安全能力不能只停留在 Web 管理界面的认证强度上,需要深入到系统内核模块、启动链路、固件更新机制等底层维度。安全设计上至少要保证,“即便应用层失守,内核层也不应该被轻松植入恶意模块”。
7.3 防守方可以借鉴的成熟思路
从防守角度看,要应对这类越来越底层化的攻击手法,单纯依赖单一安全产品是不现实的。更成熟的做法是建立多层防御体系:边界侧收敛攻击面、主机侧建立基线监控、网络侧持续追踪异常行为、在响应侧准备专门的对抗预案。每一层都有自己的检测盲区,但层与层之间的盲区错位,恰好形成了一张纵深防御的网。
设备厂商、管理员和安全研究者之间的信息共享也很重要。定向攻击样本通常不会只出现在一个目标上,如果在情报共享平台上广泛扩散样本特征和 IOC,其他环境可以提前发现和控制同类威胁。安全对抗本质上是一场信息差博弈,谁掌握更多样本特征,谁就能在防御中占据主动。
8. 最后总结一点实战体会
把这次分析从头回顾一遍,我最大的一个感触是:大多数被深度入侵的系统,问题都不是出在攻击者技术有多强,而是防守方在基础运维上留了太多口子。补丁不更新、管理端口暴露、日志不存留、基线不建立,每一条单独拿出来都不是什么大问题,但叠加在一起,就为一次本来成功率不高的定向攻击铺好了路。
这个样本的设计确实精巧,尤其是内核态后门加多层持久化的组合,给了防守方很大的压力。但换个角度看,如果环境从一开始就具备完整的内核模块基线、严格的端口收敛和日志外发能力,攻击链路大概率会在初始突破环节就被拦截或阻断。安全建设是一个性价比问题,投入在关键节点的成本,换来的回报往往是倍数级的。
最后再补充一个实操技巧:在常规排查完全无果的情况下,不要忽略内核模块目录对比这种“笨办法”。很多时候看起来最朴素的手段,反而是发现高级后门最有效的切入口。安全分析没有银弹,有的只是在正确的位置持续做正确的事情。