IntraSpanNet:利用探针+内网流量分析模型被动探测内网及终端安全设备
原创 侠盗鲁平 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 个产品标签之一,或 |
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 字节进,四个头出

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 | 多任务监督损失,返回每个分项与 |
RLConfig | REINFORCE 阶段的奖励权重 |
compute_rl_loss | 带滑动均值基线的 REINFORCE 目标 |
Trainer | 每次调用走一步优化,两个阶段通用 |
load_backbone | 从已发布臂热启动,自动适配改过尺寸的产品头 |
06 结果
指标 | test(503 流) | 全验证集(1006 流) |
|---|---|---|
产品准确率 | 0.8787 | 0.8817 |
大类准确率 | 0.9245 | 0.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 9012CPU 路径是纯 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」,查看原文。版权归原作者所有,如有侵权请联系删除。