EDR的“自毁”开关"

admin 2026-10-22 06:29:30 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

cover_image

不是 0day,不是提权,不是远程攻击。只是一个本地普通用户,对着文件系统狂写、狂删、狂重命名,终端安全软件的监控模块就自己卸了。

参考原文:Trend Micro Deep Security Agent Research by 0xMatheuZ


你家的防盗门,被敲门敲到自动打开

近日,安全研究员 0xMatheuZ 公开发布了一份针对 Trend Micro Deep Security Agent(趋势科技深度安全代理)Linux 版本的安全研究报告。

报告揭示了一个令人意外的安全缺陷:在特定条件下,这款企业级端点安全产品会主动卸载自身的关键内核监控模块,从而在攻击者可控的情况下制造出可被利用的防护空窗期。

想象一下这个场景:

你家装了防盗门,门上有传感器,有人在撬门、砸窗、乱晃,传感器都会报警。但有一天你发现,只要用一个机械臂以极高频率反复敲门——不是撬,就是正常的敲——防盗门的传感器就过热重启了。在它重启的那几秒里,你干什么它都看不见。

这不是小说。这就是安全研究员 0xMatheuZ 对 Trend Micro Deep Security Agent 做的一次安全研究。

他用一个本地普通用户权限的进程,生成了大量文件写入、重命名、符号链接、进程创建和退出事件。结果,Trend Micro 的内核监控模块自己把自己卸载了。

没有 root 权限。没有内核漏洞。没有崩溃。

是安全产品自己的恢复机制,主动执行了 rmmod。


模块是怎么自己消失的

先理解一下 Trend Micro 在 Linux 上的监控架构。它有两个关键内核模块:

tmhook:通用系统调用钩子层。用 Linux livepatch 机制挂在系统调用路径上。

bmhook:行为监控模块。依赖 tmhook,负责真正的事件分析、队列、扫描、上报。

简单说:tmhook 是\"耳朵\",bmhook 是\"大脑\"。所有用户态的系统调用,先经过 tmhook 这个耳廓,再传到 bmhook 这个听觉中枢。

关系的静态证据在模块符号里很清楚:

bmhook_add_hook()
  -> tmhook_register_hook()
  -> syscall dispatch path

然后研究者做了什么事呢?他写了一个 PoC,在 /dev/shm 下疯狂制造文件事件:创建、写入、截断、重命名、符号链接、fork 子进程再退出。64 个 worker 同时跑,每个管 512 个文件。

一开始只是正常的资源压力——dmesg 里出现 fork 压力、perf 降采样率。然后,真正有趣的东西出现了:

livepatch: 'tmhook': starting unpatching transition
livepatch: signaling remaining tasks
livepatch: 'tmhook': unpatching complete
tmhook: tmhook 1.2.2129 unloaded

模块没了。


深入 PoC:这个\"敲门器\"到底长什么样

此节为技术深潜,面向想自己复现或理解攻击面的读者。如果你只关心安全影响,可以直接跳到下一节。

作者没有公开完整的 PoC 源码,但给出了足够让有经验的 Linux 研究人员自己写出来的细节。这种做法本身就值得认可——提供可验证的技术细节,却不给脚本小子一键武器化的工具。

命令行参数

./exploit /dev/shm/trend-poc 6006451244
参数 值 含义
工作目录 /dev/shm/trend-poc tmpfs 内存文件系统,避免磁盘 I/O 瓶颈,纯粹压测内核事件路径
运行时长 600 600 秒(10 分钟),足够触发阈值
worker 线程 64 文件事件工作线程
每 worker 文件数 512 64 × 512 = 32768 个文件被反复操作
fork 线程 4 专门制造进程创建/退出事件
symlink 线程 4 专门制造符号链接操作

它到底干了哪几件事

PoC 同时执行七类操作,每一类都精准命中行为监控的关注点:

操作 行为 为何命中监控
write + truncate 写入文件内容后截断 文件内容变化
close + reopen 反复关闭和重新打开 文件句柄生命周期
rename 重命名文件 文件元数据变化
symlink + unlink 创建符号链接后立即删除 文件系统拓扑变化
fork + exit 创建子进程后立即退出 进程生命周期
open + read + close 打开、读取、关闭 文件访问事件
批量创建 每个 worker 处理 512 个文件 增加总事件密度

没有什么\"高级漏洞利用技术\"。就是大量、高频、覆盖多个监控路径的普通操作。

核心代码骨架

模块监控线程——每秒读一次 /proc/modules,检测 bmhook/tmhook 是否消失:

