IntraSpanNet:利用探针+内网流量分析模型被动探测内网及终端安全设备

· 2026-10-29 08:00 · 27 阅读

原创 侠盗鲁平 2026-10-29 08:00 北京

面向安全产品发现的字节级流量分类模型

不主动发包,只看探针里已经存在的流量。

IntraSpanNet 从一条流的前 5 个包,判断它是哪个安全设备、哪个终端 Agent、哪款常用软件发出的。

Apache-2.0 · PyTorch · 单臂 2.86M 参数 · 四臂集成 11.44M · 18 类 + unknown

GitHub:https://github.com/lupingQAQ/IntraSpanNet

Hugging Face:https://huggingface.co/luping123/IntraSpanNet

支持纯cpu环境部署


00 打点阶段,最恶心的是「被发现」

打点最难受的时刻,往往是getshell后,刚发完内网探测,防守方的告警群里已经出现了你的源 IP。

主动扫描一定会留下痕迹。SYN 扫描、目录爆破、指纹探测、漏洞验证,每一个动作都在 NDR、WAF、EDR 的规则库里。刚进行探测,IP 就被封了,权限就被踢了,整条链路从头再来。

IntraSpanNet 试图一定程度上解决这个问题。

依赖内网流量探针被动嗅探,发现内网中已经部署的安全设备,进行定向规避和绕过


01 模型介绍

  • 输入:一条单向流的前 5 个包,1600 字节,IPv4 地址置零

  • 输出:产品(18 类或 unknown)、类型(10 类)、大类(3 类)、原型距离、置信度、Top-3

  • 关键能力:开集拒识。训练时不需要未知类样本,判不了就返回 unknown

  • 测试集:503 条流,产品准确率 0.8787,大类准确率 0.9245,门控 AUROC 0.9784

  • 部署形态:42 KB C 探针 + CLI + HTTP 服务;四臂集成 253 flows/s,权重合计约 46 MB


02 端口和协议规则,为什么不够用

按端口和协议划分,听上去够用,但这个标签集会很快把它拆掉:

  • 三个 VPN——wireguard、openvpn、stunnel——都允许自定义端口;

  • 三个 Web 面产品——squid_proxy、ntopng、guacamole_mgmt——默认就占 80 和 443;

  • 四个终端 Agent——windows_defender、clamav_freshclam、velociraptor、osquery——升级流量是同一种 HTTPS 形态。

规则型指纹能从报文头判断操作系统、从载荷判断协议、从握手判断 TLS 栈;学习型设备识别能从流统计判断设备类型。但它们都不输出一个封闭集里的产品标签,也都不提供在留出会话上标定过的「拒识」选项。


03 它到底输出什么

输入为一条单向流,取前 5 个包,每包 320 字节,共 1600 字节。每包由 80 字节 IPv4 与传输层头、240 字节载荷组成。

IPv4 源地址与目的地址在向量离开探针之前就被置零。端口、协议号、标志位、载荷内容全部保留。

每条流的输出:

字段

含义

tier

安全设备、安全软件、正常软件

type

WAF、上网行为管理、堡垒机、NDR、零信任/VPN、EDR/HIDS、杀毒、浏览器、文件传输、远程管理

product

18 个产品标签之一,或 unknown

distance

到最近类原型的余弦距离

confidence

四个分类臂的平均 softmax 概率

topk

概率最高的三个产品

一个真实记录长这样:

{
"product": "wazuh_agent",
"display": "Wazuh agent",
"tier": "安全软件",
"type": "EDR / HIDS",
"unknown": false,
"distance": 0.0104,
"confidence": 0.9991,
"class_id": 6,
"topk": [
    {"product": "wazuh_agent", "display": "Wazuh agent", "probability": 0.9991},
    {"product": "osquery", "display": "osquery", "probability": 0.0006},
    {"product": "velociraptor", "display": "Velociraptor", "probability": 0.0002}
  ]
}

判不了,就说 unknown

每个类在训练嵌入上用 KMeans 生成三个子原型,18 个类一共 54 行原型。对一条流的特征 f 和类 c 的原型集 P_c:

d(f) = 1 − max cos(f, p),  p ∈ P_c

两条门控臂的距离取平均,超过阈值 τ = 0.1041 就返回 unknown。τ 取开发集距离的 68 分位,只在 dev 半折上标定,没有在 test 上调过。

关键在于:训练过程不需要任何未知类样本。

这一点很重要——一个网络里「没装哪些产品」,事先根本枚举不出来。而 softmax 置信度是糟糕的边界估计,到类原型的距离才是可标定的替代方案。

阈值属于流量,不属于模型。 换一个站点、换一批软件版本,τ 必须重新标定。


04 为什么 5 个包就够

握手包暴露产品特征。

这 18 个产品都会在前 5 个报文里露出更新请求、证书、固定头部或版本串;第 6 个报文之后承载的是用户的载荷,属于用户,而不属于产品。

短包补零,短流补零,超出就截断。不足 5 个包的流同样补零。以太网、VLAN、裸 IPv4 三种封装都接受,解析不在热路径上——探针在流的第 5 个报文到达时就交出了向量。


05 模型:1600 字节进,四个头出

