看论坛留言,一些用户遇到清理后复发的情况,就和我最开始的情况一样。恶意程序作者肯定也在关注,被发现的恶意ip,他们肯定会更换,因此每个人的情况可能也不一样,如果对终端敲命令不陌生,可以参考下面的说明操作。
清理之前必须保证断网,可以考虑禁止任何出站请求,或拔掉网线,接显示器、键盘鼠标操作
查找恶意文件
以下输出是正常情况,如果有其它文件,可以视为恶意文件。
lasttr 应该只读取文件系统元数据信息,执行是相当快的,如果多次清理仍无法成功,考虑检查整个数据盘(比如 /vol1 )
# 查找 /usr /etc /var 目录中,添加了不可变更属性的文件
root@fnos:~# lsattr -Ra /usr/ 2> /dev/null |grep '\-i-'
----i---------e------- /usr/trim/etc/machine_id
root@fnos:~# lsattr -Ra /etc 2> /dev/null |grep '\-i-'
root@fnos:~# lsattr -Ra /var 2> /dev/null |grep '\-i-'
如果发现了异常文件,可以用stat命令查看文件内容修改时间:
# 以下面输出中的Modify:这一行的时间作为参考,大致计算过去了多少分钟
root@fnos:~# stat /etc/openvpn/server/ccd/android
File: /etc/openvpn/server/ccd/android
Size: 37 Blocks: 8 IO Block: 4096 regular file
Device: 8,2 Inode: 2621838 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2026-02-02 16:02:20.881555617 +0800
Modify: 2026-02-02 16:02:20.881555617 +0800
Change: 2026-02-02 16:02:20.905555811 +0800
Birth: 2026-02-02 16:02:20.881555617 +0800
使用find命令,查找最近一段时间内修改过的文件,筛选恶意程序, /etc、/usr 目录重点查看:
# 查看/etc目录中最近8小时文件内容被修改过的文件
root@fnos:~# find /etc/ -type f -mmin -640
/etc/ld.so.cache
/etc/openvpn/server/ccd/android
/etc/init.d/.depend.stop
/etc/init.d/.depend.boot
/etc/init.d/.depend.start
/etc/apt/sources.list.d/tsinghua.sources
/etc/fail2ban/filter.d/sshd.conf
/etc/fail2ban/jail.d/sshd.conf
/etc/nftables.conf
/etc/iproute2/rt_tables
/etc/shadow
/etc/issue
/etc/passwd
# 查看/usr目录中最近8小时文件内容被修改过的文件
root@fnos:~# find /usr/ -type f -mmin -640
/usr/local/apps/@appdata/trim.media/logs/trim-media.log
/usr/local/apps/@appdata/trim.media/database/trimactivity.db
/usr/local/apps/@appdata/trim.media/database/trimmedia.db
/usr/local/apps/@appdata/trim.photos/db/photo.db-shm
/usr/local/apps/@appdata/trim.photos/db/photo.db-wal
/usr/local/apps/@appdata/trim.photos/index/1.bleve/store/000000000e2c.zap
/usr/local/apps/@appdata/trim.photos/index/1.bleve/store/root.bolt
/usr/local/apps/@appdata/trim.photos/index/1.bleve/store/000000000e2b.zap
/usr/local/apps/@appdata/trim.photos/log/info.log
/usr/local/apps/@appdata/trim.photos/log/error.log
/usr/local/apps/@appdata/trim.photos/exiftoolCmdList.json
/usr/trim/logs/sysinfo_service.2.log
/usr/trim/logs/rpc_broker.log
/usr/trim/logs/filestor_service.log
/usr/trim/logs/share_service.log
/usr/trim/logs/network_service.log
/usr/trim/logs/backup_service.log
/usr/trim/logs/security_service.log
/usr/trim/logs/resmon_service.log
/usr/trim/logs/sysinfo_service.1.log
/usr/trim/logs/sysinfo_service.log
/usr/trim/logs/imagesrv.log
/usr/trim/logs/uploadsrv.log
/usr/trim/logs/sysinfo_service.5.log
/usr/trim/logs/sysinfo_service.3.log
/usr/trim/logs/dockermgr.log
/usr/trim/logs/sysinfo_service.4.log
/usr/trim/etc/network_cert_all.conf
/usr/trim/etc/fw.conf
/usr/trim/etc/rpc_broker.conf
/usr/trim/etc/network_wifi_state.conf
/usr/trim/etc/network_gateway_cert.conf
/usr/trim/etc/network_cert_all.conf.old
/usr/trim/nginx/logs/access.log
/usr/data/2L79GF21D2/tfa.db
清理恶意文件
如果确认不是系统中的文件,可以直接删除。
如果是飞牛系统文件,可以下载官方iso安装包,在另外一个电脑中解压镜像中的trimfs.tgz文件, 与解压的文件进行对比,确认是否被添加恶意内容。
之所以在另外一个电脑操作,因为之前发现病毒会修改解压后的usr/trim/bin/system_startup.sh文件,不留神的话可能会被迷惑。
如果文件被添加了i属性,类似----i---------e------- /usr/trim/etc/machine_id这样,先使用chattr -i 去除该属性再删除。
如果提示没有lsattr或chattr命令, 执行apt-get reinstall e2fsprogs 命令后再重试。
如果root用户执行netstat -ntlp 或 ss -ntlp 命令,发现有监听端口但是看不到进程号的程序,大概率是有恶意内核模块被加载。但也有例外,wireguard好像就看不到进程号,但是是正常的。
如果怀疑有恶意内核模块,可以计算解压的安装镜像trimfs.tgz内核目录中每个文件的md5, 并与系统中的比较,确认是否有异常的模块。
# 计算镜像中文件的md5值:
find lib/modules/6.12.18-trim/ -type f |xargs md5sum > md5.txt
# 和系统中的进行比较, 结果输出到result.txt
cd /
md5sum -c md5.txt > result.txt
# 查看result.txt文件,重点关注没有输出OK的内容, modules.开头这这些忽略
root@fnos:/# grep FAILED result.txt
lib/modules/6.12.18-trim/modules.alias.bin: FAILED
lib/modules/6.12.18-trim/modules.dep.bin: FAILED
lib/modules/6.12.18-trim/modules.symbols: FAILED
lib/modules/6.12.18-trim/modules.dep: FAILED
lib/modules/6.12.18-trim/modules.alias: FAILED
lib/modules/6.12.18-trim/modules.symbols.bin: FAILED
确认之后,如果发现有异常加载的模块,可以删除内核模块后执行 depmod -a 更新模块依赖关系。
就算误删除了也无所谓,从解压的目录中拷一个放进去就行,内核目录中的模块变更后,要执行depmod -a 更新依赖关系。
配置监控服务
安装监控组件,持续检查是否有异常活动,如有异常活动,按照前面的步骤继续排查。下面是我使用的docker-compose配置,之前通过监控发现凌晨3点多一点儿,cpu和网络流量就会开始活跃,并且会持续一小段时间,后续每隔一小时就又开始活动,基本确认未清理干净,反反复复折腾了三天才最终平静。
下面的端口映射部分,未使用docker内置的方案,使用nft配置dnat进行访问,可以根据情况修改。
# root@fnos:/opt/websites# cat prometheus.yaml
name: "prometheus"
services:
prometheus:
image: prom/prometheus
container_name: prometheus
environment:
TZ: Asia/Shanghai
volumes:
- ${DOCKER_VOLUME_DIRECTORY}/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
networks:
webnet:
ipv4_address: 172.18.0.8
node_exporter:
image: quay.io/prometheus/node-exporter:latest
container_name: node_exporter
privileged: true
command:
- '--path.rootfs=/host'
network_mode: host
pid: host
restart: unless-stopped
volumes:
- '/:/host:ro,rslave'
grafana:
image: grafana/grafana
container_name: grafana
# restart: always
environment:
TZ: Asia/Shanghai
volumes:
- grafana_storage:/var/lib/grafana
depends_on:
- prometheus
networks:
webnet:
ipv4_address: 172.18.0.6
volumes:
grafana_storage:
prometheus_data:
networks:
webnet:
external: true
所有的容器共用一个网络,相关配置:
# 这个是其它compose文件中网络配置部分
networks:
web:
driver: bridge
attachable: true
enable_ipv4: true
enable_ipv6: false
external: false
name: webnet
ipam:
driver: default
config:
- subnet: 172.18.0.0/24
ip_range: 172.18.0.0/24
gateway: 172.18.0.1
使用的配置文件:
# root@fnos:/opt/websites# cat prometheus/prometheus.yml
global:
scrape_interval: 5s
evaluation_interval: 5s
external_labels:
monitor: 'dashboard'
rule_files:
#- '**.rules'
scrape_configs:
- **_name: 'prometheus'
scrape_interval: 5s
static_configs:
- targets: ['172.18.0.8:9090']
- **_name: fnos
static_configs:
- targets: ['172.18.0.1:9100']
防火墙参考配置
不指定访问某个目的地址,只要是本地程序主动对外发起请求,一律拦截,外部请求进来后,关联的响应可以放行。
#!/usr/sbin/nft -f
flush ruleset
table inet filter {
chain input {
type filter hook input priority filter; counter; policy drop;
ct state related,established counter accept;
iifname "lo" accept;
iifname "enp0s31f6-ovs" udp dport { 53, 67 } accept;
iifname "enp0s31f6-ovs" tcp dport { 53, 67 } accept;
ip saddr { 192.168.5.0/24, 10.8.0.0/24, 172.18.0.0/24 } counter accept;
tcp dport { 22, 1194, 8443, 443} counter accept;
}
chain forward {
type filter hook forward priority filter; counter; policy drop;
iifname { "tun0", "enp0s31f6-ovs", "br-691295fe2d05" } counter accept;
oifname { "tun0", "enp0s31f6-ovs", "br-691295fe2d05" } counter accept;
}
chain output {
type filter hook output priority filter; policy drop;
oif "lo" accept;
ct state established,related accept;
udp dport 53 accept;
tcp dport 53 accept;
tcp dport 22 accept;
}
}
table inet nat {
chain postrouting {
type nat hook postrouting priority srcnat;
ip saddr 10.8.0.0/24 counter masquerade;
ip saddr 172.18.0.0/24 counter masquerade;
}
chain prerouting {
type nat hook prerouting priority dstnat;
ip daddr 192.168.5.254 tcp dport 3000 counter dnat to 172.18.0.6:3000;
ip daddr 192.168.5.254 tcp dport 9090 counter dnat to 172.18.0.8:9090;
}
}
其它
就像人都会犯错一样,大多数也都会为错误找些理由,希望都能吸取这次的教训,后面变得更加强大,也希望大家能一起参与做一个伟大的产品。