0x01 概述
企业安全建设中非常重要的一项工作就是入侵感知体系建设,不同于网络层的安全防护检测如WAF、IPS、IDS等,入侵感知体系更偏向于被入侵后的异常行为发现,即你的机器已经被黑掉的,你能否第一时间发现并且定位到哪里出了问题。Web中间件的系统命令调用监控是我认为入侵感知中性价比较高的一项监控措施,当然你也可以算作HIDS的一项功能。
举个例子,记得S2-045爆出来的时候,公司的不少站点都受到了影响,即便当时安全、运维和开发的响应速度够快,排查受影响的项目替换Jar包,但是还是有部分机器受到了影响,通过这项监控我可以清楚的定位到哪些机器已经被黑了,攻击者执行了什么,心里有底,不至于盲目的去查找。
我目前在用的是通过Linux系统自带的Auditd服务来监控的系统的EXECVE调用,联动OSSEC报警。另外使用开源工具Snoopy可以,我们之前也提到过Bash命令审计,也见到过有的公司运维就是直接用的Snoopy来做的审计,不过我看了下老外的评论有说到可能会影响到系统的稳定性,暂时没有在生产环境测试。
下面我们就详细说一下Auditd和Snoopy这两项监控方式。
0x02 Auditd
auditd服务是Linux自带的审计系统,用来记录审计信息,从安全的角度可以用于对系统安全事件的监控。
auditd服务的配置文件位于/etc/audit/audit.rules,其中每个规则和观察器必须单独在一行中。语法如下:
-a <list>,<action> <options>
<list>配置如下
task
每个任务的列表。只有当创建任务时才使用。只有在创建时就已知的字段(比如UID)才可以用在这个列表中。
entry
系统调用条目列表。当进入系统调用确定是否应创建审计时使用。
exit
系统调用退出列表。当退出系统调用以确定是否应创建审计时使用。
user
用户消息过滤器列表。内核在将用户空间事件传递给审计守护进程之前使用这个列表过滤用户空间事件。有效的字段只有uid、auid、gid和pid。
exclude
事件类型排除过滤器列表。用于过滤管理员不想看到的事件。用msgtype字段指定您不想记录到日志中的消息。
<action>配置如下:
never
不生成审计记录。
always
分配审计上下文,总是把它填充在系统调用条目中,总是在系统调用退出时写一个审计记录。如果程序使用了这个系统调用,则开始一个审计记录。
<options>配置如下:
-S <syscall>
根据名称或数字指定一个系统。要指定所有系统调用,可使用all作为系统调用名称。
-F <name[=,!=,<,>,<=]value>
指定一个规则字段。如果为一个规则指定了多个字段,则只有所有字段都为真才能启动一个审计记录。每个规则都必须用-F启动,最多可以指定64个规则。
常用的字段如下:
pid
进程ID。
ppid
父进程的进程ID。
uid
用户ID。
gid
组ID。
msgtype
消息类型号。只应用在排除过滤器列表上。
arch
系统调用的处理器体系结构。指定精确的体系结构,比如i686(可以通过uname -m命令检索)或者指定b32来使用32位系统调用表,或指定b64来使用64位系统调用表。
...
下面我们编写测试Java命令监控规则
Jboss的启动账户为nobody,添加审计规则
# grep '\-a' /etc/audit/audit.rules
-a exclude,always -F msgtype=CONFIG_CHANGE
-a exit,always -F arch=b32 -F uid=99 -S execve -k webshell
重启服务
# service auditd restart
Stopping auditd: [ OK ]
Starting auditd: [ OK ]
使用菜刀马测试:
菜刀马传递的参数为
tom=M&z0=GB2312&z1=-c/bin/sh&z2=cd /;whoami;echo [S];pwd;echo [E]
所执行的程序如下:
else if(Z.equals("M")){String[] c={z1.substring(2),z1.substring(0,2),z2};Process p=Runtime.getRuntime().exec(c);
审计日志如下:
type=EXECVE msg=audit(1500273887.809:7496): argc=3 a0="/bin/sh" a1="-c" a2=6364202F7765622F7072.....
然后对照着日志时间戳去找对应的Nginx Access Log中的请求即可定位到webshell。
这里我们添加的规则是针对uid=99的nobody账户,而针对一些环境jboss的启动账户和运维的操作账户相同的情况,可以针对ppid来监控。
0x03 snoopy
项目地址:https://github.com/a2o/snoopy
安装步骤如下:
rm -f snoopy-install.sh &&
wget -O snoopy-install.sh https://github.com/a2o/snoopy/raw/install/doc/install/bin/snoopy-install.sh &&
chmod 755 snoopy-install.sh &&
./snoopy-install.sh stable
输出日志:
SNOOPY INSTALL: Starting installation, log file: /tmp/snoopy-install.log
SNOOPY INSTALL: Installation mode: package-latest-stable
SNOOPY INSTALL: Getting latest Snoopy version... got it, 2.4.6
SNOOPY INSTALL: Downloading from http://source.a2o.si/download/snoopy/snoopy-2.4.6.tar.gz... done.
SNOOPY INSTALL: Unpacking ./snoopy-2.4.6.tar.gz... done.
SNOOPY INSTALL: Configuring... done.
SNOOPY INSTALL: Building... done.
SNOOPY INSTALL: Installing... done.
SNOOPY INSTALL: Enabling... done.
SNOOPY LOGGER is now installed and enabled.
TIP #1: If Snoopy is to be enabled for all processes, you need
to restart your system, or at least all services on it.
// 如果想要Snoopy作用于所有进程,那么需要重启服务器
TIP #2: If you ever need to disable Snoopy, you should use provided
'snoopy-disable' script. Use 'snoopy-enable' to reenable it.
// 可以snoopy-disable来关掉监控,使用snoopy-enable来开启监控
TIP #3: Snoopy output can usually be found somewhere in /var/log/*
Check your syslog configuration for details.:
// Snoopy的日志文件位于/var/log/*
TIP #4: Configuration file location: /etc/snoopy.ini
See included comments for additional configuration options.
// 配置文件/etc/snoopy.ini
Snoopy wishes you a happy logging experience:)
安装完成后会在/usr/local/lib目录下创建libsnoopy.so文件
[root@template log]# ls -alt /usr/local/lib | head -n 10
总用量 8512
drwxr-xr-x. 5 root root 4096 6月 4 11:22 .
-rwxr-xr-x. 1 root root 959 6月 4 11:22 libsnoopy.la
lrwxrwxrwx. 1 root root 18 6月 4 11:22 libsnoopy.so -> libsnoopy.so.0.0.0
lrwxrwxrwx. 1 root root 18 6月 4 11:22 libsnoopy.so.0 -> libsnoopy.so.0.0.0
-rwxr-xr-x. 1 root root 218012 6月 4 11:22 libsnoopy.so.0.0.0
并在/etc/ld.so.preload里加入/usr/local/lib/libsnoopy.so
[root@template log]# cat /etc/ld.so.preload
/usr/local/lib/libsnoopy.so
默认会输出在/var/log/secure
[root@template ~]# tail -n 1 /var/log/secure
Jun 4 16:48:04 template snoopy[2024]: [uid:0 sid:1499 tty:/dev/pts/1 cwd:/root filename:/usr/bin/tail]: tail -n 1 /var/log/secure
执行snoopy-disable
[root@template ~]# snoopy-disable
SNOOPY: Removing from /etc/ld.so.preload: /usr/local/lib/libsnoopy.so
SNOOPY: Disabled.
SNOOPY: Hint: Your system needs to be restarted to finish Snoopy cleanup.
执行snoopy-enable
[root@template ~]# snoopy-enable
SNOOPY: Adding to /etc/ld.so.preload: /usr/local/lib/libsnoopy.so
SNOOPY: Hint #1: Reboot your machine to load Snoopy system-wide.
SNOOPY: Hint #2: Check your log files for output.
SNOOPY: Enabled.
我们来看下/etc/snoopy.ini中的配置项,日志格式可以自己定义,默认的日志格式如下
; Default value:
; "[uid:%{uid} sid:%{sid} tty:%{tty} cwd:%{cwd} filename:%{filename}]: %{cmdline}"
可以定制一些过滤条件,例如
; List of available filters:
; - exclude_spawns_of ; (available=yes) Exclude log entries that occur in specified process trees
; - exclude_uid ; (available=yes) Exclude these UIDs from logging
; - only_root ; (available=yes) Only log root commands
; - only_tty ; (available=yes) Only log commands associated with a TTY
; - only_uid ; (available=yes) Only log commands executed by these UIDs
可以指定Syslog的Facility
; Default value:
; LOG_AUTHPRIV
可以指定Syslog的Level
; Default value:
; LOG_INFO
这里我们测试一下,修改/etc/snoopy.ini配置:
syslog_facility = LOG_LOCAL6
在/etc/rsyslog.conf添加一条配置
local6.info /tmp/snoopy.log
重启rsyslog服务
[root@template ~]# service rsyslog restart
然后我们看下输出
[root@template ~]# tail -n 1 /tmp/snoopy.log
Jun 4 17:00:30 template snoopy[2141]: [uid:0 sid:2068 tty:/dev/pts/2 cwd:/root filename:/usr/bin/tail]: tail -n 1 /tmp/snoopy.log
同样也可以修改rsyslog的配置输出到日志中心。
0x04 OSSEC告警配置
这里我使用的是OSSEC监控/var/log/audit/audit.log日志
OSSEC本身已经包含了auditd事件的解码规则,例如:
<decoder name="auditd">
<prematch>^type=</prematch>
</decoder>
.......
但是在RULES里面没有找到现成的规则,编辑local_rules.xml,新增
<group name="syslog,auditd,">
<rule id="110000" level="0" noalert="1">
<decoded_as>auditd</decoded_as>
<description>AUDITD messages grouped.</description>
</rule>
<rule id="110001" level="10">
<if_sid>110000</if_sid>
<match>EXECVE</match>
<description>Java execution command</description>
</rule>
</group>
测试
[root@localhost ossec]# ./bin/ossec-logtest
2017/07/17 16:28:26 ossec-testrule: INFO: Reading local decoder file.
2017/07/17 16:28:26 ossec-testrule: INFO: Started (pid: 9463).
ossec-testrule: Type one log per line.
type=EXECVE msg=audit(1500273958.180:7500): argc=1 a0="whoami"
**Phase 1: Completed pre-decoding.
full event: 'type=EXECVE msg=audit(1500273958.180:7500): argc=1 a0="whoami"'
hostname: 'localhost'
program_name: '(null)'
log: 'type=EXECVE msg=audit(1500273958.180:7500): argc=1 a0="whoami"'
**Phase 2: Completed decoding.
decoder: 'auditd'
**Phase 3: Completed filtering (rules).
Rule id: '110001'
Level: '10'
Description: 'Java execution command'
**Alert to be generated.
然后在Agent端添加监控文件
<localfile>
<log_format>syslog</log_format>
<location>/var/log/audit/audit.log</location>
</localfile>
然后jspspy执行系统命令,可以看到告警如下
[root@localhost ossec]# tail -f /var/ossec/logs/alerts/alerts.log
** Alert 1500280231.400419: mail - syslog,auditd,
2017 Jul 17 16:30:31 (agent-31) 10.110.1.31->/var/log/audit/audit.log
Rule: 110001 (level 10) -> 'Java execution command'
type=EXECVE msg=audit(1500280229.507:7665): argc=1 a0="pwd"
这里还需考虑的一个问题是白名单,例如公司的一些站点本身就会调用视频处理的一些功能,也会调用系统命令。所以为了避免误报,需要新增一个白名单功能。
这里我们修改一下local_rules.xml,新增白名单规则,并且放到EXECVE规则上面。
<group name="syslog,auditd,">
<rule id="110000" level="0" noalert="1">
<decoded_as>auditd</decoded_as>
<description>AUDITD messages grouped.</description>
</rule>
<rule id="110001" level="0">
<if_sid>110000</if_sid>
<regex>whoami|passwd</regex>
<description>Java execution white list</description>
</rule>
<rule id="110002" level="10">
<if_sid>110000</if_sid>
<match>EXECVE</match>
<description>Java execution command</description>
</rule>
</group>
如上所示,执行whoami和cat /etc/passwd的时候不会产生告警。