IntraSpanNet 模型架构
IntraSpanNet 模型架构
1600 bytes
  → ByteEmbed (256)
  → [bytes, CLS] + 位置编码
  → 4 × GDN Block (d_model=256, d_state=16)
  → CLS 特征 (256)
  → 产品头(18) / 类型头(10) / 大类头(3) / 恶意头(11)
  • 没有分词器,不依赖外部预训练语料。 字节直接进模型,词表就是 0–255。

  • 编码器占大头。 四个头合计约 0.4M 参数,占单臂 2.86M 的 14%,其余 86% 都在 GDN 主干里。

  • 线性代价。 Gated DeltaNet 对序列长度是线性的,单次前向 O(L·d_model·d_state),L = 1600。

  • 四臂集成。 A-S0、A-LDA、B-LDA、B-S0 四个臂结构相同,差异在预训练配方、损失权重与硬负样本采样;softmax 输出与原型距离都取平均。

  • 门控只用两臂。 A-LDA 与 B-LDA 负责拒识,另外两臂只做分类。

两个难负样本臂(A-HN、B-HN)AUROC 更高,但阈值一动,门控距离就漂移,因此按稳定性而非准确率剔除。

三个阶段训出来

阶段

数据

目标

1. 对比预训练

33,184 条仅训练流

NT-Xent / SimCLR

2. 多任务 SFT

产品、基准、恶意训练流

产品、类型、大类、恶意、域对抗

3. RL 微调

训练 split,奖励塑形

产品正确、类型正确、诚实拒识

标注集共 40,283 条流、18 个类别,验证集 1,006 条来自 14 个留出会话。训练用 4 张 RTX 4090,发布检查点为最终四臂。

第 2、3 阶段以稳定 API 发布,可以拿自己的抓包继续训练:

接口

作用

SFTConfig

监督阶段的各项损失权重

compute_sft_loss

多任务监督损失,返回每个分项与 total

RLConfig

REINFORCE 阶段的奖励权重

compute_rl_loss

带滑动均值基线的 REINFORCE 目标

Trainer

每次调用走一步优化,两个阶段通用

load_backbone

从已发布臂热启动,自动适配改过尺寸的产品头


06 结果

指标

test(503 流)

全验证集(1006 流)

产品准确率

0.87870.8817

大类准确率

0.92450.9334

Macro-F1(有支撑类)

0.7621

0.8240

门控 AUROC

0.9784

0.9820(dev)

产品准确率的 Wilson 区间为 ±0.029。test 半折的 Macro-F1 被只有一两条样本的类拉低(wireguard 只有一条测试流),全验证集的 0.8240 是更稳定的参照。

其他结果:

  • 恶意家族 Macro-F1 0.9702,USTC-TFC2016 去重测试集,n=1242;二分类 F1 不低于 0.994。恶意头只单独报告,不进入自动响应路径。

  • 未知拒识 18/18:18 个未知产品桶全部被拒识,操作点在 q=0.64 至 0.75 区间内稳定。

  • 验收 demo:含时序救援 9/10,不含时序救援 8/10,未知拒识 100%。

  • 端到端服务:已知流 6/6。

  • Few-shot 注册:给一个标签集外的新品类(smb)注册 3 个子原型后 8/8,不用重新训练。


07 工程形态:探针、服务与注册

42 KB 单文件 C 探针。 旁路收流,第 5 个报文到达即输出 1600 字节向量

CLI。 直接对一个 pcap 做分类,打印表格,--json 输出每流一条记录。

HTTP 服务。POST / 接收一个或多个 1620 字节的 FLW1 记录,返回 JSON 数组。

Few-shot 注册。 遇到标签集外的产品,注册 3 个子原型即可,不需要重新训练。smb 就是这样从 0 到了 8/8。

吞吐与显存(单张 RTX 4090,fp32):

配置

吞吐

batch 1 延迟

batch 128 峰值显存

单臂

1017 flows/s

10.7 ms

3.37 GB

四臂集成

253 flows/s

43.1 ms

3.40 GB

蒸馏学生

1011 flows/s

10.6 ms

3.37 GB

探针的采集速度高于集成 253 flows/s 的分类速度,所以部署上只有三条路:抽样、分片到多卡,或者按需分类。8 GB 卡在 batch 128 下仍有富余。


08 快速开始

git clone https://github.com/lupingQAQ/IntraSpanNet.git
cd IntraSpanNet
python -m venv .venv
source .venv/bin/activate
pip install -e .            # 默认即可在 CPU 上跑
pip install -e ".[gpu]"# 加上 flash-linear-attention 走 Triton 快路径

也可以直接 pip install intraspannet,权重仍从 Hugging Face 下载:

huggingface-cli download luping123/IntraSpanNet --local-dir weights/intraspannet

分类一个抓包:

python -m intraspannet.cli classify \
  --pcap sample.pcap \
  --weights-dir weights/intraspannet \
  --json results.json

加 --device cpu 强制走 CPU;只想快速看一眼输出,再加 --arms a_s0 --gate a_s0 用单臂。

服务模式:

python -m intraspannet.cli serve --weights-dir weights/intraspannet --port 9012

CPU 路径是纯 PyTorch 的 GDN 移植,单臂约 2 秒一条流,四臂约 10 秒一条流。



9 授权使用

只在有授权的安全评估、攻防演练与资产管理环境中运行。

  • 仓库不包含任何抓包;

  • 不要把敏感抓包上传到公共演示;

  • 恶意头单独报告,且排除在自动响应路径之外;

  • 输入不含地址,除字节模式外也不含载荷语义。


链接

代码与权重 Apache-2.0,文档 CC-BY-4.0。

引用

@software{luping2026intraspannet,
  author = {luping},
  title  = {IntraSpanNet: 不主动扫描识别内网安全设备、终端安全产品与常用软件},
  year   = {2026},
  doi    = {10.5281/zenodo.23643146},
  url    = {https://github.com/lupingQAQ/IntraSpanNet},
  note   = {模型:https://huggingface.co/luping123/IntraSpanNet}
}

跳转微信打开

本文转载自微信公众号「Security丨Art」,查看原文。版权归原作者所有,如有侵权请联系删除。