黑客入侵Web服务器以后,通常会通过系统漏洞进一步提权,获得root权限。我们试图通过搜集Linux服务器的bash操作日志,通过训练识别出特定用户的操作习惯,然后进一步识别出异常操作行为。完整演示代码请见本书GitHub上的5-2.py。
1.数据搜集和数据清洗
Schonlau在他的个人网站:http://www.schonlau.net/ 上发布了针对Linux操作的训练数据(见图5-3)。
图5-3 Schonlau个人网站
训练数据中包括50个用户的操作日志(见图5-4),每个日志包含15000条操作命令,其中前5000条都是正常操作,后面的10000条日志中随机包含有异常操作。为了便于分析,数据集每100条操作作为一个操作序列,同时进行了标注,每个操作序列只要有1条操作异常就认为这个操作序列异常(见图5-5)。
图5-4 操作日志的目录结构
其中以用户名作为文件名,每个用户的操作都记录在对应的文件里面。
每个文件中,按照操作顺序依次记录了操作命令。
图5-5 操作日志的内容
依次读取每行操作命令,每100个命令组成一个操作序列,保存在列表里面:
with open(filename) as f: i=0 x=[] for line in f: line=line.strip('\n') x.append(line) dist.append(line) i+=1 if i == 100: cmd_list.append(x) x=[] i=0
统计最频繁使用的前50个命令和最不频繁的前50个命令:
fdist = FreqDist(dist).keys() dist_max=set(fdist[0:50]) dist_min = set(fdist[-50:])
2.特征化
(1)去重操作命令的个数。
以100个命令为统计单元,作为一个操作序列,去重后的操作命令个数作为特征。
f1=len(set(cmd_block))
(2)最频繁使用的前10个命令。
最频繁使用的命令从某种程度上反映出当前用户的操作习惯。
fdist = FreqDist(cmd_block).keys() f2=fdist[0:10]
(3)最不频繁使用的前10个命令。
最不频繁使用的命令也从某种程度上反映出当前用户的使用习惯。
f3=fdist[-10:]
以user3为例,在完整的数据集合上统计其操作命令,去重后获得一个操作命令的字典:
['more', 'emacs-20', 'netscape', 'netscape', 'netscape', 'netscape', 'netscape', 'netscape', 'netscape', 'netscape', 'netscape', 'netscape', 'aacdec', 'cat', 'aiffplay', 'sh', 'netscape', 'rm', 'sh', 'MediaMai', 'netscape', 'netscape', 'xcal', 'launchef', 'launchef', 'sh', 'gettxt', 'hostname', 'gettxt', 'gettxt', 'gettxt', 'xconfirm', 'endsessi', 'tellwm', 'tellwm', 'xprop', 'endsessi', 'xdm', '4Dwm', 'toolches', 'xwsh', 'csh', 'aiffplay', 'rlogin', 'xterm', 'aiffplay', 'rlogin', 'csh', 'sh', 'sh', 'netscape', 'xwsh', 'csh', 'netscape', 'cpp', 'sh', 'xrdb', 'cpp', 'sh', 'xrdb', 'mkpts', 'env', 'csh', 'csh', 'csh', 'userenv', 'sh', 'csh', 'kill', 'wait4wm', 'xhost', 'xsetroot', 'reaper', 'cat', 'mail', 'csh', 'launchef', 'launchef', 'sh', 'hostname', 'cat', 'mail', 'csh', 'launchef', 'launchef', 'sh', 'hostname', 'cat', 'mail', 'csh', 'launchef', 'launchef', 'sh', 'sh', 'launchef', 'launchef', 'sh', 'netstat', 'netscape', 'netscape']
对应的特征为:
[36, ['gettxt', 'xsetroot', 'xhost', 'kill', 'xrdb', 'wait4wm'], ['cat', 'sh', 'xprop', 'cpp', 'more', 'launchef']]
KNN只能以标量作为输入参数,所以需要将f2和f3标量化,最简单的方式就是和统计的最频繁使用的前50个命令以及最不频繁使用的前50个命令计算重合程度:
f2 = len(set(f2) & set(dist_max)) f3=len(set(f3)&set(dist_min))
3.训练模型
标识文件的内容:每行50列,分别代表每个用户的当前操作序列,正常操作标识为0,异常操作标识为1。
从标识文件中加载针对操作序列正常和异常的标识:
def get_label(filename,index=0): x=[] with open(filename) as f: for line in f: line=line.strip('\n') x.append( int(line.split()[index])) return x
加载user3的操作数据,并将前120个操作序列作为训练序列,后30个操作序列作为测试序列。
user_cmd_list,user_cmd_dist_max,user_cmd_dist_min=load_user_cmd("../data/MasqueradeDat/User3") user_cmd_feature=get_user_cmd_feature(user_cmd_list,user_cmd_dist_max,user_cmd_dist_min) labels=get_label("../data/MasqueradeDat/label.txt",2) y=[0]*50+labels x_train=user_cmd_feature[0:N] y_train=y[0:N] x_test=user_cmd_feature[N:150] y_test=y[N:150]
调用KNN函数进行训练:
neigh = KNeighborsClassifier(n_neighbors=3) neigh.fit(x_train, y_train) y_predict=neigh.predict(x_test)
4.效果验证
测试结果表明,准确率约80%,不是很理想。
score=np.mean(y_test==y_predict)*100