Linux使用snoopy记录命令执行日志

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u010039418/article/details/85068712

注:本文基于CentOS 6.5编写

1、关于snoopy

snoopy是一个开源的轻量级lib库, 可以记录系统中所有执行过的命令和参数。它是以预加载(preload)的方式实现历史命令的记录。 通过封装execv()和execve()系统调用,在发生这两个系统调用的时候记录下所需要的信息。

2、安装

在CentOS 6.5系统上可以直接通过yum方式安装,如果没有对应的rpm包也可以直接用源码安装。以下以yum安装方式为例。

yum install -y snoopy

安装完成后查看下组件列表:

[root@CentOS-6-5 /home]# rpm -ql snoopy
/lib64/snoopy.so
/usr/share/doc/snoopy-1.7.10
/usr/share/doc/snoopy-1.7.10/COPYING
/usr/share/doc/snoopy-1.7.10/ChangeLog
/usr/share/doc/snoopy-1.7.10/README
/usr/share/doc/snoopy-1.7.10/README.Fedora
[root@CentOS-6-5 /home]# 

可见就一个.so文件,其他都是文档。

3、配置

在/etc/ld.so.preload文件中添加以下配置,指定snoopy.so库文件所在位置。

[root@CentOS-6-5 /]# cat /etc/ld.so.preload 
/lib64/snoopy.so

由于linux的动态链接机制可以让程序在运行时加载或预处理需要的动态库文件(使用 --static静态选项编译的程序除外),因此后续执行命令时就会加载snoopy.so这个库文件,从而达到记录命令及参数的目的。

4、执行效果

我们可以通过strace看下df -h命令的执行过程。

[root@CentOS-6-5 /home]# strace df -h
...
access("/etc/ld.so.preload", R_OK)      = 0
open("/etc/ld.so.preload", O_RDONLY)    = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=17, ...}) = 0
mmap(NULL, 17, PROT_READ|PROT_WRITE, MAP_PRIVATE, 3, 0) = 0x7fc84144a000
close(3)                                = 0
open("/lib64/snoopy.so", O_RDONLY)      = 3
read(3, "\177ELF\2\1\1\0\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0`\10\0\0\0\0\0\0"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=5952, ...}) = 0
mmap(NULL, 2101216, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fc841249000
mprotect(0x7fc84124a000, 2093056, PROT_NONE) = 0
mmap(0x7fc841449000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0) = 0x7fc841449000
close(3)                                = 0
munmap(0x7fc84144a000, 17)              = 0
...
open("/etc/mtab", O_RDONLY)             = 3
...      

从上面打印可以看到,df -h命令执行过程会先读取/etc/ld.so.preload的内容,并加载snoopy.so库文件,然后才去执行df -h命令。

对应的日志会记录在/var/log/secure文件中,

Dec 18 01:34:17 CentOS-6-5 snoopy[14034]: [uid:0 sid:11304 tty:/dev/pts/0 cwd:/home filename:/bin/df]: df -h

5、记录ssh远程执行命令

通过snoopy也可以记录ssh远程执行的命令,以远程执行pwd为例,在日志中会有以下记录,

Dec 18 01:47:26 CentOS-6-5 snoopy[14290]: [uid:0 sid:14290 tty: cwd:/ filename:/usr/sbin/sshd]: /usr/sbin/sshd -R 
Dec 18 01:47:26 CentOS-6-5 snoopy[14292]: [uid:0 sid:14292 tty: cwd:/root filename:/bin/bash]: bash -c pwd 

可见,记录的时候分为两部分,一部分是调用/usr/sbin/sshd,之后才是调用/bin/bash执行pwd命令。

6、查看命令是否能被snoopy记录

我们可以通过查看某个命令的链接库中是否包含snoopy来判断,以pwd为例,

[root@CentOS-6-5 /home]# ldd /bin/pwd
	linux-vdso.so.1 =>  (0x00007fff1e753000)
	/lib64/snoopy.so (0x00007f985bdd3000)
	libc.so.6 => /lib64/libc.so.6 (0x00000030b4400000)
	libdl.so.2 => /lib64/libdl.so.2 (0x00000030b4000000)
	/lib64/ld-linux-x86-64.so.2 (0x00000030b3c00000)

通过ldd查看pwd命令链接的动态库,可见,该命令可被snoopy记录。

7、注意事项

A、snoopy相比于history+shell的方式,可以对ssh远程执行命令进行记录。但是由于动态库的限制,对于静态编译的应用则无法记录。

B、对于已经将动态库加载到内存并运行的程序,snoopy也无法生效,除非重启服务。

C、由于是封装execve()类函数,因此snoopy记录的粒度更为细致,比如执行一个脚本,snoopy的记录方式会记录脚本里执行的具体命令,而采用history+shell的方式则只会记录执行脚本这个动作,无法感知脚本具体内容。这一点有好有坏,就看具体场景了。

D、通过封装execve()类函数方式也就决定这种方式拉长了命令的时间,对性能肯定有一定影响。

E、snoopy的方式也很容易通过LD_PRELOAD环境变量绕过记录。

F、新版本2.x.x的snoopy可以设置一些过滤项来避免产生大量日志,也可以配置日志格式,可到github上了解:https://github.com/a2o/snoopy/

猜你喜欢

转载自blog.csdn.net/u010039418/article/details/85068712