void*monitor_thread() {
    while (running) {
        // 读 /proc/modules,检查 bmhook 和 tmhook
        FILE*fp=fopen(\"/proc/modules\", \"r\");
        while (fgets(line, sizeof(line), fp)) {
            if (strstr(line, \"bmhook\")) bmhook_ok=1;
            if (strstr(line, \"tmhook\")) tmhook_ok=1;
        }
        fclose(fp);

        if (!bmhook_ok||!tmhook_ok) {
            // 检测到盲区!此时可以执行本来会被拦截的操作
            perform_action_during_window();
        }
        sleep(1);
    }
}

文件 worker 线程——对每个文件反复执行 create/write/truncate/rename/read/unlink:

void*file_worker(void*arg) {
    charpath[256];
    for (inti=0; i<512; i++) {
        sprintf(path, \"%s/file_%d_%d\", base_dir, worker_id, i);

        intfd=open(path, O_CREAT|O_WRONLY, 0644);  // 创建
        write(fd, data, 4096);                            // 写入
        close(fd);                                        // 关闭

        truncate(path, 1024);                             // 截断

        charnewpath[256];
        sprintf(newpath, \"%s/file_%d_%d.renamed\", ...);
        rename(path, newpath);                            // 重命名

        fd=open(newpath, O_RDONLY);                     // 重新打开
        read(fd, buf, 1024);                              // 读取
        close(fd);

        unlink(newpath);                                  // 删除
    }
}

fork 和 symlink worker 更简单,就是死循环里 fork() + exit() 和 symlink() + unlink()。

PoC 的输出长这样

[*] dir=/dev/shm/trend-poc seconds=600 workers=64 files/worker=512 forkers=4 symlinkers=4
[*] monitoring /proc/modules for bmhook/tmhook unload
[  75s] events=     5479173 bmhook=1 tmhook=1 window_seen=0
[!] hook reload window detected: bmhook=0 tmhook=1
[+] benign marker actions completed during window
[ 241s] events=    64584240 bmhook=1 tmhook=1 window_seen=1

几个关键数字:

  • 75 秒时触发了第一次盲区检测
  • 547 万个事件后 bmhook 消失
  • 从 75 秒到 241 秒,系统处理了约 5900 万个事件
  • bmhook=0 tmhook=1 说明行为监控模块先于底层钩子层消失——\"大脑\"已经瞎了,\"耳朵\"还在

关键复现条件一览

条件 说明
工作目录在 tmpfs /dev/shm,纯内存,不碰磁盘 I/O
持续时间够长 600 秒,给 loop prevention 阈值足够的累积时间
并发度够高 72 个线程同时制造不同类型的事件
覆盖多个监控路径 不只是写文件——fork、symlink、rename 一起上
持续监控模块状态 每秒检查 /proc/modules,窗口一开就行动

对熟悉 Linux 系统编程的人,这些信息完全足够写出可用的 PoC。这不是脚本小子的工具,而是一份干净的安全研究复现指南。


不是崩溃,是自己卸的

研究员用 bpftrace 抓了 execve 和 module_free 事件,找到了真正的凶手:

EXEC rmmod pid=135640 comm=ds_am.init file=/usr/sbin/rmmod cmdline=rmmod bmhook
FREE module=bmhook by rmmod pid=135640 comm=rmmod

EXEC rmmod pid=136069 comm=ds_am.init file=/usr/sbin/rmmod cmdline=rmmod tmhook
FREE module=tmhook by rmmod pid=136069 comm=rmmod

是 Trend Micro 自己的进程 ds_am.init 调用了 rmmod。

不是内核崩溃。不是 PoC 调了 rmmod。不是你想象的任何\"外部攻击\"。

安全产品自己的行为监控模块被自己的恢复逻辑主动卸载了。从二进制逆向看,触发链很可能是:

事件风暴 → 行为队列压力 → loop prevention 阈值触发
  → ds_am.init 重启行为监控
  → rmmod bmhook
  → rmmod tmhook
  → 重新 insmod + livepatch

模块符号中有 enable_loop_prevention、bmhook_throttle_check、TELEMETRY_EVENT_DROPPED_COUNT 等关键词,模块日志中有 startBM enableBLP=1 thresholdBLP=100。整个恢复路径在二进制和日志里都有迹可循。


卸了就卸了?问题在\"窗口\"里

关键不是模块会卸,而是:模块卸了之后会发生什么。

研究者在正常状态下做了一次测试:Trend Micro 默认会拦截某个已知的恶意测试文件写入磁盘,文件不会留在目标目录。

然后他在模块 reload 窗口期间做了同样的操作。

结果:文件落盘了。

-rwxrwxr-x 1 ubuntu ubuntu 18K Jun  3 15:41 test-artifact
Bypass worked

时间窗口多长?一个观测周期里:

  • livepatch 完整过渡:约 19.6 秒
  • tmhook 真正缺失:约 1.3 秒
  • bmhook 先消失,此时 tmhook 可能还在,但行为监控已经瞎了

1.3 秒够干什么?

够写一个文件。够改权限。够启动一个短进程。够重命名、移动、删掉痕迹。

而且这个过程可以重复触发。PoC 跑了 600 秒,出现了多次 reload 循环。每次窗口只有一两秒,但攻击者可以等,可以反复触发,每次做一个小动作。

就算模块回来了,窗口里发生的事它已经不知道了。


为什么这算漏洞而不是\"特性\"

你可能想:这不就是产品自己的保护机制吗?压力太大了重启一下很正常吧?

对,恢复机制本身没问题。问题是两个叠加条件:

  1. 触发门槛太低:不需要 root,不需要漏洞,不需要特殊权限。一个普通用户写了个循环脚本就够了。
  2. 被恢复的恰好是保护层本身:loop prevention 为了\"防止行为监控死循环\"而卸载了行为监控模块——这就像火灾报警器因为太吵而自己把电源拔了。

安全边界被击穿的点不是系统权限,而是保护的连续性。

CWE 分类的话:

  • CWE-693:保护机制失效
  • CWE-400:不受控的资源消耗

研究员给的严重程度是 High——因为它是本地的、临时的,但直接影响了安全控制,而且在实际测试中确认了 bypass。

不是 Critical 的原因:不是远程、没提权、没内核代码执行、不是永久卸载。


时间线:报告 4 个月,石沉大海

这个漏洞的披露过程本身也是一个值得关注的点:

  • 2026-02-06:初次报告给 Trend Micro
  • 2026-02-26:厂商确认收到,PoC 和复现视频交付
  • 2026-03-18:厂商怀疑是 ds\_am 的 OOM 机制触发,要求诊断包
  • 2026-03-18:诊断包交付(PoC 运行时一份,模块卸载后一份)
  • 2026-03-20:厂商确认诊断包已转交后端团队
  • 2026-04-09:回复\"后端团队仍在处理日志\"
  • 2026-05-04:第四次跟进
  • 2026-05-31:第五次跟进
  • 2026-06-03:自行确认 bypass 成立,决定公开

从初报到公开,近 4 个月。没有 CVE 编号,没有修复时间线,没有最终 triage 结论。

这本身也是一个值得安全行业思考的问题:当一个漏洞被反复确认但厂商迟迟不回,研究者有多大的耐心是\"足够\"的?


最后说一句

这个研究最打动我的,不是技术多复杂——恰恰相反,触发条件简单得令人不安。一个低权限用户、一个循环脚本、一个 /dev/shm 目录,就能让一家头部安全厂商的端点防护出现可观测的保护盲区。

安全产品是防线,不是铜墙铁壁。它们自己也是软件,有 bug,有阈值,有恢复路径。把它们当作不可突破的\"保险箱\"是危险的。

这篇文章的价值也在于研究者的思维过程值得学习——从观察到假设,从假设到验证,从验证到归因,从归因到影响评估。这是一条清晰的安全研究链路,适合每一个做安全或做系统的人参考。

💎 服务

本文演示的攻击手法在真实环境中屡试不爽。如果你需要在其他EDR环境中测试这种技术手法,或者需要专业的红队工具与评估服务,我们提供:

✅ 各大 EDR 端点授权 Token
包括但不限于 SentinelOne、Trend Micro、CrowdStrike、等主流平台的合法测试授权,助你搭建真实的攻防演练环境。

CrowdStrike800一个端点,其他300一个。

培训课程:

第一期

第二期

第三期

第四期

第五期

第六期


    EDR的“自毁”开关" 网络安全文章

    EDR的“自毁”开关"

    本文揭示TrendMicroDeepSecurityAgent存在本地低权限安全缺陷,攻击者可通过高频文件系统操作触发内核监控模块的自我卸载机制,利用防护空窗期绕过安全检测。文章详细分析了技术原理、PoC构造及厂商披露过程,指出了该防御机制失效的严重性及应对思考。
    评论:0   参与:  0