本文参考文献:https://www.researchgate.net/publication/316176048_Malware_traffic_classification_using_convolutional_neural_network_for_representation_learning
僵尸网络检测是网络安全中的一个重要课题。本文是在参考了Wei Wang的论文后,经过修改而来。
原文中,使用的数据集的僵尸网络的分布没有特别地指出,但是其文章的检测精度很高,所以很有可能是训练集与测试集有相同数量种类的僵尸网络。这样是与现实不符的。(当然不能确定,只是本人的猜测。)
因此本文使用的数据集是UBN的botnet数据集。该数据集与别的数据集相比真实性更高。其中训练集包含7种僵尸网络,测试集包含16种僵尸网络。利用该数据集训练并且测试可以更好的体现出检测器对于从未见过的僵尸网络的检测效果,也更贴近现实。
我们的数据集是一些.pcap文件,其中是抓包工具抓下来的包。为了能够分析并且训练CNN,我们需要组织一下这些数据。一般经典的方法是基于<源地址,目标地址,源端口,目标端口,传出层协议> 的五元组进行划分。 其中又分为单向的flow和双向的session。
这里推荐大家一个工具: PcapSplitter。该工具可以基于connection将数据包划分为不同的文件。通过PcaPSplitter划分后,每个文件中包含的是一次connection的双方接发的包。也就是基于Session划分文件。
因此数据划分我们通过PcapSplitter,将数据集划分为不同的connection。
在基于机器学习的僵尸网络的方法中,特征提取是最重要的一环。如果能提取出能够正确反应僵尸网络特性的特征,模型就会有很高的精确度。
然而对于CNN这种representing learning,我们不需要花很大的精力去研究特征。网络本身会不断地学习,提取。但是我们依旧需要将我们的数据集转换为能输入到CNN的形式。
本文使用的方法是对于每个connection,我们按照时间顺序提取该connection的前1024字节数据。如果整个connection的数据不足1024字节的在后面补0。这样每个connection我们就可以用32x32的矩阵表示。其中里面的值都在0-255之间。原文中会将目标地址和源地址随即化。这里我们不需要随即化。
payload_table = []
count = 0
for dirname in dirk:
for name in dirk[dirname]:
if count % 1000 == 0:
print(count)
data = []
finish = 0
f = open(dirname+'/'+name,'rb')
pcap = dpkt.pcap.Reader(f)
for ts,buf in pcap:
if len(data) + len(buf) <= 1024:
for i in buf:
data.append(i)
else:
for i in buf[:1024 - len(data)]:
data.append(i)
finish = 1
if finish == 1:
break
if finish == 0:
# if len(data) == 0:
# continue
j = [0 for i in range(1024 - len(data))]
data.extend(j)
pay1 = dpkt.ethernet.Ethernet(buf).data
src_dst = ('%d.%d.%d.%d'%tuple(list(pay1.dst)),'%d.%d.%d.%d'%tuple(list(pay1.src)))
data.append(src_dst)
payload_table.append(data)
count += 1
payload_table = pd.DataFrame(payload_table)
数据准备好就可以搭建CNN了。由于我们的输入数据跟手写体的图像数据很像,因此我们的CNN结构与LeNet的结构很像。
model = Sequential()
model.add(Conv2D(32,(5,5),activation = 'relu',input_shape=(32,32,1),padding='same'))
model.add(MaxPooling2D(pool_size=(2, 2),padding='same',strides=(2,2)))
model.add(Conv2D(64,(5,5),activation = 'relu',padding='same'))
model.add(MaxPooling2D(pool_size=(2,2),padding='same',strides=(2,2)))
model.add(Flatten())
model.add(Dropout(0.5))
model.add(Dense(1024, activation='tanh'))
model.add(Dense(10, activation='tanh'))
model.add(Dense(2, activation='softmax'))
通过以上结构的CNN训练出来的检测器。Accuracy达到0.906。具体如下
precision recall f1-score support
0 0.72 0.99 0.83 26881
1 1.00 0.88 0.93 87484
micro avg 0.91 0.91 0.91 114365
macro avg 0.86 0.94 0.88 114365
weighted avg 0.93 0.91 0.91 114365
之后我用同样的数据同样的结构再次训练,发现准确率下降了很多。应该是训练时Shuffle的问题。这种问题怎么解决还请高人指点。