我是靠谱客的博主 幸福山水,这篇文章主要介绍使用深度学习识别webshell,现在分享给大家,希望可以做个参考。

在做毕设的时候选的这个题目,实际在完成的过程中也有了一些收获,在这里记录下
首先是样本,webshell黑样本主要来源于github上的webshell收集项目,白样本来自于github上的开源框架。我也尝试过asp,jsp语言的恶意脚本识别,其实识别效果也很不错,能有95%左右,但是asp,jsp这些语言的恶意脚本数量太少,只有大约1000个左右,说服力不是很强。php样本的数量和质量都要高一些,最终我所搜集到了5000个webshell,以及10000个php白样本
样本链接:https://pan.baidu.com/s/1AdpfAgL3sT2C77RYLwImaQ
提取码:dj4w
完整代码链接:https://pan.baidu.com/s/13sBlnuSbatsdNEkPoDJg9Q
提取码:3tym

词向量提取特征方法:用的是sklearn自带的词向量化器,提词方法是用正则匹配来匹配单词边界,最后生成两个numpy数组,x里存放提取的词向量,y里存放黑白样本的标记。实际实验下来,词向量提取特征识别webshell正确率只有70%左右,和其他的方法相比还是不行。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def get_feature_by_bag_tfidf(): global white_count global black_count global max_features print("max_features=%d" % max_features) webshell_files_list = load_files(webshell_dir) y1 = [1] * len(webshell_files_list) black_count = len(webshell_files_list) wp_files_list = load_files(whitefile_dir) y2 = [0] * len(wp_files_list) white_count = len(wp_files_list) x = webshell_files_list + wp_files_list y = y1 + y2 CV = CountVectorizer(ngram_range=(1, 1), max_features=10000, token_pattern=r'bw+b', min_df=1, max_df=1.0) x = CV.fit_transform(x).toarray() transformer = TfidfTransformer(smooth_idf=False) x_tfidf = transformer.fit_transform(x) x = x_tfidf.toarray() print("黑样本", black_count, "白样本", white_count) x = np.array(x) y = np.array(y) return x, y

tf-idf算法,即逆词频统计,即是在词向量提取特征的基础上进行逆词频统计,可以看到实际代码也就比词向量提取特征多了个tf-idf转换。这里的ngram_range其实用处不大,特别是限定最大长度为10000的时候,因为实际webshell里词与词的组合变化非常多,就算只计算连续两个词的组合也有很多种,所以在词库上限定死为10000的情况下,实际n-gram和1-gram是没有区别的,我的实验结果也说明了这一点。实际实验下来,tf-idf提取特征识别webshell正确率还是可以的差不多能有95%左右

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def get_feature_by_bag_tfidf(): global white_count global black_count global max_features print("max_features=%d" % max_features) webshell_files_list = load_files(webshell_dir) y1 = [1] * len(webshell_files_list) black_count = len(webshell_files_list) wp_files_list = load_files(whitefile_dir) y2 = [0] * len(wp_files_list) write_txt_byline(all_file_name) white_count = len(wp_files_list) x = webshell_files_list + wp_files_list y = y1 + y2 CV = CountVectorizer(ngram_range=(1, 1), max_features=10000, token_pattern=r'bw+b', min_df=1, max_df=1.0) x = CV.fit_transform(x).toarray() transformer = TfidfTransformer(smooth_idf=False) x_tfidf = transformer.fit_transform(x) x = x_tfidf.toarray() print("黑样本", black_count, "白样本", white_count) x = np.array(x) y = np.array(y) return x, y

文件字节分布+区间熵:这个特征提取方法是从识别exe文件参考来的,一般来说恶意exe文件,比如勒索软件一类的,因为难以提取直接的静态文本特征所以采用这种方法,但是webshell有直接的文本特征,而且大小相比于exe文件要小很多。字节分布就是文件以二进制读入时,0-255个字节出现的次数,区间熵就是计算每1024字节的熵,计算文件最后256个1024字节区间的熵,不够的补0,多了的话取最后256个,最后组合成512维的特征向量。实际实验下来,这种特征提取方法的识别准确率最高,在训练集:测试集大小为1:9的时候都能有97%的测试集正确率,缺点是有一定的不可解释性。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def generate_byte_feature(file_name): with open(file_name, mode='rb') as f: file_rb = np.fromfile(f, dtype=np.ubyte) byte_laymap = Counter(file_rb) file_length = len(file_rb) byte_layout = [] # 统计0-255个字节出现的次数 for byte in range(0, 256): # 0-255字节出现的次数 byte_layout.append(byte_laymap[byte]) current_loc = 0 # 滑动窗口统计熵 step = 1024 # 滑动窗口一次移动字节数 entro_list = [] while current_loc <= file_length: if current_loc + step > file_length: end = file_length else: end = current_loc + step entro_list.append(Entropy(file_rb[current_loc:end])) current_loc = current_loc + step final_result = byte_layout + entro_list if len(final_result) < 512: final_result = np.array(final_result) final_result = list(np.pad(final_result, (0, 512 - len(final_result)), 'constant', constant_values=(0, 0))) return final_result[0:512] else: return final_result[0:512]

文件灰度图化:本质上也是通过文件的二进制特征来识别webshell,只不过是把文件读取的字节转换成一维数组,然后再reshape成64乘64,128乘128,256乘256这样形式的二维数组,然后以灰度图的形式保存,就得到了webshell的灰度图,然后通过图像识别的方法来识别这些灰度图。实验下来发现识别效果还行,128*128大小的灰度图识别效果最好,能达到95%左右。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
def myresize_image(myimage, padding_mode=1,size=data_pic_size ): # 两种填充方式,1和2,1为重复填充,2为补0填充 pixel_num = myimage.shape[0] if pixel_num <= 5: # 如果文件大小极小,视作空文件处理 return np.array([0]), -1 total_pixel = size * size if total_pixel >= pixel_num: if padding_mode == 1: recycle_num = total_pixel // pixel_num result = myimage for temp in range(0, recycle_num - 1): result = np.hstack((result, myimage)) result = np.hstack((result, myimage[0:total_pixel - result.shape[0]])) result = result.reshape(size, size) return result, 1 else: result = np.pad(myimage, (0, total_pixel - pixel_num), 'constant', constant_values=(0, 0)) result = result.reshape(size, size) return result,1 if total_pixel < pixel_num: result = myimage[pixel_num - total_pixel:pixel_num] # 如果字节过多,取最后的文本 result = result.reshape(size, size) return result, 1 def generate_pic_data(dir, type): g = os.walk(dir) file_count = 0 for path, d, filelist in g: # print d; for filename in filelist: # print os.path.join(path, filename) if filename.endswith('.php') or filename.endswith('.txt'): fulepath = os.path.join(path, filename) # print("正在转成图片 %s" % fulepath) file_count = file_count + 1 f = open(fulepath, mode='rb') image = np.fromfile(f, dtype=np.ubyte) pic_array, flag = myresize_image(image) temp = random.randint(0, 100) if temp >= 90: # >=n,表示n%的数据作为测试集 save_dir = "picdata/" else: save_dir = "picdata_test/" if flag == 1: save_path = save_dir + type + "/" + str(file_count) + ".png" cv2.imwrite(save_path, pic_array) print(save_path + "已保存") if file_count >= max_sample_num: cv2.waitKey(0) return cv2.waitKey(0)

最后

以上就是幸福山水最近收集整理的关于使用深度学习识别webshell的全部内容,更多相关使用深度学习识别webshell内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(79)

评论列表共有 0 条评论

立即
投稿
返回
顶部