0x01:前言
直奔主题,先来看看网络层是如何进行入侵检测的:
入侵检测重点关注的,是GetShell这个动作,以及GetShell成功之后的恶意行为(为了扩大战果,黑客多半会利用Shell进行探测、翻找窃取、横向移动攻击其它内部目标)。包括自己以往的真实的工作中,更多的是分析了GetShell之前的一些“外部扫描、攻击尝试”行为,基本上是没有意义的。外部的扫描和尝试攻击无时无刻不在持续发生的,而类似于SQL注入、XSS等一些不直接GetSHell的Web攻击,暂时不在狭义的“入侵检测”考虑范围,当然,利用SQL注入、XSS等入口,进行了GetShell操作的,我们仍抓GetShell这个关键点,就如sql注入进行GETshell,常见的使用into outfile写函数,那么最简单的就是我们把流量镜像一份,孵化成日志,从uri/post/cookie等可能出现注入的地方检测是否是否了into outfile,和常用webshell形式以及状态码是否是200。
常见的可以getshell的web攻击
直接上传获取webshell、SQL注入、远程文件包含(RFI)、FTP,甚至使用跨站点脚本(XSS)作为攻击的一部分,甚至一些比较老旧的方法利用后台数据库备份及恢复获取webshell、数据库压缩等。通用功能包括但不限于shell命令执行、代码执行、数据库枚举和文件管理。
0x02:webshell的检测
可以通过监控指定目录下的所有文件的创建、修改、重命名等操作,再比如说<?php eval($_POST[1])?>时,判断为webshell,但如果只出现eval的函数,就判断为敏感函数。也可以通过webshell hash、文件名等进行检测,在GitHub上就有这么一个项目:webshell特征、某大佬之前写过通过机器学习的方法去检测webshell:初探机器学习检测PHP Webshell、本人之前也根据工作经验总结过:webshell入侵检测。
其实可以看到,从网络层检测,基于关键字等检测方式,有被绕过的风险,上面还介绍了基于目录下文件的监控到达检测风险的作用,就由此引出了HIDS(主机型入侵检测系统)
0x03:简介
HIDS(Host-based Intrusion Detection System)作为传统攻防视角的重要一环,有着不可替代的作用,可以有效的检测到从网络层面难以发现的安全问题,如:后门,反弹shell,恶意操作,主机组件安全漏洞,系统用户管理安全问题,主机基线安全风险等。
需求分析
下面引用“点融”和“美团”对HIDS的需求:
代码语言:javascript复制 1.灵活且轻量级:对系统资源需求少,系统负载占用小; 2. 有丰富的API和强大的联动能力:兼容性好,可横向扩展,支持和CMDB联动,支持Docker,可以梳理建立“白名单”(如某应用的对外连接名单,数据库名单等)。; 3.支持基线检查/系统完整性检测; 4. 支持规则引擎,能够灵活的进行规则配置(规则引擎最好可以和AgentSmith-NIDS复用);
架构
目前大部分的HIDS平台建设主要分三大部分:终端Agent监控组件,Dashboard控制面板和与SIEM、运维数据等其他平台对接的接口集合:
代码语言:javascript复制终端Agent组件:主要作用包括:监控文件变更、监控服务器状态、下发一些操作指令等(如果控制了一台HIDS服务器相当于拥有了百万台肉鸡,HIDS的研发大佬,只能帮到这了)。DashBoard:用来执行一些策略推送、资源管理方面的操作MQ && Servers:用来做负载均衡并吞吐数据到数据库Database:数据库SIEM APIs:用来将HIDS的数据和SIEM做整合
终端Agent通过对业务IT资产文件的监控可以发现一些潜在威胁的文件或者是被人中的webshell后门,也可以记录和发现文件改动。同时终端Agent肩负着把日志摆渡到数据库的工作,方便运维人员对日志进行检索,进行终端日志的统一化收集管理。这里直接使用了公司先已有的安全架构,直接将日志发送到kibana统一分析。
0x04 开源HIDS
安全部门不是盈利部门,“一个人的信息安全部”之中型公司常用开源项目二次开发,知名的HIDS项目如OSSEC、Osquery。OSSEC的主要功能包括日志监控、文件完整性检测、Rootkit检测以及联动配置,另外你也可以将自己的其他监控项集成到OSSEC中。可以参照OSSEC官网,如果你可以一样,不想参考英文文档~OSSEC_安装、OSSEC_扩展使用。
日志监控
日志是平常安全运维中很重要的一项,OSSEC日志检测为实时检测,OSSEC的客户端本身没有解码文件和规则,所监控的日志会通过1514端口发送到服务端。
在agent端ossec.conf/agent.conf 配置,需要注意的是command和full_command不能配置在agent.conf中,需要配置在ossec.conf中:
客户端监控
一个以时间日志文件,ossec/logs/alerts/2019/Jan/ossec-alerts-06.log(本次06为agent端的主机名)
auth认证日志
端口监听日志
再已启动项为例,Linux下开机启动项是应急响应中很重要的检测项,Redhat中的运行模式2、3、5都把/etc/rc.d/rc.local做为初始化脚本中的最后一个。这里我在agent的ossec.conf中新加一个监控,检测当rc.local发生改变的时候告警。
客户端监控规则
服务器监控规则
会在queue/diff/agent生成和规则id相同的文件夹,报警如下:
监控结果
这里包括做了一些端口反弹如bash、nc、python就不一一贴图了。
完整性检测
有多种类型的攻击和许多攻击向量,但所有这些都有一个独特之处:它们留下痕迹并始终以某种方式改变系统。从修改一些文件的病毒到改变内核的内核级rootkit,系统的完整性总会有一些变化。完整性检查是入侵检测的重要组成部分,可检测系统完整性的变化,通过可以通过md5检验来实现,而 命令替换在应急响应中很常见,经常被替换掉的命令例如ps、netstat、ss、lsof等等。另外还有SSH后门。完整性检测的工作方式是Agent周期性的扫描系统文件,并将检验和发送给Server端。Server端存储并进行比对,发现修改是发出告警。
客户端监控配置
本文使用的属性值为check_all,即使用全部为yes,会根据周期性进行检测:
代码语言:javascript复制checkall:以下的属性全部为yesrealtime:实时监控report_changes:报告文件变化,文件类型只能是文本check_sum:监测MD5和SHA1 HASH的变化,相当于设置check_sha1sum=”yes”和check_md5sum=”yes”check_sha1sum:监测SHA1 HASH的变化check_md5sum:监测MD5 HASH的变化check_size:监测文件大小check_owner:监测属主check_group:监测属组check_perm:监测文件权限restrict:限制对包含该字符串的文件监测
服务端监控规则
服务端数据存放到服务端的/var/ossec/queue/syscheck目录下,这里健康的是常被攻击的web路径,如当修改/var/www/html时,告警级别为12
rootkit检测
ossec检测rootkit的原理是对比/var/ossec/etc/shared/rootkit_fikes.txt文件,该文件包含了rootkit常用的文件,和病毒库一样。
会扫描整个文件系统,检测异常文件和异常的权限设置,文件属主是root,但是其他用户可写是非常危险的,rootkit将会扫描这些文件。同时还会检测具有suid权限的文件、隐藏的文件和目录。另外还会检测隐藏端口、隐藏进程、/dev目录、网卡混杂模式等。
这里找了个经典的rootkit测试,adore-ng
0x05:个人HIDS实践
从SQLmap到HIDS
刚学习安全的时候,SQL注入的内容还是挺丰富的,当时是怎么快速入手的呢?
如 SQL注入的分类:SQLMAP支持1、基于布尔的盲注2、基于时间的盲注3、基于报错注入4、联合查询注入5、堆查询注入,那SQL注入的分类应该就这些吧
SQLMAP支持“-u”、“—data”、“—cookie”、“—user-agent ”等,那容易出现注入的地方应该是这些地方吧,有了大的方向,然后再慢慢深入,回到HIDS,也没怎么深入接触HIDS,就从开源项目从回走。OSSEC的主要功能包括日志分析、文件完整性检测、Rootkit检测以及联动配置,先从这几个入手。
个人需求
有过态势感知的项目经验,态势感知的数据来源实在是太多太多了,给我一个比较大的感触就是首先得确认所需的数据源:
代码语言:javascript复制基础信息:系统版本信息 帐号信息 用户组信息 系统应用信息 系统ARP信息 CPU信息 系统环境变量 文件监控信息 硬盘信息 内核信息 内存信息 本地防火墙信息 网络连接 文件共享信息 端口监听信息 进程信息 本地路由表信息 系统服务 系统ARP信息 rpm包信息检测信息:用户登录信息(包括可登录shell,ssh公私钥,可以用户,root_id,用户登录的源ip地址等) sudo授权信息 /etc/rc.local脚本内容 计划任务/etc/cron.d 用户定义的自启动项 系统内核模块运行时的文件信息(基于白名单的md5计算内核模块文件检测) 运行进程数(基于白名单的异常进程检测) 端口网络连接信息(基于白名单的异常连接检测或基于威胁情报的异常网络连接检测) 本地防火墙信息检测 rpm包检测(diff对比以及rpm签名) 环境变量检测日志信息: bash_history(snoopy)命令记录 audit日志 auth认证日志 secure安全日志 服务日志(如中间件、数据库、FTP等)kern内核日志 自定义local5日志
基本信息获取
基本信息获取的方法比较简单,本文使用python来实现,业务的现学现卖的变成,这里使用使用psutil库获取系统信息:psutil
代码语言:javascript复制#!/usr/bin/python
#coding:utf-8import psutilimport datetimeimport time# 当前时间now_time = time.strftime('%Y-%m-%d-%H:%M:%S', time.localtime(time.time()))print(now_time)# 查看cpu物理个数的信息print(u"物理CPU个数: %s" % psutil.cpu_count(logical=False))#CPU的使用率cpu = (str(psutil.cpu_percent(1))) '%'print(u"cup使用率: %s" % cpu)#查看内存信息,剩余内存.free 总共.total#round()函数方法为返回浮点数x的四舍五入值。free = str(round(psutil.virtual_memory().free / (1024.0 * 1024.0 * 1024.0), 2))total = str(round(psutil.virtual_memory().total / (1024.0 * 1024.0 * 1024.0), 2))memory = int(psutil.virtual_memory().total - psutil.virtual_memory().free) / float(psutil.virtual_memory().total)print(u"物理内存: %s G" % total)print(u"剩余物理内存: %s G" % free)print(u"物理内存使用率: %s %%" % int(memory * 100))# 系统启动时间print(u"系统启动时间: %s" % datetime.datetime.fromtimestamp(psutil.boot_time()).strftime("%Y-%m-%d %H:%M:%S"))# 系统用户users_count = len(psutil.users())## >>> for u in psutil.users():# ... print(u)# ...# suser(name='root', terminal='pts/0', host='61.135.18.162', started=1505483904.0)# suser(name='root', terminal='pts/5', host='61.135.18.162', started=1505469056.0)# >>> u.name# 'root'# >>> u.terminal# 'pts/5'# >>> u.host# '61.135.18.162'# >>> u.started# 1505469056.0# >>>users_list = ",".join([u.name for u in psutil.users()])print(u"当前有%s个用户,分别是 %s" % (users_count, users_list))#网卡,可以得到网卡属性,连接数,当前流量等信息net = psutil.net_io_counters()bytes_sent = '{0:.2f} Mb'.format(net.bytes_recv / 1024 / 1024)bytes_rcvd = '{0:.2f} Mb'.format(net.bytes_sent / 1024 / 1024)print(u"网卡接收流量 %s 网卡发送流量 %s" % (bytes_rcvd, bytes_sent))io = psutil.disk_partitions()# print(io)# print("io[-1]为",io[-1])#del io[-1]print('-----------------------------磁盘信息---------------------------------------')print("系统磁盘信息:" str(io))for i in io: o = psutil.disk_usage(i.device) print("总容量:" str(int(o.total / (1024.0 * 1024.0 * 1024.0))) "G") print("已用容量:" str(int(o.used / (1024.0 * 1024.0 * 1024.0))) "G") print("可用容量:" str(int(o.free / (1024.0 * 1024.0 * 1024.0))) "G")print('-----------------------------进程信息-------------------------------------')# 查看系统全部进程for pnum in psutil.pids(): p = psutil.Process(pnum) print(u"进程名 %-20s 内存利用率 %-18s 进程状态 %-10s 创建时间 %-10s " % (p.name(), p.memory_percent(), p.status(), p.create_time()))
文件监控
inotify是一种文件系统变化通知机制,如增加文件、删除等事件可以立刻让用户得知,inortify参考文档,这里监控的是常受攻击的web目录,监控了文件的创建、删除、修改属性, 该机制是著名的桌面搜索引擎项目beagle引入的,并在Gamin等项目中被应用。
代码语言:javascript复制#!/usr/bin/python# encoding:utf-8import osfrom pyinotify import WatchManager, Notifier,ProcessEvent,IN_DELETE, IN_CREATE,IN_MODIFYclass EventHandler(ProcessEvent): """事件处理""" def process_IN_CREATE(self, event): print("Create file: %s " % os.path.join(event.path,event.name)) def process_IN_DELETE(self, event): print("Delete file: %s " % os.path.join(event.path,event.name)) def process_IN_MODIFY(self, event): print("Modify file: %s " % os.path.join(event.path,event.name))def FSMonitor(path='/var/www/html'): wm = WatchManager() mask = IN_DELETE | IN_CREATE |IN_MODIFY notifier = Notifier(wm, EventHandler()) wm.add_watch(path, mask,rec=True) print('now starting monitor %s'%(path)) while True: try: notifier.process_events() if notifier.check_events(): notifier.read_events() except KeyboardInterrupt: notifier.stop() breakif __name__ == "__main__": FSMonitor()
进程监控
1.可使用inotify实时监控/proc下面的文件变动即可(a.有可能进程启动、结束太快来不及读取文件内容从而没捕捉到必要信息)
2.使用psutil获取进程信息,diff下即可,基本信息中已获取进程信息
3.直接调用os模块执行命名ps -ef(嗯,我知道上面的思路好low)
文件完整性
文件完整性,本文监控了命令替换,监控的目录为/usr/bin/,获取文件路径,计算md5直接diff。
代码语言:javascript复制#!/usr/bin/python# -*- coding: utf-8 -*-import osimport hashlibimport datetimeimport difflibglobal srt1def gci(filepath):#遍历filepath下所有文件,包括子目录 files = os.listdir(filepath) #print(files) for fi in files: fi_d = os.path.join(filepath,fi) if os.path.isdir(fi_d):#判断是否是一个目录,是则继续执行循环执行gci函数 gci(fi_d) else: file=os.path.join(filepath,fi_d) #计算文件的md5值 hash = hashlib.md5() f=open(file,'rb') while True: b=f.read(1000)#每次以特定字节读取,避免内容过大,占用内存 if not b: break hash.update(b)#更新哈希对象以字符串参数 f.close() str=(file,hash.hexdigest())#返回摘要,作为十六进制数据字符串值,并定义为字典 str1=(str[0] ":" str[1]) str2=open('/root/md5.txt')#md5的文件为md5文件样本 str3=str2.read() d = difflib.HtmlDiff() f=open('/root/md6.txt','w') print (d.make_file(str1,str3),file=f)#将文件名和md5值对应,并初始md5值对比发现问题邮件发送 f.close()if __name__=="__main__": gci('/usr/bin/')# 输出文件的md5值以及记录运行时间starttime = datetime.datetime.now()endtime= datetime.datetime.now()print('运行时间:%ds'%((endtime-starttime).seconds))
rootkit检测
rootkit检测还没有好的思路,按照ossec是调用rootkit常用的文件,这里能想到的就是监控系统的文件变化,以及进程信息,若进程被rootkit隐藏,可以对比/proc,对比id查看是否被隐藏,若按照这种思路,以上的代码改改就能实现了。或许还可以直接调用chkrootkit、rhhunter进行检测。
0x06:总结
HIDS建设未完待续,欢迎指教, 从一个攻防的角度的初级建设,还是得开发大大来实现。
我们要坚持每天学习,慢慢的熬,熬到大佬们都退了休,都转了行,我们就是独当一面的扛把子,一个二十年不够,那就再来一个二十年 ~~~
参考文献
保障IDC安全:分布式HIDS集群架构设计 企业安全建设—基于Agent的HIDS系统设计的一点思路 点融开源AgentSmith HIDS—- 一套轻量级的HIDS系统
*本文作者:罹♛殇,本文属 FreeBuf 原创奖励计划,未经许可禁止转载。