华为云HIPS,名叫
hostguard
, 这篇是从hostguard
的进程来分析这个产品上一篇的链接:华为云HIPS分析:软件篇
[email protected]#ps -ef|grep hostguard|grep -v grep
root 1258 1 0 2019 ? 01:38:39 /usr/local/hostguard/bin/hostguard -l /usr/local/hostguard/log
root 10501 1258 0 Jun30 ? 00:12:59 /usr/local/hostguard/bin/hostguard -l /usr/local/hostguard/log
可以看到hostguard
启动了两个同名进程,且1258
号进程还是10501
进程的父进程。
看一下1258
号进程,先看一下它是否由docker还是systemd启动
[email protected]#cat /proc/1258/cgroup
11:perf_event:/
10:memory:/system.slice/hostguard.service
9:devices:/system.slice/hostguard.service
8:blkio:/system.slice/hostguard.service
7:cpuset:/
6:hugetlb:/
5:net_prio,net_cls:/
4:cpuacct,cpu:/system.slice/hostguard.service
3:pids:/system.slice/hostguard.service
2:freezer:/
1:name=systemd:/system.slice/hostguard.service
可见它是由systemd
启动的hostguard.service
再看启动参数和环境变量
[email protected]#cat /proc/1258/cmdline
/usr/local/hostguard/bin/hostguard^@-l^@/usr/local/hostguard/log^@
[email protected]#cat /proc/1258/environ
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin^@PWD=/^@LANG=en_US.UTF-8^@SHLVL=1^@_=/usr/local/hostguard/bin/hostguard^@
可见没什么有用信息,只是PATH
环境变量调整了一下程序执行路径
再看它加载的so
[email protected]#cat /proc/1258/maps|awk '{print $6}'|sort|uniq[heap]
[stack]
/usr/lib64/ld-2.17.so
/usr/lib64/libc-2.17.so
/usr/lib64/libdl-2.17.so
/usr/lib64/libm-2.17.so
/usr/lib64/libpthread-2.17.so
/usr/lib64/librt-2.17.so
/usr/local/hostguard/bin/hostguard
/usr/local/hostguard/bin/libagent.so
/usr/local/hostguard/bin/libbasecomm.so
/usr/local/hostguard/bin/libbaselogger.so
/usr/local/hostguard/bin/libbaseutils.so
/usr/local/hostguard/lib/libcrypto.so.1.0.0
/usr/local/hostguard/lib/libcurl.so.4.5.0
/usr/local/hostguard/lib/libgcc_s.so.1
/usr/local/hostguard/lib/libsecurec.so
/usr/local/hostguard/lib/libssl.so.1.0.0
/usr/local/hostguard/lib/libstdc_plus.so.6.0.14
[vdso]
[vsyscall]
可见,并没有加载一些功能so,说明这完全是一个daemon进程,可能是用来管控子进程的。
再看它的fd
[email protected]#ls -l /proc/1258/fd
total 0
lrwx------ 1 root root 64 Jun 11 15:41 0 -> /dev/null
lrwx------ 1 root root 64 Jun 11 15:41 1 -> /dev/null
lrwx------ 1 root root 64 Jun 11 15:41 2 -> /dev/null
lrwx------ 1 root root 64 Jun 11 15:41 3 -> /usr/local/hostguard/log/daemon.log
可见它确实是一个daemon进程。也就是说,hostguard
的防护功能都放在子进程。
这种设计方式是非常好的。父进程的功能尽量简单,只做子进程的管控,一来父进程稳定,即使出问题也容易追溯,二来,如果子进程出了问题,父进程也容易恢复服务。
由于10501
的1258
的子进程,那么cgroup
不用分析了。只要分析其它的。
分析启动参数和环境变量,一般父进程在启动子进程时,有可能会设置启动参数和改变环境变量,一般集中在PATH
, LD_LIBRARY_PATH
之类。
软件打桩技术,一般是启动子进程执行被分析程序,通过改变
LD_LIBRARY_PATH
这个环境变量,让被分析程序加载指定so。这些指定so会定义不少和libc.so同名的函数。各种性能分析软件就是使用这种技术。
[email protected]#cat /proc/10501/cmdline
/usr/local/hostguard/bin/hostguard^@-l^@/usr/local/hostguard/log^@
[email protected]#cat /proc/10501/environ
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin^@PWD=/^@LANG=en_US.UTF-8^@SHLVL=1^@_=/usr/local/hostguard/bin/hostguard^@
可见父进程并没有对子进程进行打桩。
看一下子进程加载的so
[email protected]#cat /proc/10501/maps|awk '{print $6}'|sort|uniq[heap]
[stack]
/usr/lib64/ld-2.17.so
/usr/lib64/libc-2.17.so
/usr/lib64/libcrypt-2.17.so
/usr/lib64/libdl-2.17.so
/usr/lib64/libfreebl3.so
/usr/lib64/libfreeblpriv3.so
/usr/lib64/libm-2.17.so
/usr/lib64/libnss_files-2.17.so
/usr/lib64/libpthread-2.17.so
/usr/lib64/librt-2.17.so
/usr/local/hostguard/bin/hostguard
/usr/local/hostguard/bin/libagent.so
/usr/local/hostguard/bin/libbasecomm.so
/usr/local/hostguard/bin/libbaselogger.so
/usr/local/hostguard/bin/libbaseutils.so
/usr/local/hostguard/bin/libmodargoseye.so
/usr/local/hostguard/bin/libmoddetconf.so
/usr/local/hostguard/bin/libmodfastscan.so
/usr/local/hostguard/bin/libmodfilemon.so
/usr/local/hostguard/bin/libmodiso.so
/usr/local/hostguard/bin/libmodlogin.so
/usr/local/hostguard/bin/libmodprocmon.so
/usr/local/hostguard/bin/libmodpuppetdet.so
/usr/local/hostguard/bin/libmodpwd.so
/usr/local/hostguard/bin/libmodwebcms.so
/usr/local/hostguard/bin/libmodwhitelist.so
/usr/local/hostguard/bin/libmodwshell.so
/usr/local/hostguard/lib/libcrypto.so.1.0.0
/usr/local/hostguard/lib/libcurl.so.4.5.0
/usr/local/hostguard/lib/libgcc_s.so.1
/usr/local/hostguard/lib/libmagic.so.1.0.0
/usr/local/hostguard/lib/libsecurec.so
/usr/local/hostguard/lib/libssl.so.1.0.0
/usr/local/hostguard/lib/libstdc_plus.so.6.0.14
/usr/local/hostguard/lib/libyara.so.3.4.0
/usr/local/hostguard/lib/libz.so.1.2.11
[vdso]
[vsyscall]
可见,确实是子进程加载了各种功能模块,也就是检测功能都放在子进程里。
这种设计有很大缺陷。因为HIPS有实时监控功能和定时扫描功能(用于各种基线)。把所有功能放在一个进程里,就会出现这样的情况:当在进行定时扫描时,刚好有大量事件出现,这时候实时监控功能也会占用不少资源,导致整个进程达到预定的资源配额时,会导致进程被重启,从而中断扫描,使得一些基线检查无法完成。所以,最好还是把进程拆分,每个进程完成一种功能。
再看打开的fd
[email protected]#ls -l /proc/10501/fd
total 0
lrwx------ 1 root root 64 Jun 30 14:40 0 -> /dev/null
lrwx------ 1 root root 64 Jun 30 14:40 1 -> /dev/null
lr-x------ 1 root root 64 Jun 30 14:40 10 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 11 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 12 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 13 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 14 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 15 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 16 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 17 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 18 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 19 -> anon_inode:inotify
lrwx------ 1 root root 64 Jun 30 14:40 2 -> /dev/null
lr-x------ 1 root root 64 Jun 30 14:40 20 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 21 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 22 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 23 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 24 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 25 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 26 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 27 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 28 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 29 -> anon_inode:inotify
lrwx------ 1 root root 64 Jun 30 14:40 3 -> /usr/local/hostguard/log/hostguard.log
lr-x------ 1 root root 64 Jun 30 14:40 30 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 31 -> anon_inode:inotify
lrwx------ 1 root root 64 Jun 30 14:40 32 -> socket:[2797256217]
lr-x------ 1 root root 64 Jun 30 14:40 33 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 18:46 34 -> /usr/local/hostguard/benchmarks/ssh.zip
lr-x------ 1 root root 64 Jul 2 21:31 35 -> /usr/local/hostguard/benchmarks/ssh.zip
lr-x------ 1 root root 64 Jun 30 14:41 36 -> /usr/local/hostguard/benchmarks/tomcat.zip
lr-x------ 1 root root 64 Jun 30 23:06 37 -> /usr/local/hostguard/benchmarks/ssh.zip
lr-x------ 1 root root 64 Jun 30 23:06 38 -> /usr/local/hostguard/benchmarks/tomcat.zip
lr-x------ 1 root root 64 Jul 3 21:50 39 -> /usr/local/hostguard/benchmarks/ssh.zip
lr-x------ 1 root root 64 Jun 30 14:40 4 -> anon_inode:inotify
lr-x------ 1 root root 64 Jul 1 23:06 40 -> /usr/local/hostguard/benchmarks/tomcat.zip
lr-x------ 1 root root 64 Jul 4 21:51 41 -> /usr/local/hostguard/benchmarks/ssh.zip
lr-x------ 1 root root 64 Jul 3 03:50 42 -> /usr/local/hostguard/benchmarks/tomcat.zip
lr-x------ 1 root root 64 Jul 5 11:16 43 -> /proc/71500/net/tcp
lr-x------ 1 root root 64 Jul 3 23:06 44 -> /usr/local/hostguard/benchmarks/tomcat.zip
lr-x------ 1 root root 64 Jun 30 14:40 5 -> anon_inode:inotify
lrwx------ 1 root root 64 Jul 2 18:43 6 -> socket:[2808807671]
lr-x------ 1 root root 64 Jun 30 14:40 7 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 8 -> anon_inode:inotify
lr-x------ 1 root root 64 Jun 30 14:40 9 -> anon_inode:inotify
满屏的anon_inode:inotify
就说明hostguard
在实时监控文件变动,这么多的inotify实例,会不会导致内核内存占用过多,毕竟一个inotify监控事件结构体是300-500字节。
而这些
lr-x------ 1 root root 64 Jun 30 18:46 34 -> /usr/local/hostguard/benchmarks/ssh.zip
lr-x------ 1 root root 64 Jul 2 21:31 35 -> /usr/local/hostguard/benchmarks/ssh.zip
lr-x------ 1 root root 64 Jun 30 14:41 36 -> /usr/local/hostguard/benchmarks/tomcat.zip
lr-x------ 1 root root 64 Jun 30 23:06 37 -> /usr/local/hostguard/benchmarks/ssh.zip
lr-x------ 1 root root 64 Jun 30 23:06 38 -> /usr/local/hostguard/benchmarks/tomcat.zip
lr-x------ 1 root root 64 Jul 3 21:50 39 -> /usr/local/hostguard/benchmarks/ssh.zip
lr-x------ 1 root root 64 Jul 1 23:06 40 -> /usr/local/hostguard/benchmarks/tomcat.zip
lr-x------ 1 root root 64 Jul 4 21:51 41 -> /usr/local/hostguard/benchmarks/ssh.zip
lr-x------ 1 root root 64 Jul 3 03:50 42 -> /usr/local/hostguard/benchmarks/tomcat.zip
lr-x------ 1 root root 64 Jul 3 23:06 44 -> /usr/local/hostguard/benchmarks/tomcat.zip
说明正在进行一些服务配置的基线检查。但配置脚本重复加载了。之前调研时,也遇到打开了280个fd,大部分是这些配置脚本,一开始以为是句柄泄露了,后来回落了。在这一块,hostguard
需要好好审计一下代码,毕竟这5个配置脚本压缩包大小有297K,就算不解压,如果达到50份,也有14M,再加上其它任务,可能就导致hostguard
达到内存配额150M,从而被重启掉。
再看fd里面的两个socket
lrwx------ 1 root root 64 Jun 30 14:40 32 -> socket:[2797256217]
lrwx------ 1 root root 64 Jul 2 18:43 6 -> socket:[2808807671]
看一下2808807671
这个,第6个fd
[email protected]#grep -rIn 2808807671 /proc/10501/net/
/proc/10501/net/tcp:73: 71: 0201000A:ED02 27007D64:01BB 01 00000000:00000000 00:00000000 00000000 0 0 2808807671 1 ffff880037394d80 20 4 0 10 9
可见,它是一个TCP socket
,是对应这个
[email protected]#netstat -anp4|grep hostguard
tcp 0 0 10.0.1.2:60674 100.125.0.39:443 ESTABLISHED 10501/hostguard
这说明它是和管理端相连。
再看一下第32个fd,2797256217
[email protected]#grep -rIn 2797256217 /proc/10501/net/
/proc/10501/net/netlink:10:ffff880227ba4000 11 10501 00000001 0 0 0 2 721841 2797256217
说明它是netlink socket
。
根据netlink文件的格式
sk Eth Pid Groups Rmem Wmem Dump Locks Drops Inode
可见这个netlink socket
的信息是
根据内核代码net/netlink/af_netlink.c
:
static int netlink_native_seq_show(struct seq_file *seq, void *v)
{
if (v == SEQ_START_TOKEN) {
seq_puts(seq,
"sk Eth Pid Groups "
"Rmem Wmem Dump Locks Drops Inode\n");
} else {
struct sock *s = v;
struct netlink_sock *nlk = nlk_sk(s); seq_printf(seq, "%pK %-3d %-10u %08x %-8d %-8d %-5d %-8d %-8u %-8lu\n",
s,
s->sk_protocol,
nlk->portid,
nlk->groups ? (u32)nlk->groups[0] : 0,
sk_rmem_alloc_get(s),
sk_wmem_alloc_get(s),
nlk->cb_running,
refcount_read(&s->sk_refcnt),
atomic_read(&s->sk_drops),
sock_i_ino(s)
);
}
return 0;
}
可知sk_protocol
是11,那么11是哪个值呢?
根据/usr/include/linux/netlink.h
的定义
#define NETLINK_ROUTE 0 /* Routing/device hook */
#define NETLINK_UNUSED 1 /* Unused number */
#define NETLINK_USERSOCK 2 /* Reserved for user mode socket protocols */
#define NETLINK_FIREWALL 3 /* Unused number, formerly ip_queue */
#define NETLINK_SOCK_DIAG 4 /* socket monitoring */
#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
#define NETLINK_XFRM 6 /* ipsec */
#define NETLINK_SELINUX 7 /* SELinux event notifications */
#define NETLINK_ISCSI 8 /* Open-iSCSI */
#define NETLINK_AUDIT 9 /* auditing */
#define NETLINK_FIB_LOOKUP 10
#define NETLINK_CONNECTOR 11
#define NETLINK_NETFILTER 12 /* netfilter subsystem */
#define NETLINK_IP6_FW 13
#define NETLINK_DNRTMSG 14 /* DECnet routing messages */
#define NETLINK_KOBJECT_UEVENT 15 /* Kernel messages to userspace */
#define NETLINK_GENERIC 16
可知,它这个值是NETLINK_CONNECTOR
,说明是一个Kernel connector
Kernel connector:新的基于 netlink 的用户空间 <-> 内核空间容易使用通讯模块。
既然已经知道是Kernel connector
,那么groups
的定义就从/usr/include/linux/connector.h
查
define CN_IDX_PROC 0x1
#define CN_VAL_PROC 0x1
#define CN_IDX_CIFS 0x2
#define CN_VAL_CIFS 0x1
#define CN_W1_IDX 0x3 /* w1 communication */
#define CN_W1_VAL 0x1
#define CN_IDX_V86D 0x4
#define CN_VAL_V86D_UVESAFB 0x1
#define CN_IDX_BB 0x5 /* BlackBoard, from the TSP GPL sampling framework */
#define CN_DST_IDX 0x6
#define CN_DST_VAL 0x1
#define CN_IDX_DM 0x7 /* Device Mapper */
#define CN_VAL_DM_USERSPACE_LOG 0x1
#define CN_IDX_DRBD 0x8
#define CN_VAL_DRBD 0x1
#define CN_KVP_IDX 0x9 /* HyperV KVP */
#define CN_KVP_VAL 0x1 /* queries from the kernel */
#define CN_VSS_IDX 0xA /* HyperV VSS */
#define CN_VSS_VAL 0x1 /* queries from the kernel */
从groups的值为1,可知hostguard
使用netlink
从内核接收实时进程创建,退出的信息,也就是hostguard
有做进程实时监控功能。
杀掉10501
进程,看看会如何?
[email protected]#ps aux|grep hostguard|grep -v "grep"
root 1258 0.0 0.0 41000 1512 ? Ss 2019 99:02 /usr/local/hostguard/bin/hostguard -l /usr/local/hostguard/log
root 10501 0.4 0.2 1229132 17608 ? Sl Jun30 29:44 /usr/local/hostguard/bin/hostguard -l /usr/local/hostguard/log
[email protected]#kill -9 10501
[email protected]#ps aux|grep hostguard|grep -v "grep"
root 1258 0.0 0.0 41000 1512 ? Ss 2019 99:02 /usr/local/hostguard/bin/hostguard -l /usr/local/hostguard/log
root 55611 25.0 0.1 636692 10920 ? Sl 16:46 0:00 /usr/local/hostguard/bin/hostguard -l /usr/local/hostguard/log
可见重新创建了55611
子进程。
如果杀掉1258
进程,就没有再创建进程了,只能重启服务了。
[email protected]#kill -9 1258
[email protected]#ps aux|grep hostguard|grep -v "grep"
root 55611 1.7 0.1 1226520 13796 ? Sl 16:46 0:02 /usr/local/hostguard/bin/hostguard -l /usr/local/hostguard/log
[email protected]#ps aux|grep hostguard|grep -v "grep"
root 55611 1.7 0.1 1226516 13796 ? Sl 16:46 0:02 /usr/local/hostguard/bin/hostguard -l /usr/local/hostguard/log
[email protected]#ps aux|grep hostguard|grep -v "grep"
root 55611 1.7 0.1 1226520 13796 ? Sl 16:46 0:02 /usr/local/hostguard/bin/hostguard -l /usr/local/hostguard/log
[email protected]#ps aux|grep hostguard|grep -v "grep"
root 55611 1.6 0.1 1226516 13804 ? Sl 16:46 0:02 /usr/local/hostguard/bin/hostguard -l /usr/local/hostguard/log
从这一点,说明hostguard
并没有对服务的防护能力。
hostguard
单从进程行为来看,有如下能力:
inotify
进行实时文件监控netlink
进行实时进程事件监控=========================================
暗号:7ae7c