天天看点

snoopy初探

snoopy是什么?刚了解这货的时候,是公司服务器上有snoopy的so无法加载的错误,然后是系统日志里面一堆日志,导致机器空间不足。官方说明是:

snoopy is designed to aid a sysadmin by providing a log of commands executed.也就是说这货会监控服务器上的命令执行,并记录到syslog。

首先来看下这个功能是怎么被完成的。首先会发现,服务器上的/etc/ld.so.preload这个文件被修改,强制可执行程序加载之前加载snoopy的so:

[cce]

#cat /etc/ld.so.preload

/usr/local/snoopy/lib/snoopy.so

[/cce]

关于ld.so.preload和ld_preload,可以参考man ld.so:

ld_preload a whitespace-separated list of additional, user-specified, elf shared libraries to be loaded before all others. this can be used to selectively override functions in other shared libraries. for set-user-id/set-group-id elf binaries, only libraries in the standard search directories that are also set-user-id will be loaded. /etc/ld.so.preload file containing a whitespace separated list of elf shared libraries to be loaded before the program.

也就是说,snoopy.so会在所有elf文件加载之前预加载,确保将一些系统调用被这货劫持。

如果在机器上执行

[cce lang=”bash”]

ls /notfound

会在系统日志中记录类似:

snoopy[25505]: [uid:0 sid:9701 tty:/dev/pts/15 cwd:/root filename:/bin/ls]: ls /notfound

这样的内容。通过ldd,可以看下一个命令加载的动态链接库:

#ldd /bin/ls

linux-vdso.so.1 => (0x00007fff99fff000)

/usr/local/snoopy/lib/snoopy.so (0x00007fc407938000)

librt.so.1 => /lib64/librt.so.1 (0x0000003e4f600000)

libacl.so.1 => /lib64/libacl.so.1 (0x0000003e50200000)

libselinux.so.1 => /lib64/libselinux.so.1 (0x0000003e4fa00000)

libc.so.6 => /lib64/libc.so.6 (0x0000003e4e200000)

libdl.so.2 => /lib64/libdl.so.2 (0x0000003e4e600000)

libpthread.so.0 => /lib64/libpthread.so.0 (0x0000003e4ea00000)

/lib64/ld-linux-x86-64.so.2 (0x0000003e4de00000)

libattr.so.1 => /lib64/libattr.so.1 (0x0000003e4f200000)

libsepol.so.1 => /lib64/libsepol.so.1 (0x0000003e4fe00000)

果然snoopy被最早加载了。

那么如果想不要snoopy加载,又有什么办法呢?

搜索了半天,没有看见linux中有什么办法能够将设置在ld.so.preload中预先加载的so给卸载掉,但是有一个值得注意的是:ld_preload加载的优先级高于ld.so.preload。

我们能不能通过更早的加载被劫持的系统调用,来避免被劫持呢?答案是肯定的。

首先,我们可以猜测出来这货是不会劫持太多的系统调用,通过nm命令看下snoopy的符号表:

#nm /usr/local/snoopy/lib/snoopy.so

0000000000000890 t execv

0000000000000b00 t execve

这两个系统调用应该是非常熟悉的,函数定义在unistd.h中,主要用于创建新的进程,并加载另一个可执行程序。只要截获了这几个系统调用,就能知道要执行什么命令了。

我们还可以再用bash来验证下:

#strace bash -c “ls /abc”

connect(3, {sa_family=af_file, path=”/dev/log”…}, 110) = 0

sendto(3, “<86>sep 23 04:34:56 snoopy[28052″…, 104, msg_nosignal, null, 0) = 104

execve(“/bin/ls”, [“ls”, “/abc”], [/* 29 vars */]) = 0

从这里可以看出两个地方,首先bash在执行ls的时候,的确是通过execve这个系统调用的;其次,这个系统调用已经被snoopy劫持了(向日志设备发送了数据)。

最后,通过代码也验证了这个猜想:代码在这里

[cce lang=”c”]

int execv (const char *filename, char *const argv[]) {

static int (*func)(const char *, char **);

fn(func,int,”execv”,(const char *, char **const));

snoopy_log_syscall_execv(filename, argv);

return (*func) (filename, (char **) argv);

}

int execve (const char *filename, char *const argv[], char *const envp[])

{

static int (*func)(const char *, char **, char **);

fn(func,int,”execve”,(const char *, char **const, char **const));

snoopy_log_syscall_execve(filename, argv, envp);

return (*func) (filename, (char**) argv, (char **) envp);

知道了原理,想到绕开,就很简单了。首先,找到execve真实的提供者:从之前ls命令的动态链接库就可以看见大部分系统的系统调用,都在/lib64/libc.so.6中,用nm命令验证下:

#nm /lib64/libc.so.6 | grep execv

0000003e4e29acf0 t __gi_execvp

0000003e4e29a880 t __execve

0000003e4e29a980 t execv

0000003e4e29a880 w execve

0000003e4e29acf0 t execvp

0000003e4e29a8b0 t fexecve

因此,然后尝试执行:

ld_preload=”/lib64/libc.so.6″ bash -c “ls /abc”

再去查看系统日志,会发现只记录了bash -c “ls /abc”这个命令,真正执行的ls /abc这个命令没有记录。

通过strace也可以看见,在执行ls之前,没有了和系统日志交互的连接了。

stat(“/bin/ls”, {stmode=sifreg|0755, st_size=91272, …}) = 0 access(“/bin/ls”, x_ok) = 0 access(“/bin/ls”, r_ok) = 0 rtsigaction(sigint, {sigdfl, [], sarestorer, 0x3e4e2302d0}, {sigdfl, [], sa_restorer, 0x3e4e2302d0}, 8) = 0 rtsigaction(sigquit, {sigdfl, [], sarestorer, 0x3e4e2302d0}, {0x1, [], sarestorer, 0x3e4e2302d0}, 8) = 0 rtsigaction(sigchld, {sigdfl, [], sarestorer, 0x3e4e2302d0}, {0x436360, [], sarestorer, 0x3e4e2302d0}, 8) = 0 execve(“/bin/ls”, [“ls”, “/abc”], [/* 30 vars */]) = 0

也就是说,如果你登陆服务器之后,执行了:

ld_preload=”/lib64/libc.so.6″ bash

用当前被snoopy劫持的bash再创建一个没有被snoopy劫持的bash,之后执行的所有命令,都不会再被记录。

转载自:https://coolex.info/blog/445.html