ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

半监督深度学习实现木马流量检测:从pcap到Mnist的完整实践

半监督深度学习实现木马流量检测:从pcap到Mnist的完整实践 简介这套基于半监督深度学习的木马流量检测项目面向具备一定Python与深度学习基础的安全研究人员、高校学生及入侵检测方向开发者。项目以USTC-TFC2016数据集为对象覆盖从pcap原始流量切分、会话处理、图像化转换到Mnist格式生成及模型训练与评估的完整链路适合用于网络安全实验、毕业设计或课题预研。压缩包共193个文件约134.9MB主要包含67个Python脚本、9个模型checkpoint文件、6个文档说明、4个mat数据文件以及辅助的XML配置、PowerShell处理脚本等目录按PcapToMnist各阶段清晰划分便于对照执行。已有191人学习下载。通过该资源可掌握半监督方法在恶意流量识别中的落地流程获得可复现的数据预处理管线、训练好的模型权重及配套使用说明便于快速验证和二次开发。1. 为什么木马流量检测需要半监督深度学习安全团队每天从网关、终端和云环境抓取的原始pcap里真正被打过标注的木马样本可能不到1%。剩下99%的流量都是未标记的它们既可能隐藏着新型变种也可能只是高噪音的背景流量。如果只靠人工标注去训练一个有监督分类器数据的清洗和打标成本会直接拖垮整个检测项目。半监督深度学习在这里的价值不是替代分析师而是用少量可信标注数据作为种子让模型自己从海量未标记流量中挖掘潜在恶意模式从而提升对未知木马的召回率。这份项目资源正好提供了一个可落地的半监督检测闭环从原始pcap开始经过会话切分、净化和图像化最终生成Mnist格式的样本模型部分则给出了完整的训练脚本、多个checkpoint存档以及推理说明。整套流程基于USTC-TFC2016公开数据集既能用于毕业设计也能当作企业内部流量检测器的一个快速原型。适合已经会用Python和TensorFlow、但对流量侧领域不太熟的后端或者安全工程师也适合想研究半监督伪标签策略在网络安全场景应用的数据算法同学。2. 从pcap到Mnist木马流量的多维特征预处理全链路2.1 流量切分与会话重组PcapToSession的边界问题原始pcap文件是连续的数据包流没法直接喂给图像分类模型。第一步必须把流按照五元组源IP、目标IP、源端口、目标端口、协议切分成一个个独立会话。项目里0_Tool目录下放的流量切分工具就是干这件事的常见做法是用SplitCap这类工具它会把单个pcap拆成若干子pcap每个子pcap对应一条TCP或UDP会话。Windows环境下直接运行2_PcapToSession.ps1这个PowerShell脚本。注意脚本执行策略可能被禁用需要先放开powershell -ExecutionPolicy Bypass -File 2_PcapToSession.ps1 -PcapDir D:\PcapToMnist\1_Pcap -SessionDir D:\PcapToMnist\2_Session参数里PcapDir是存放原始pcap的目录SessionDir是切分会话后的输出目录。启动脚本前要确认源路径里不能有空格和中文否则SplitCap解析参数时会把路径截断。脚本跑完后2_Session目录下会生成大量小的pcap文件每个文件代表一次完整的会话连接。这里有一个容易忽略的细节切分工具默认会把双向流量合并成一个会话文件但如果你的pcap里混入了非IP协议比如ARP这些包会被丢弃或者单独生成文件后续处理需要留意。2.2 会话净化和统一长度ProcessSession的参数选择切分出来的会话仍然不是干净的样本因为一条会话里可能包含TCP三次握手、重传包、keep-alive包这些对木马检测没有帮助反而会引入噪声。3_ProcessSession.py负责做三件事去掉无负载的ACK和SYN包、过滤长度为零的包、对每个会话做截断或补零操作让所有会话具有相同的包长度序列。执行命令如下python 3_ProcessSession.py -i D:\PcapToMnist\2_Session -o D:\PcapToMnist\3_ProcessedSession --max_packets 100 --min_payload 20代码逻辑里--max_packets指定一个会话最多保留前100个包超过的部分直接截断--min_payload表示负载小于20字节的包会被过滤掉。这样处理的原因是木马通信通常会产生大量小包但小包也可能是正常的信令设置一个合理的阈值既能保留有效载荷又能压制无意义的ACK风暴。处理完成后每个会话被保存为一个二进制文件里面的数据是按照包顺序排列的负载长度序列。这一步的产出质量直接决定后续图像化的效果。如果你发现生成的3_ProcessedSession文件大小差异很大大概率是因为会话里有效包的数量差异过大此时需要重新调整--max_packets的值或者对超长会话做滑窗采样而不是简单截断。2.3 Session转图像与Mnist矩阵保留空间结构的必要性把处理后的会话转成图像本质是把一维的包长度序列编码成二维像素矩阵让卷积神经网络能够通过空间局部性发现流量模式。4_Session2png这一步会把每个会话文件里的数据映射为灰度图比如将每隔固定数量的包当作一行像素包长度映射到0-255的像素值。之后5_Png2Mnist.py再把PNG图统一缩放到28x28然后序列化为Mnist格式。处理流程建议按顺序执行不要跳步因为每个脚本都会读取上一个脚本的输出目录。mnist文件生成后会放在5_Mnist目录下包含train-images.idx3-ubyte、train-labels.idx1-ubyte等四个标准文件。以下是一个典型调用流程python 4_Session2png.py -i D:\PcapToMnist\3_ProcessedSession -o D:\PcapToMnist\4_Png python 5_Png2Mnist.py -i D:\PcapToMnist\4_Png -o D:\PcapToMnist\5_Mnist --train_ratio 0.8生成后的图像尺寸可以通过参数调整比如--img_size 32但注意Mnist标准是28x28改动后会破坏后续模型对checkpoint的兼容性。整个预处理链路到这里就闭环了pcap变成了模型能够直接消费的数值型samples每一行对应一个会话的全局特征。3. 半监督模型设计与checkpoint恢复教师-学生框架下的木马识别3.1 半监督自训练的核心循环伪标签与置信度筛选有监督训练要求每个样本都有标签但流量场景下标注稀缺所以本项目采用半监督自训练方法。核心思想是先用少量有标签样本训练一个初始模型教师模型让这个模型对大量无标签流量做预测把预测置信度极高的样本打上伪标签再将其混入有标签集合中训练新模型学生模型。这个过程可以迭代多轮每一轮伪标签的可信度都会随模型能力的增强而提高。伪标签不是随便用的需要设置置信度阈值。常见做法是argmax概率0.95才保留。资源里虽然没有直接把阈值参数写在文件名上但训练脚本里通常会留一个--pseudo_threshold变量你可以调整它来控制伪标签的噪声比例。阈值太高能利用的无标签数据太少阈值太低噪声会把模型带偏。实际调参时建议从0.9开始每轮迭代后观察验证集AUC。def generate_pseudo_labels(model, unlabeled_x, threshold0.95): probs model.predict(unlabeled_x, verbose0) max_probs np.max(probs, axis1) pseudo_labels np.argmax(probs, axis1) mask max_probs threshold return unlabeled_x[mask], pseudo_labels[mask]这个函数在每一轮迭代中被反复调用后面的pseudo_mask就是筛选条件。注意每次生成伪标签后要重新打乱混合数据集防止模型记忆训练顺序。另外伪标签和真实标签在loss计算中的权重可以不同常见技巧是给伪标签样本一个小于1的loss权重降低噪声样本对梯度更新的影响。3.2 模型结构与TensorFlow checkpoint的加载逻辑模型输入是28x28的灰度图像因此项目里使用的是卷积神经网络。基本结构是两个卷积层池化层再接一个全连接层和softmax输出。因为要区分正常和木马输出维度是2。半监督部分则是在这个网络基础上增加了teacher和student两套权重的交互。项目交付的checkpoint文件夹里能看到多个checkpoint-XXXX.data-00000-of-00001文件这是TensorFlow的tf.train.Checkpoint机制保存的。加载方式如下import tensorflow as tf def build_cnn(input_shape(28, 28, 1)): inputs tf.keras.Input(shapeinput_shape) x tf.keras.layers.Conv2D(32, (3, 3), activationrelu, paddingsame)(inputs) x tf.keras.layers.MaxPooling2D((2, 2))(x) x tf.keras.layers.Conv2D(64, (3, 3), activationrelu, paddingsame)(x) x tf.keras.layers.MaxPooling2D((2, 2))(x) x tf.keras.layers.Flatten()(x) x tf.keras.layers.Dense(128, activationrelu)(x) outputs tf.keras.layers.Dense(2, activationsoftmax)(x) return tf.keras.Model(inputs, outputs) model build_cnn() ckpt tf.train.Checkpoint(modelmodel) manager tf.train.CheckpointManager(ckpt, directory./checkpoint, max_to_keep5) latest manager.latest_checkpoint() if latest: ckpt.restore(latest).expect_partial() print(fRestored from {latest})expect_partial()的作用是忽略checkpoint中不匹配的层比如只恢复模型结构而跳过优化器状态。如果你需要使用训练好的模型做推理这一步就足够了。注意checkpoint文件名里有0、400、800、1200、4400、5200这些数字它们表示训练步数step步数越大通常意味着模型见过更多数据但不代表效果一定更好需要结合验证集表现来决定用哪一个。3.3 训练超参数与调度策略模型训练过程中学习率调度决定了收敛质量。项目里常见配置是初始学习率0.001每过1000步衰减为原来的0.9。batch size可以设置为64或者128取决于显存大小。由于半监督训练需要交替迭代一般把迭代轮数epoch设置为200到300轮每一轮包含一个教师模型前向推理、伪标签生成、学生模型梯度更新三个子步骤。下面是一个训练循环的关键代码框架optimizer tf.keras.optimizers.Adam(learning_rate0.001) loss_fn tf.keras.losses.SparseCategoricalCrossentropy() tf.function def train_step(x, y, w1.0): with tf.GradientTape() as tape: logits model(x, trainingTrue) loss loss_fn(y, logits) * w grads tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(grads, model.trainable_variables)) return lossw参数是样本权重有标签样本设为1.0伪标签样本设为0.5能有效防止早期错误伪标签对模型造成过大冲击。训练过程中要定期在验证集上计算准确率和AUC并把最优step记录下来。项目提供的checkpoint-5200可以理解为一个长训练后的结果使用时建议先用它验证整个推理流程再回退到4000步左右的checkpoint做对比测试以免过拟合训练集。4. 实战加载训练好的模型检测未知木马流量4.1 新流量样本的预处理调用链要检测一段新的pcap不能直接把pcap输入模型必须复现第二章的完整预处理流程只是这次不再做任何训练验证集划分。假设新捕获的恶意样本放在/data/new_pcap你需要按顺序执行powershell -ExecutionPolicy Bypass -File 2_PcapToSession.ps1 -PcapDir /data/new_pcap -SessionDir /data/new_session python 3_ProcessSession.py -i /data/new_session -o /data/new_processed --max_packets 100 --min_payload 20 python 4_Session2png.py -i /data/new_processed -o /data/new_png python 5_Png2Mnist.py -i /data/new_png -o /data/new_mnist --train_ratio 1.0注意最后一步--train_ratio 1.0的含义是不需要划分验证集直接把全部数据都当作测试样本转换。如果你的5_Png2Mnist.py脚本不支持这个参数可以临时把所有png文件复制到一个统一目录然后手动调用。处理完成后/data/new_mnist目录下会出现一个单独的mnist测试文件。因为Mnist格式没有专门的测试集扩展名通常会被写为train-images.idx3-ubyte但实际内容已经是新流量的特征了只需要在加载时忽略标签文件即可。4.2 推理脚本与结果解读使用训练好的checkpoint做推理核心是恢复模型权重然后读取mnist文件并reshape成(28,28,1)的输入张量。下面是一个可直接运行的示例import tensorflow as tf import numpy as np import idx2numpy # 需要 pip install idx2numpy # 加载模型结构 model build_cnn() # 恢复checkpoint ckpt tf.train.Checkpoint(modelmodel) manager tf.train.CheckpointManager(ckpt, ./checkpoint, max_to_keep5) ckpt.restore(manager.latest_checkpoint()).expect_partial() # 读取Mnist格式数据 images idx2numpy.convert_from_file(/data/new_mnist/train-images.idx3-ubyte) labels idx2numpy.convert_from_file(/data/new_mnist/train-labels.idx1-ubyte) # 归一化并增加通道维度 images images.astype(np.float32) / 255.0 images np.expand_dims(images, axis-1) # 推理 pred_probs model.predict(images, batch_size128, verbose1) pred_classes np.argmax(pred_probs, axis1) # 输出每个会话的概率和判定结果 for i, (cls, prob) in enumerate(zip(pred_classes, pred_probs)): is_malware cls 1 print(fSession {i}: class{cls}, probability{prob[cls]:.4f}, {MALWARE if is_malware else BENIGN})这段代码里模型输出层有两个神经元索引0对应正常流量Benign索引1对应木马流量Malware。概率值建议多关注prob[1]如果它大于0.5就可以判定为木马如果想减少误报可以把阈值提高到0.8但这会牺牲一部分检测率。另外如果markdown环境里无法安装idx2numpy也可以用mnist库加载但要注意那个库默认加载的是官方MNIST数据集不会读取你新生成的文件所以推荐自己写一个read_idx函数来解析。推理输出的每一行对应一个会话。如果一个pcap文件里包含了大量短连接会话你可能看到几十甚至上千行输出。此时建议对全部会话的prob[1]取最大值作为这个pcap文件的最终恶意分数同时记录prob[1]0.5的会话数量方便后续人工溯源。5. 边界问题与调优从checkpoint间隔到伪标签阈值5.1 如何选择最优checkpoint检查点间隔与验证损失项目提供的checkpoint从0到5200间隔不等直接使用最新的checkpoint-5200不一定是最优选择。原因在训练后期模型可能对伪标签中的噪声过拟合验证集的损失反而会在某个中间步数达到最低。常见做法是在训练脚本里加入tf.keras.callbacks.ModelCheckpoint(monitorval_loss, save_best_onlyTrue)或者把每个checkpoint保存时的验证集AUC记录到CSV中。资源里的name_num.csv文件很可能就是记录步数与指标的关系你可以打开它看看哪一步验证损失最小。如果CSV内容只有步数没有指标可以自己跑一次验证对每个checkpoint-*加载后计算验证集的F1-score选择F1最高的那个定版。注意验证集必须来自5_Mnist划分时预留的测试部分不要使用训练时见过的伪标签数据。5.2 解决类别不平衡与伪标签噪声的实用技巧木马流量检测中正常流量样本常常远多于恶意样本直接训练会让模型偏向预测为正常。两个有效手段第一在计算loss时为恶意样本赋予更高的权重比如class_weight{0: 1.0, 1: 5.0}第二对训练集中的恶意样本做数据增强比如对会话图像做小幅度的平移、旋转但不要做水平翻转因为翻转会改变包顺序的方向性。对于伪标签噪声除了置信度阈值还可以加入熵过滤对于一批无标签样本如果它们的预测概率分布熵很低说明模型非常确定才允许进入伪标签集。公式是entropy -sum(p * log(p))阈值可以设置为0.1。下面的代码展示了如何把熵过滤与置信度过滤结合起来def entropy_filter(probs, conf_thresh0.95, entropy_thresh0.1): max_probs np.max(probs, axis1) entropy -np.sum(probs * np.log(probs 1e-8), axis1) mask (max_probs conf_thresh) (entropy entropy_thresh) return mask这种双重过滤能显著降低伪标签的错误传递。另外提醒一点在迭代训练中伪标签集每轮都会变化不要把这个变化视为不稳定。实际上这正是半监督学习的优势——模型逐步纠正自身错误。你可以在每次迭代后重新加载最新的checkpoint再次对无标记数据打伪标签形成循环。最后关于部署到实际网络检测环境可以把4_Session2png和5_Png2Mnist封装成gRPC服务或者用Kafka订阅实时流量切片但核心的模型推理部分无需改动只要保证输入是28x28的灰度图你的fresh流量就能无缝接入。如果你在离线pcap环境中使用建议保留原始pcap目录方便出错时回溯定位是哪一个会话触发了误报。本文还有配套的精品资源点击获取
返回列表