第三篇—基于黑白样本的webshell检测

news/2024/7/3 0:18:41

  本篇为webshell检测的第三篇,主要讲的是基于黑白样本的webshell预测,从样本收集、特征提取、模型训练,最后模型评估这四步,实现一个简单的黑白样本预测模型。
  若有误之处,望大佬们指出

Ⅰ 基本实现步骤

  1. 样本收集:首先,你需要收集大量的黑样本(恶意的webshell)和白样本(正常的web文件)。这些样本将用于训练和测试你的检测模型。
  2. 特征提取:对于每一个样本,你需要提取出对于webshell检测有用的特征。这些特征可能包括文件的大小、文件的修改时间、文件中包含的特定字符串等等。
  3. 模型训练:使用你收集的样本和提取的特征,你可以训练一个机器学习模型来进行webshell检测。这个模型可能是一个决策树、随机森林、支持向量机、神经网络等等。
  4. 模型评估:在模型训练完成后,你需要对模型的性能进行评估。这通常包括计算模型的准确率、召回率、F1值等指标。

关于样本收集过程,需要注意的地方

  • 选取合适的正常样本和恶意样本进行降噪、向量化与随机抽样
  • 其优点是具备不错的未知威胁检测能力,其缺点是对样本要求较高。

Ⅱ 样本收集

黑样本
  直接搜github,搜集近2000+webshell文件,进行数据清洗,最后只得到了525个php的webshell,样本有点少了

白样本
  常见的CMS框架:WP、帝国、极致、TP等等
注意:在这里,收集的白样本,小版本迭代的CMS可以不收集,里面存在大量的重复,我是直接收集大版本的源码
下面是我收集的白样本以及下载地址,近4w个左右
[图片]

  • https://github.com/phpmyadmin/phpmyadmin/tree/MAINT_4_0_10
  • https://github.com/smarty-php/smarty/tree/v2.6.32
  • https://github.com/yiisoft/yii2/tree/2.0.32

接下来就是——样本清洗
白样本清洗大致思路

  1. 删除无关文件:你可以删除那些与webshell检测无关的文件,例如图片、音频、视频等非代码文件。
  2. 删除重复文件:如果你的白样本中存在大量的重复文件,那么这些文件可能会对你的模型产生过拟合的影响。因此,你需要删除这些重复的文件。
  3. 代码格式化:为了使得你的模型能够更好地理解代码的结构,你可以对代码进行格式化,例如删除多余的空格和注释,统一代码的缩进和换行等。
  4. 提取代码特征:你可以提取代码的一些特征,例如函数的数量、变量的数量、代码的长度等,这些特征可以帮助你的模型更好地理解代码。
  5. 标记样本:为了训练你的模型,你需要给你的白样本打上标签,表示这些样本是正常的web文件。
    在这里插入图片描述

  黑样本清洗大致思路,样本有点少,清洗流程主要都是去空格、去注释、去重、去空白文件。

Ⅲ 特征提取

通过两种方式:词袋模型或者opcode模型训练,再配合上TF-IDF

TF-IDF是啥?
  这是一种统计方法,用来评估一个词对于一个文件集或语料库中的其中一份文件的重要程度,字词的重要性随着它在文件中出现的次数成正比增加, 但是同时也会随着它在语料库中出现的频率成反比下降。

  1. 词袋模型 + TF-IDF模型训练
    基本流程
  • 合并黑白样本
  • 计算TF-IDF值,并保存模型

    def calculate_tfidf(self):
        # 合并黑样本和白样本
        samples = self.black_samples + self.white_samples
        # 计算TF-IDF值
        vectorizer = TfidfVectorizer(max_features=1000)
        self.features = vectorizer.fit_transform(samples)
        # 保存TF-IDF值模型
        joblib.dump(vectorizer, os.path.join(self.config_dir, "tfidf_model.pkl"))
        # 为黑样本和白样本生成标签
        self.labels = [1]*len(self.black_samples) + [0]*len(self.white_samples)
        # 保存特征和标签
        np.savez(os.path.join(self.config_dir, 'features_labels.npz'), features=self.features.toarray(), labels=self.labels)
        print(f"有效的样本总数:{len(samples)}")

最终需要形成一个特征文件,作为后续预测使用
采用词袋模型算法,计算出的样本数量 1w个
[图片]

【留下疑问】

  • 这个特征文件有什么用
  • 最后需要怎么进行评分模型处理
  • 如何提高一个预测的正确率

Ⅳ 预测模型生成

  拿到这个特征文件后,需要将黑样本标记为1,白样本标记为0,然后用以下算法,生成预测模型

  • 第一种是朴素贝叶斯算法,
  • 第二种是随机森林

用python写了两个算法的实现逻辑
【随机森林实现】

# 加载特征和标签
data = np.load('config/features_labels.npz')
features = data['features']
labels = data['labels']

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.2, random_state=42)

# 输出矩阵数量
print(f"训练集的矩阵形状:{X_train.shape}")
print(f"测试集的矩阵形状:{X_test.shape}")
# 创建并训练随机森林模型
clf = RandomForestClassifier(n_estimators=100, random_state=42)
clf.fit(X_train, y_train)

# 保存随机森林预测模型
joblib.dump(clf, "config/rf_model.pkl")
# 预测测试集
y_pred = clf.predict(X_test)

