很多时候我们为了安全审计或者故障跟踪排错,可能会记录分析主机系统的操作行为。比如在系统中新增了一个用户,修改了一个文件名,或者执行了一些命令等等,理论上记录的越详细,越有利于审计和排错的目的。不过过剩的记录也会为分析带来不少麻烦,尤其是将很多主机的记录行为发送到固定的远程主机中,数据越多,分析的成本便越大。
实际上,绝大多数的系统行为都是重复多余的,比如cron任务计划,我们信任的程序等,这些都会产生大量的记录,但很少用于审计分析。基于这个需求,我们在审计系统操作行为的时候,至少应该添加一些过滤规则,避免记录过多的无用信息,比如重复的cron任务操作,同时也要避免记录一些敏感信息,比如带密码的命令行操作。满足这些需求后,我们在审计系统操作行为的时候应该遵照以下准则:忽略cron,daemon产生的记录;
忽略带密码的敏感命令行或脚本操作记录;
忽略监控用户(比如nagios,zabbix,promethus等)产生的记录;
忽略频繁产生日志的操作行为;
第二点为可选项,在以明文方式传输到远程日志服务器的时候,我们建议忽略记录。第四点则需要着重强调,比如我们记录一台web主机中的所有connect,accept网络系统调用操作,虽然可以据此分析该主机所有的网络访问请求,达到安全或者故障定位的目的,但是这两个系统调用可能在短时间内产生大量的日志,对kernel和网络日志传输都会产生不小的压力,这种大海捞针似的审计方式我们不推荐直接在线上主机中使用,建议仅在需要定位问题的时候启用。下面我们主要介绍有哪几种方式可以实现系统操作的审计:history记录方式定制bash记录方式snoopy记录方式auditd记录方式eBPF记录方式history记录方式history方式很传统也很简单,本质上是将历史的命令发送到syslog日志中,可以用来简单记录用户的命令操作历史。但是这种方式有几个重要的缺点,并不适合审计的目的:
容易被修改,被绕过;记录太简单,没有上下文信息(比如pid,uid,sid等);无法记录shell脚本内的操作;无法记录非登录的操作;难以实现过滤规则;定制bash记录方式定制bash方式比较冷门,本质上是为bash源程序增加审计日志的功能,开发者可以据此添加一些操作命令的上下文信息,不过很难记录子进程的信息,其缺点和上述的history方式类似:容易被绕过,用户可以使用csh,zsh等;无法记录shell脚本内的操作;过滤规则可能单一;可能需要不停的更新bash版本,工作量大,否则容易被发行版替换;snoopy记录方式snoopy方式相对新颖,本质上是封装了execv,execve系统调用,以系统预加载(pload)的方式实现记录所有的命令操作。更多介绍可以参考以前的文章snoopy如何记录系统执行过的命令。目前大部分系统执行命令时都通过execv,execve系统调用执行,这点就和会话无关,几乎所有的情况下,只要通过这两个系统调用执行命令,就会将操作行为记录下来,从目前的最新版本(.4.8)来看,snoopy有几个优点:难以绕过,只要设置了PRELOAD,就肯定会记录;
无论是否存在tty会话,都会记录execv,execve相关的命令行操作,包含详细的进程上下文信息;
可以记录shell脚本内部的操作行为,脚本内的命令行操作大部分都会调用execv,execve;
可以记录操作行为的参数,比如指定了用户名,密码等;
过滤规则丰富,可以忽略指定daemon,uid,也可以仅记录指定的uid;
如下日志示例:
Oct:34:31cz-t1snoopy[]:[time_ms:login:czuid:0pid:ppid:sid:tty:/dev/pts/0cwd:/rootfilename:/bin/uptimeusername:root]:uptime-p
上述日志显示root用户执行了uptime命令,参数包含-p对应的进程上下文信息都比较全,不过snoopy的缺点也比较明显,主要包含以下几点:
仅支持execv,execve相关系统调用的操作;不设置规则可能产生的日志过多,对日志搜集系统造成很大的负担;暂不支持过滤敏感信息规则;在实际的使用中,snoopy记录方式可以很详细的记录所有的命令操作信息,帮助我们定位很多疑难问题。不过我们也需要通过过滤规则来避免产生过多的信息,snoopy的过滤规则可以满足以下需求:
忽略cron,daemon产生的记录;
忽略监控用户(比如nagios,zabbix,promethus等)产生的记录;
比如以下配置,即可忽略crond,my-daemon守护进程,忽略zabbix用户:
#zabbixuid为99filter_chain=exclude_uid:99;exclude_spawns_of:crond,my-daemon
备注:过滤规则在(filtering.c-snoopy_filtering_check_chain)函数实现,由log.c-snoopy_log_syscall_exec函数调用,过滤规则为事后行为,即在打印日志的时候判断是否满足过滤规则,并非事前行为。
另外,我们在snoopy的基础上增加了exclude_