目录html
AI安全初探——利用深度学习检测DNS隐蔽通道python
1、DNS 隐蔽通道简介算法
2、 算法前的准备工做——数据采集shell
3、 利用深度学习进行DNS隐蔽通道检测安全
4、 验证XShell的检测效果服务器
5、 结语网络
1、DNS 隐蔽通道简介app
DNS 通道是隐蔽通道的一种,经过将其余协议封装在DNS协议中进行数据传输。因为大部分防火墙和入侵检测设备不多会过滤DNS流量,这就给DNS做为隐蔽通道提供了条件,从而能够利用它实现诸如远程控制、文件传输等操做,DNS隐蔽通道也常常在僵尸网络和APT攻击中扮演着重要的角色。框架
DNS隐蔽通道能够分为直连和中继两种模式。直连也就是Client直接和指定的目标DNS Server(受权的NS 服务器)链接,经过将数据编码封装在DNS协议中进行通讯,这种方式速度快,可是限制比较多,不少场景不容许用户指定DNS Server。而中继模式的DNS通道则更为隐蔽,但同时也由于数据包到达目标DNS Server前须要通过多个DNS查询服务器,因此速度上较直连模式慢不少。中继模式的DNS通道原理如图1所示。dom
图1 中继模式下的DNS隐蔽通道原理
例如,前段时间著名的XShell DNS通道攻击,黑客在Xshell中植入恶意代码,经过DNS隐蔽通道外发用户敏感数据的示例如图2 所示,黑客将外发数据藏在nylalobghyhirgh.com子域名中。
图2 Xshell DNS隐蔽通道,黑客将外发数据藏在nylalobghyhirgh.com子域名中
DNS 隐蔽通道从提出到如今已经有了不少实现工具,历史比较早的有NSTX、Ozymandns,目前比较活跃的有iodine、dnscat2、dns2tcp,其余不太常见的还有DeNise、Heyoka等。不一样工具的核心原理类似,但在编码、实现细节和应用场景方面存在必定的差别。
本文使用卷积神经网络(CNN)来检测DNS隐蔽通道。第一步工做是样本数据采集。
利用上述DNS隐蔽通道工具进行“黑”样本采集工做见另外一篇博文《DNS隐蔽通道检测——数据收集,利用iodine进行DNS隐蔽通道样本收集》,其流程是先抓取DNS隐蔽通道工具攻击过程当中的网络流量pcap包,而后利用wireshark工具将pcap包转换为机器学习算法可以识别文本文件。这是一个体力活,我收集到的业界流行的DNS 隐蔽通道工具的数据样本如图3所示。
图3 收集的DNS隐蔽通道工具示意样本
以dnscat2工具为例,其生成的一个样本见图4,能够看到DNS报文里包含了大量的较长子域名,而外发数据便藏在这些子域名中(我使用的主域名是friendsakka.xyz)。
图4 dnscat2工具生成的示意样本
至于“白”样本收集,咱们使用的是某高校的校园网络流量。黑白样本收集好之后,就能够进入检测算法环节了。
本文使用CNN(卷积神经网络)来检测DNS隐蔽通道,在介绍算法前,先简单介绍下CNN。
CNN(卷积神经网络)经常使用于图像识别并取得了极佳的效果。图5展现的是一个典型的卷积神经网络结构。该网络包含两个卷积层(convolution layer),两个池化层(pooling layer)和一个全链接层(fully connected layer)。
图5 典型的卷积神经网络结构
卷积神经网络的基本思想和咱们人类大脑识别图像的机制是一致的。例如,当看到一张“喵星人”图像时,咱们之因此认为它是“喵星人”,是由于咱们看到它有萌萌的头、长长的尾巴、柔软光滑的皮毛等明显特征,经过组合(更高层次的抽象)这些特征,咱们的大脑最终即可作出准确的判断。卷积神经网络的基本思想也是相似,核心理念包括:
若是你尚未理解的话,咱们再看下面这个例子,专家们设计了包含10个卷积层,4个池化层和2个全链接层的卷积神经网络,见图6所示,该网络主要用于图像识别。专家们发现,在比较低的层,神经元倾向于学习一些简单的模式,好比图像边缘、颜色、条带灯;而在比较高的层,神经元可以检测到一些更为高层次的抽象特征,好比整辆轿车等。
图6 专家构建的用于图像识别的卷积神经网络
CNN的诞生是为了解决图像处理问题。在安全界,瀚思科技开发出了基于深度学习的二进制病毒样本检测技术,能够作到沙箱同等水平的 99% 的检测准确率,而误报率低于 1/1000。
CNN检测的图像一般是二维数据,而做为DNS隐蔽通道传输的子域名虽是一维的文本数据,但一样能够用CNN进行处理。在本文的DNS隐蔽通道检测中,咱们使用一维的卷积函数处理DNS子域名片断,以提炼高级特征进一步分析。
利用CNN进行DNS隐蔽通道检测的代码框架以下:
def run(): X, Y, max_len, volcab_size = get_data() trainX, testX, trainY, testY = train_test_split(X, Y, test_size=0.2, random_state=42) model = get_cnn_model(max_len, volcab_size) model.fit(trainX, trainY, validation_set=(testX, testY), show_metric=True, batch_size=32)
大体流程是先获取黑白样本数据,而后将80%的数据用于训练,剩下20%的数据用于CNN模型验证。
其中,get_cnn_model使用了python的TensorFlow库tflearn,其代码以下:
def get_cnn_model(max_len, volcab_size): # 构建CNN模型 network = tflearn.input_data(shape=[None, max_len], name='input') # 为了进行数据降维加入了embedding层 network = tflearn.embedding(network, input_dim=volcab_size, output_dim=64) # 卷积层使用了一维的卷积函数 branch1 = conv_1d(network, 128, 3, padding='valid', activation='relu', regularizer="L2") branch2 = conv_1d(network, 128, 4, padding='valid', activation='relu', regularizer="L2") branch3 = conv_1d(network, 128, 5, padding='valid', activation='relu', regularizer="L2") network = merge([branch1, branch2, branch3], mode='concat', axis=1) network = tf.expand_dims(network, 2) # 最大池化操做 network = global_max_pool(network) # 加入dropout防止过拟合 network = dropout(network, 0.5) # 全链接 network = fully_connected(network, 2, activation='softmax') # 回归操做 network = regression(network, optimizer='adam', learning_rate=0.001, loss='categorical_crossentropy', name='target') # 构建深度神经网络模型 model = tflearn.DNN(network, tensorboard_verbose=0) return model
在上述模型中,为了进行数据降维先加入了embedding层,其本质和word2vec同样,由于在DNS 隐蔽通道的子域名中包含了大量的字符而致使数据输入维度太高,代码中output_dim=64表示将数据输入下降维度到64维。接下来咱们使用一维的卷积函数conv_1d处理DNS子域名片断,提炼高级特征进一步分析。因为典型的一维卷积函数处理文字片断的大小一般为3、4、5,咱们也使用这些典型参数。此外,模型中加入了dropout,用于防止过拟合。
获取黑白样本数据的代码以下,其中包括对原始的子域名字符进行字典编码(先获得黑白样本全部子域名字符集合),并使用pad_sequences函数按照固定长度进行子域名长度对齐操做(因CNN要求各样本数据输入维度一致,而某些子域名很短,某些子域名很长,pad_sequences将短的子域名采用特殊数字进行填充补齐,使它们长度一致):
def get_data(): black_x, white_x = get_local_data() black_y, white_y = [LABEL.black]*len(black_x), [LABEL.white]*len(white_x) X = black_x + white_x labels = black_y + white_y # Generate a dictionary of valid characters valid_chars = {x:idx+1 for idx, x in enumerate(set(''.join(X)))} max_features = len(valid_chars) + 1 maxlen = np.max([len(x) for x in X]) # Convert characters to int and pad X = [[valid_chars[y] for y in x] for x in X] X = pad_sequences(X, maxlen=maxlen, value=0.) # Convert labels to 0-1 Y = to_categorical(labels, nb_classes=2) return X, Y, maxlen, max_features
其中,get_local_data主要是从样本文件中提取DNS子域名。
def get_local_data(tag="labeled"): data_path = "latest_metadata_sample" black_data, white_data = [], [] for dir_name in ("black", "white_like"): dir_path = "%s/%s_%s" % (data_path, tag, dir_name) for path in iterbrowse(dir_path): with open(path) as f: for line in f: _, subdomain = extract_subdomain(line) if subdomain is not None: if "white_like" in path: white_data.append(subdomain) elif "black" in path: black_data.append(subdomain) return black_data, white_data
核心代码讲解完毕,开始进行模型训练。在个人我的电脑上,算法运行时间大概17小时,最后的结果以下:
Run id: 6U1KPD Log directory: /tmp/tflearn_logs/ -- Training Step: 5131 | total loss: 0.03967 | time: 6406.696s | Adam | epoch: 001 | loss: 0.03967 - acc: 0.9888 | val_loss: 0.02546 - val_acc: 0.9926 -- iter: 164165/164165 -- Training Step: 10262 | total loss: 0.03562 | time: 6422.500s5776/164165 | Adam | epoch: 002 | loss: 0.03562 - acc: 0.9917 | val_loss: 0.01793 - val_acc: 0.9948 -- iter: 164165/164165 -- Training Step: 15393 | total loss: 0.03433 | time: 6357.422s | Adam | epoch: 003 | loss: 0.03433 - acc: 0.9888 | val_loss: 0.01432 - val_acc: 0.9962 -- iter: 164165/164165 -- Training Step: 20524 | total loss: 0.02852 | time: 6312.083s | Adam | epoch: 004 | loss: 0.02852 - acc: 0.9892 | val_loss: 0.01186 - val_acc: 0.9972 -- iter: 164165/164165 -- Training Step: 25655 | total loss: 0.02441 | time: 6292.232s | Adam | epoch: 005 | loss: 0.02441 - acc: 0.9947 | val_loss: 0.01398 - val_acc: 0.9960 -- iter: 164165/164165 -- Training Step: 30786 | total loss: 0.01890 | time: 6286.252s | Adam | epoch: 006 | loss: 0.01890 - acc: 0.9930 | val_loss: 0.01373 - val_acc: 0.9963 -- iter: 164165/164165 -- Training Step: 35917 | total loss: 0.00921 | time: 6261.734s | Adam | epoch: 007 | loss: 0.00921 - acc: 0.9984 | val_loss: 0.01290 - val_acc: 0.9966 -- iter: 164165/164165 -- Training Step: 41048 | total loss: 0.00780 | time: 6266.017s | Adam | epoch: 008 | loss: 0.00780 - acc: 0.9994 | val_loss: 0.01177 - val_acc: 0.9970 -- iter: 164165/164165 -- Training Step: 46179 | total loss: 0.01850 | time: 6257.918s | Adam | epoch: 009 | loss: 0.01850 - acc: 0.9951 | val_loss: 0.01109 - val_acc: 0.9971 -- iter: 164165/164165 -- Training Step: 51310 | total loss: 0.02062 | time: 6258.476s | Adam | epoch: 010 | loss: 0.02062 - acc: 0.9953 | val_loss: 0.00966 - val_acc: 0.9974 -- iter: 164165/164165
能够看到算法迭代了10次,每次训练时间一个多小时,最终的检测精度在99.53%,使用CNN进行DNS隐蔽通道的检测效果初步看来还不错。可是,由于训练样本和测试样本的内在数据分布规律是相同的,该精度再高也可能存在必定的过拟合风险。下面咱们利用前段时间著名的XShell DNS隐蔽通道攻击来评估算法的检测能力。
咱们尝试用训练出的算法检测前段时间著名的XShell隐蔽通道攻击,其进行攻击的域名为nylalobghyhirgh.com,将包含该攻击的DNS样本加入到模型预测中:
def predict(): testX, testY = get_xshell_data() model = get_cnn_model() .... predictions = model.predict(testX) cnt = 0 for i,p in enumerate(predictions): if abs(p[2]-testY[i][2]) < 0.1: cnt += 1 print cnt/(len(predictions)+.0)
代码运行后获得的检测准确率为97.3%,也就意味着nylalobghyhirgh.com下97.3%的子域名均可能是在利用DNS隐蔽通道传输数据。
上述验证代表,使用CNN能够有效地检测DNS隐蔽通道。固然,最终的检测准确率还需在真实而复杂的网络环境中长期运行观察而定。
本文只是AI安全初探的一次尝试,大体说明了使用深度学习算法CNN进行安全检测的基本流程,文中有写得不明白的地方,欢迎你们留言一块儿探讨。
转载请注明出处:http://www.cnblogs.com/bonelee/p/8109172.html
参考资料:
一、http://blog.csdn.net/baobei0112/article/details/54906309