# 计算并打印检出率(召回率)和精确率
recall = recall_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)

朴素贝叶斯生成预测模型

data = np.load('config/features_labels.npz')
features = data['features']
labels = data['labels']

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(features, labels, test_size=0.2, random_state=42)

# 输出训练集和测试集的矩阵形状
print(f"训练集的矩阵形状:{X_train.shape}")
print(f"测试集的矩阵形状:{X_test.shape}")

# 创建并训练朴素贝叶斯模型
clf = MultinomialNB()
clf.fit(X_train, y_train)

# 预测测试集
y_pred = clf.predict(X_test)

# 计算并打印检出率(召回率)和精确率
recall = recall_score(y_test, y_pred)
precision = precision_score(y_test, y_pred)

以下是其预测结果
[图片]

Ⅴ 实战预测

利用训练好的模型,进行预测处理

    # 词袋模型
    tfidf_model = joblib.load('config/tfidf_model.pkl')
    # 随机森林预测模型
    rf_model = joblib.load('config/rf_model.pkl')
    # 预处理代码
    with open(file_path, 'r', errors='ignore') as f:
        code = f.read()
    code = preprocess_code(code)
    # 提取特征
    features = tfidf_model.transform([code])

    # 预测
    pred = rf_model.predict(features)

[图片]

效果没预期的那么好
这里会有一个问题,如果内容上不是携带有php文件的标签的,如"<?php>",就会默认评判会webshell
如下面所示
在这里插入图片描述

在这里插入图片描述

效果很一般,需要调整下

  • 使用MLP算法,特征提取使用词袋&TF-IDF模型
  • 特征提取使用opcode&n-gram,降低样本的噪点

  十分感谢能看到这里,这个预测还有好多好多需要完善的,貌似只使用一种方式,效果都是很一般的,下版本试一下优化下,尽可能是降低黑白样本噪点 + 其余辅助检测手段,进行文件研判。

参考文献

  • https://m.freebuf.com/articles/web/254913.html

http://lihuaxi.xjx100.cn/news/2215575.html

相关文章

Python 学习 第二册 第11章 文件

----用教授的方式学习 目录 11.1 打开文件 11.2 文件的基本方法 11.2.1 读取和写入 11.2.2 使用管道重定向输出 11.2.3 读取和写入行 11.2.4 关闭文件 11.3 迭代文件内容 11.3.1 每次一个字符&#xff08;或字节&#xff09; 11.3.2 每次一行 11.3.3 读取所有内容 …

python flask配置邮箱发送功能,使用flask_mail模块

&#x1f308;所属专栏&#xff1a;【Flask】✨作者主页&#xff1a; Mr.Zwq✔️个人简介&#xff1a;一个正在努力学技术的Python领域创作者&#xff0c;擅长爬虫&#xff0c;逆向&#xff0c;全栈方向&#xff0c;专注基础和实战分享&#xff0c;欢迎咨询&#xff01; 您的点…

Mac vscode could not import github.com/gin-gonic/gin

问题背景&#xff1a; 第一次导入一个go的项目就报红 问题分析&#xff1a; 其实就是之前没有下载和导入gin这个web框架包 gin是一个golang的微框架&#xff0c;封装比较优雅&#xff0c;API友好&#xff0c;源码注释比较明确。 问题解决&#xff1a; 依次输入以下命令。通…

【Echarts系列】水平柱状图

【Echarts系列】水平柱状图 序示例数据格式代码 序 为了节省后续开发学习成本&#xff0c;这个系列将记录我工作所用到的一些echarts图表。 示例 水平柱状图如图所示&#xff1a; 数据格式 data [{name: 于洪区,value: 2736},{name: 新民市,value: 2844},{name: 皇姑区,…

通俗范畴论2 有向图与准范畴

退一步海阔天空&#xff0c;在正式进入范畴论之前&#xff0c;我们可以重新审视一下我们是如何认识世界的&#xff0c;有了这个对人类认识世界过程的底层理解&#xff0c;可以帮助我们更好地理解范畴论。 对于人类认识世界&#xff0c;最神奇的一点就是这个世界居然是可以认识…

20.1 JSON-JSON接口以及在Go语言中使用JSON

1. 简介 JSON即JavaScript对象表示法(JavaScript Object Notation)&#xff0c;是一种用于存储和交换数据的格式&#xff0c;是一种可供人类阅读和理解的纯文本格式。 JSON既可以键值对的形式&#xff0c;也可以数组的形式&#xff0c;表示数据。 JSON最初是JavaScript的一个…

【数据结构】初识集合深入剖析顺序表(Arraylist)

【数据结构】初识集合&深入剖析顺序表&#xff08;Arraylist&#xff09; 集合体系结构集合的遍历迭代器增强for遍历lambda表达式 List接口中的增删查改List的5种遍历ArrayList详解ArrayList的创建ArrayList的增删查改ArrayList的遍历ArrayList的底层原理 &#x1f680;所属…

在Python中实现排序算法:以冒泡排序和快速排序为例

在Python中实现排序算法&#xff0c;如冒泡排序和快速排序&#xff0c;是算法和数据结构学习中的基础内容。下面我将从技术难点、面试官关注点、回答吸引力以及代码举例四个方面进行详细描述。 一、技术难点 冒泡排序&#xff1a; 双重循环&#xff1a;冒泡排序需要两层循环&…