导语:用人工智能的方法建立一套自己的用户行为分析引擎是解决高级安全人力问题的根本。
0x00、AI在安全行业的应用前景
简单对国内外安全公司做了一下调研,发现目前AI安全投资重点:
通过机器学习或者深度学习技术检测恶意软件替换传统的基于特征杀软技术
提升SOC安全运营中心效率
反欺诈
百度指数
从2016年3月,人工智能+网络安全关键字热度。
google趋势
从2017年1月,人工智能+网络安全关键字热度。
人工智能技术兴起时间在2016年3月开始,而AI公司主要集中在北京。
下面我选择一个方向,提升SOC效率方面其中的UBA技术。
0x01、产品需求
目前基于关联规则的SIEM产品市场越来越难做了,因为很多企业级用户都感觉没什么用,其实也不是没用,只是需要一支对黑客行为有着强大直觉的高级IT安全运维队伍,然而没有多少用户有这种超能力。所以用人工智能的方法建立一套自己的用户行为分析引擎是解决上述高级安全人力问题的根本。
0x02、产品场景定义
对于人工智能需要解决问题,首先确定使用场景,我们先假定一个这样的场景:服务器安全中的shell审计功能。
命令收集架构:通过更改的bash收集登陆堡垒机的用户的命令,然后把数据存储到ES,然后使用UBA引擎分析。
0x03、UBA分析引擎思路
UBA的本质是动态建立正常用户行为基线,通过行为基线预测新执行的命令序列是不是异常行为。人工智能UBA引擎,必须是可以通过训练定义出用户的正常行为。
根据上述需求,建立以下机器学习建模形式。
安全机器学习技术的尴尬
也看了市面上很多AI安全大佬的文章,但是发现一个很严重的问题,他们的训练集都是很古老的数据,2000年以前的数据,我晕,今年都2018年的了,这严重和事实不符。所以说,要想做好AI模型提供优质的原始数据。并且做好数据标注。这里的标注其实就是资深高级IT分析人员分析结果。
有幸在朋友的公司搭建的shell审计系统中拿到了200万数据样本。这些是我们分析的数据源。
0x04、UBA分析引擎算法实现
拿到数据后,做的第一件事就是清洗数据,根据包含的命令行确定其风险指数。
(1)第一类命令:低危命令风险值:1
(2)第二类命令:中危命令风险值:2
(3)第三类命令:高危命令风险值:3
当然我们可以做更详细的分支,例如:
@1、长期经验总结
@2、蜜罐系统收集的命令
备注:1、数据由朋友提供,隐私原因,不能公开太多请见谅。2、当然这里有很多情况,比如说黑客使用低危命令完成数据窃取操作,命令参数对整个操作行为危险程度的影响等,我这里只是说明一种思维方式,具体的规则还需要从实践中摸索。
数据清洗程序
@1、原始数据集:
2017-03-28T17:20:55compute068016,User1,100.14.7.169,"echo ""export PS1=" 2017-03-28T17:21:52,s-coute003085,User2,100.14.7.169,exit
@2、清洗后数据形式:
Date,Time,clock,hostname,username,sip,cmd,risklevel,command 2017-03-28,17:20:55,17, p-compute068016,User2,100.14.7.169,echo,1,"""echo """"export PS1=""" #!/usr/bin/python2 # -*- coding: utf-8 -*- import sys import csv csvfile2 = file('/Users/xxx/Desktop/xxx-2.csv', 'wb') writer = csv.writer(csvfile2) csvfile = file('/Users/xxx/Desktop/xxx.csv','rb') reader = csv.reader(csvfile) cmdlist=[] cmdlist2=[] cmdlist3=[] with open('cmd.txt', 'r') as file_to_read: for line in file_to_read.readlines(): cmdlist.append(line.strip()) with open('cmd2.txt', 'r') as file_to_read: for line in file_to_read.readlines(): cmdlist2.append(line.strip()) with open('cmd3.txt', 'r') as file_to_read: for line in file_to_read.readlines(): cmdlist3.append(line.strip()) for line in csvfile: line = line.split(",") m_ctime = line[0] m_hostname = line[1] m_username = line[2] m_src_ip = line[3] m_cmd=line[4].strip() l = str(m_ctime).split("T")[0] r = str(m_ctime).split("T")[1] r2 = str(r).split(":")[0] for w in cmdlist: if w in m_cmd: writer.writerow([l, r, r2, m_hostname, m_username, m_src_ip, '1',w]) for w in cmdlist2: if w in m_cmd: writer.writerow([l, r, r2, m_hostname, m_username, m_src_ip, '2',w]) for w in cmdlist3: if w in m_cmd: writer.writerow([l, r, r2, m_hostname, m_username, m_src_ip, '3',w]) if __name__ == '__main__': reload(sys) sys.setdefaultencoding('utf-8')
用户聚类程序
根据不同用户分别聚类,根据pandas产生的编号确定用户username。
# -*- coding: utf-8 -*- import pandas as pd import numpyas np import matplotlib.pyplotas plt import csv from sklearn.clusterimport KMeans userdata =pd.DataFrame(pd.read_csv('trainresult1.csv',header=0)) tmp = np.array([userdata['no'], userdata['count']]).T from sklearn.clusterimport KMeans kms = KMeans(n_clusters=3) y = kms.fit_predict(tmp) # 将分类结果以散点图形式展示 fig = plt.figure(figsize=(10, 6)) plt.xlabel('no') plt.ylabel('count') for iin range(0, len(y)): if (y[i] == 0): plt.plot(tmp[i, 0], tmp[i, 1], "*r") elif(y[i] == 1): plt.plot(tmp[i, 0], tmp[i, 1], "sy") elif(y[i] == 2): plt.plot(tmp[i, 0], tmp[i, 1], "pb") plt.show()
把用户分为3个群。
用户KDE概率分布程序
#coding:utf-8 import numpyas np import matplotlib.pyplotas plt import pandas as pd from sklearn.neighborsimport KernelDensity userdata =pd.DataFrame(pd.read_csv('cmdlog1000000-train.csv',header=0)) tmp = userdata.username.unique() for line in tmp: one_userdata = userdata[userdata['username'] == line] two_userdata = pd.DataFrame(one_userdata[['clock','risklevel']].groupby(['clock'], as_index=False).size()[:24]) # X=two_userdata.as_matrix() two_userdata.plot(kind='bar', color='#d62728', alpha=0.5, rot=0) plt.xlabel(line+u'登陆时间段') plt.ylabel(u'登陆次数') plt.legend() plt.show()
根据每个用户建立不同的概率模型,一旦发现不符合以往登陆规律,视为异常。
关联规则挖掘(Apriori algorithm)
# -*- coding: utf-8 -*- import pandas as pd import numpyas np import matplotlib.pyplotas plt from itertoolsimport combinations from sklearn.neighborsimport KernelDensity defget_support(df): pp = [] for cnumin range(1, len(df.columns)+1): for cols in combinations(df, cnum): s = df[list(cols)].all(axis=1).sum() pp.append([",".join(cols), s]) sdf = pd.DataFrame(pp, columns=["Pattern", "Support"]) return sdf userdata =pd.DataFrame(pd.read_csv('xxx-train.csv',header=0)) tmp = userdata.username.unique() for line in tmp: one_userdata = userdata[userdata['username'] == line] s = get_support(one_userdata) print s[s.Support>= 3]
登陆用户和登陆源IP关系KDE统计分析
登陆用户和命令关系KDE统计分析
登陆用户和登陆服务器IP关系KDE统计分析
这些都作为统计模型,如果发现异常告警。
0x05、总结
本文主要通过传统的统计分析模型看一下UBA应该怎么处理数据,下一篇继续讲解持久化、工程化的方法和实践路径。