网络安全大模型训练数据获取全攻略:从CVE到CTF的语料构建与清洗实践
发布时间:2026/9/6 2:31:07 锦皓数字建站

做网络安全大模型训练最容易踩的坑不是模型结构选不对也不是显卡不够用而是数据。我前面十几篇把训练框架、算力调度、微调流程都聊过一遍了卡在一个问题上卡了很久模型在通用问答上表现正常一丢给它一段Docker配置或者一个Java反序列化异常就开始一本正经地胡说八道。后来把问题定位到数据层才发现网安大模型和通用大模型的差距主要不在算法而在训练语料的长尾覆盖和对抗性。这篇就把我在数据获取这件事上踩过的坑和验证过的路径完整写出来给后面做网络安全垂直模型的人一个可复用的参考。先明确一下这篇的定位讲的是训练数据从哪来、怎么拿、怎么洗、怎么变成能进loss计算的数据集。不涉及模型结构调优也不展开训练过程重点是把数据这根链条上的每一步都讲透。适合正在搭网安大模型训练pipeline、打算从零构建领域语料库、或者被数据清洗折磨到头秃的团队参考。1. 垂直模型和通用模型的差距问题八成出在数据上1.1 通用语料里到底缺什么很多人会问直接用通用大模型蒸馏或者拿开源大模型做全量微调不行吗我的回答是行但效果天花板取决于你喂给它的领域语料。通用预训练语料里中英文维基、网页、书籍、代码仓库占了大头网络安全内容少得可怜而且分布极不均匀。以漏洞情报为例通用语料里最不缺的是什么是SQL注入这类基础解释但最缺的是具体细节某个CVE的触发条件、受影响版本范围、补丁diff前后的代码差异、绕过手法、缺陷在具体框架里的上下文。这些信息分散在GitHub issue、安全博客、漏洞报告、CTF writeup里通用爬虫要么抓不到要么抓到了权重极低。模型没有见过这些文本自然无法生成有依据的回答。另一个问题是时效性。预训练语料往往滞后而网安领域几乎每天都有新漏洞、新攻击手法、新工具链。一个模型如果只知道2019年的OAuth攻击手法面对2024年的某些绕过链就是睁眼瞎。领域数据获取本质上是在给模型补充最近一两年发生了什么、怎么发生的、怎么防护的高密度知识。1.2 网络安全语料的三个特殊性网安语料和普通领域语料相比有三个显著特点这三个特点决定了你不能简单地用通用数据清洗流程套用。第一是高对抗性。网安数据天然包含大量的攻击Payload、恶意样本、漏洞利用代码。这些内容是模型必须具备的知识但同时也是风险源。清洗时必须保证不问输出风险或帮助攻击的边界常见做法是过滤敏感负载、保留分析思路而非完整利用代码、增加安全对齐层。第二是强时效性。CVE编号、补丁状态、受影响的软件版本、利用状态这些字段会随时间变化。同一个漏洞昨天是未公开利用今天可能就已出现利用。数据管线必须支持增量更新和档案字段的覆盖而不是一次性构建就完事。第三是碎片化严重。一个完整的安全事件信息往往散落在多个来源漏洞库只有描述厂商公告里有补丁信息某安全博客里有分析GitHub上有人发布了PoC推特上有讨论。把这些碎片串成一条有因果关系的样本是数据清洗阶段最耗时也最有价值的工作。2. 六大网安语料来源盘点各自的价值定位与取舍在我实际建库的过程中来源选择直接决定了下游模型的效果形态。下面按我自己的使用频次和价值评估把来源盘一遍。2.1 漏洞库与编号数据让模型学会按编号说话CVE/NVD、CNVD、CNNVD这类平台的数据是网安大模型最基础的骨架语料。它们格式相对统一包含漏洞编号、描述、CVSS评分、影响组件、参考链接等字段。这类数据的价值不是文笔而是指代精准。模型需要学会看到CVE-2024-1234这样的编号时能准确说出漏洞类型、影响范围、修复版本而不是编造一个不存在的漏洞。编号类数据非常适合用来训练信息抽取和问答对。我建议把CVE描述转成两种格式一种是描述修复建议的指令对另一种是漏洞编号字段填充的信息抽取样本。前者用于SFT阶段后者用于预训练阶段的格式感知。2.2 SRC平台与漏洞报告最接近真实攻防的问答对各大SRC平台如补天、漏洞盒子、众测平台和企业安全应急响应中心公开的漏洞报告是网安语料里质量最高的一类。原因很简单这些报告是真实攻击者在真实系统上、得到授权后测试产出的攻防逻辑完整漏洞成因、利用路径、危害证明、修复方案四项齐全。这正好是模型最需要学习的结构化推理链。不过这里的坑在于授权和数据边界。我获取这类数据只使用平台公开发布的合规内容、官方博客、年度公告中的脱敏案例绝不对平台内网或非公开报告做抓取。获取后还需要二次脱敏删除域名、用户名、IP、截图中的关键信息只留下技术逻辑。这一层不做干净后面模型很容易把敏感信息背出来。2.3 CTF赛题与Wargame训练推理链的最佳素材CTF赛题writeup、攻防世界和各大比赛的题目描述对模型推理能力的提升帮助很大。因为CTF天然是给目标、给限制、求路径的题目结构一个高质量的writeup会包含从分析入口到逐步利用的完整推理过程非常适合训练模型的链式思维。我通常会从GitHub上搜索公开writeup仓库按赛事分类去重后导入语料库。这里有一个小经验不要只收集成功解题的writeup也要收集卡住后如何排查的记录。这类过程性文本对模型训练出在卡点处尝试新路径的能力比标准答案更有效。2.4 安全文档与知识库结构化程度参差不齐OWASP Top 10、MITRE ATTCK、CWE、CAPEC、各家安全厂商的检测规则文档属于结构化程度很高的数据源。尤其是MITRE的ATTCK和CAPEC官方直接提供STIX/JSON格式的下载文件字段规整适合做预训练阶段的格式化语料。但市面上大量的安全博客、厂商白皮书却是非结构化的一眼望去全是排版混乱的HTML和PDF。这类数据必须经过一轮高质量的知识抽取才能变成可用的文本。我在这一块用的是OneKE这类中文知识抽取框架做实体和关系抽取效果比自己硬写正则好得多。2.5 流量与日志数据需要合成增强真实流量包和日志数据是很多团队忽略的一块。网安模型如果只学漏洞知识不接触真实的请求日志、告警日志、DNS解析记录对检测类任务的泛化能力会很弱。公开的网络安全学术数据集比如CICIDS、UNSW-NB15、NSL-KDD等可以拿到一部分。但它们有两个问题一是字段模式和真实生产环境差别大二是样本分布与当前攻击手法脱节。我的做法是把公开数据集当成种子再用脚本做日志合成模拟登录爆破、端口扫描、Webshell调用等行为生成带有攻击阶段标注的合成日志。合成数据不能完全替代真实数据但能有效扩充长尾场景。2.6 红蓝对抗报告与复盘高质量长文本年度红蓝对抗报告、重大安全事件的复盘分析、威胁情报机构的年度总结属于网安语料中少见的长文本、高密度内容。一段几千字的分析报告往往能把攻击链从初始突破口讲到横向移动、权限维持、痕迹清理因果链条极其完整。这类报告适合用来冷启动模型的领域长文本能力。我通常会把PDF转成结构化文本后再以段落-摘要或事件-攻击链的形式做成QA样本。但要注意PDF解析存在排版错乱问题表格会被拆散、多栏文本会串行解析后需要人工抽检。数据源获取方式形态特点主要用途风险等级漏洞库官方API/页面字段规整、时效强信息抽取、QA对低SRC报告公开内容、脱敏后使用推理链完整攻防推理训练中CTF writeupGitHub公开仓库步骤清晰链式思维训练低安全文档官网下载/知识抽取结构参差预训练、知识抽取低流量日志公开数据集合成样本丰富检测类任务中红蓝对抗报告报告解析长文本高密度领域长文本能力低3. 公开漏洞库数据的获取实操从索引到落库3.1 通过NVD官方API批量拉取CVE数据我目前的主力数据管线里面NVD API是每天固定增量拉取的开源路径。NVD的REST API可以从2023年后的2.0版本开始使用返回JSON结构字段非常规范。下面的代码是我在数据采集服务里跑的一段按关键词和时间范围增量更新import requests import json import time from datetime import datetime, timedelta API_KEY 你的NVD_API_KEY LAST_RUN_FILE ./last_run.txt def load_last_run(): try: with open(LAST_RUN_FILE, r) as f: return f.read().strip() except FileNotFoundError: return (datetime.now() - timedelta(days7)).strftime(%Y-%m-%d) def fetch_cves(keyword: str, pub_start_date: str, results_per_page: int 50): url https://services.nvd.nist.gov/rest/json/cves/2.0 params { keywordSearch: keyword, pubStartDate: pub_start_date T00:00:00.000, resultsPerPage: results_per_page, } headers {apiKey: API_KEY} if API_KEY else {} resp requests.get(url, paramsparams, headersheaders, timeout60) resp.raise_for_status() return resp.json() def process_cve_item(item): cve item[cve] cve_id cve[id] description for desc in cve.get(descriptions, []): if desc[lang] en: description desc[value] break metrics cve.get(metrics, {}) cvss_v31 metrics.get(cvssMetricV31, [{}])[0].get(cvssData, {}) base_score cvss_v31.get(baseScore) weaknesses [] for w in cve.get(weaknesses, []): for desc in w.get(description, []): weaknesses.append(desc[value]) return { cve_id: cve_id, description: description, base_score: base_score, weaknesses: weaknesses, raw: cve } def main(): last_run load_last_run() today datetime.now().strftime(%Y-%m-%d) all_items [] start_index 0 while True: data fetch_cves(, last_run, start_indexstart_index) vulnerabilities data.get(vulnerabilities, []) if not vulnerabilities: break for item in vulnerabilities: all_items.append(process_cve_item(item)) total data.get(totalResults, 0) start_index len(vulnerabilities) if start_index total: break time.sleep(1.2) # NVD免费key限速不要删 with open(./nvd_cve.jsonl, a, encodingutf-8) as f: for item in all_items: f.write(json.dumps(item, ensure_asciiFalse) \n) with open(LAST_RUN_FILE, w) as f: f.write(today) print(fdone: {len(all_items)} cves) if __name__ __main__: main()几点提醒免费API Key的限速是5次/30秒所以我在循环里加了time.sleep没有API Key也不是完全不能调但会被429限流搞得很痛苦而且字段里部分参数拿不完整。如果你打算把这个数据源当成日更服务建议直接申请正式key并把增量状态持久化到数据库而不是文本文件里。3.2 数据落库后的格式转换从NVD拿到的原始JSON不能直接丢给训练框架用。它字段嵌套太深有很多对模型无价值的元数据。我的落库流程是先存一份原始JSONL作为档案层再由解析脚本产出一份问答层。问答层的一种构造思路是把CVE描述作为上下文把该漏洞属于什么类型、影响哪些组件、CVSS评分多少、如何修复作为问题把从结构化字段拼出来的答案作为回答。这样一份CVE数据可以产生4到5条训练样本既保留了事实准确性又让模型学会了从描述中提取关键信息的格式感。def build_qa_from_cve(record): cve_id record[cve_id] desc record[description] weaknesses ,.join(record[weaknesses]) if record[weaknesses] else 未知 score record[base_score] if record[base_score] is not None else 未知 return { instruction: f请分析漏洞{cve_id}它属于哪些弱点类型严重程度评分是多少根据描述判断主要影响。, input: desc, output: f该漏洞对应的弱点类型为{weaknesses}CVSS评分为{score}。 }这里有个细节容易被忽略CVE描述是英文的而网安模型需要同时处理中英文输入。我的做法是保留英文原始描述作为输入输出用中文结构化摘要这样一个样本就实现了英文技术文本 - 中文推理结论的能力迁移。3.3 从GitHub官方安全公告拉取Advisory数据GitHub Advisory Database也是非常好的漏洞语料源它和NVD的侧重点不同更偏开源生态的实际影响。GitHub提供了官方REST API可以直接拉取advisory列表再逐条获取详情。curl -H Accept: application/vnd.githubjson \ https://api.github.com/advisories?updated2024-01-01拉下来后重点关注affected版本范围和references字段。这类数据的优势是补丁提交、影响版本写得非常具体非常适合训练模型做版本影响判断的问答。4. 语料加工从原始素材到训练集必须经过的四道工序很多人以为数据获取就是下载清洗两步实际上在网安领域原始数据到训练集的差距非常大。我把自己的流水线拆成了四道工序每一道都有对应的检验标准。4.1 相似去重MinHash 向量双重确认网安语料的重复问题非常严重。同一个漏洞的分析会同时出现在厂商公告、技术博客、某微信公众号、某论坛转载里内容相似度可能达到80%以上。如果不去重模型会在这些重复知识上过拟合反而降低了面对新表述时的泛化能力。我采用两轮去重第一轮用MinHash LSH做粗筛处理大规模文本集合很快适合把完全重复或近似重复的段落找出来。第二轮对疑似重复的候选对用embedding计算语义相似度超过0.92的再人工确认一次。用一个小技巧不是简单删除重复文本而是保留质量最高的一版。判断标准是结构完整度有头有尾、上下文明确有漏洞编号或攻击链描述、来源可信优先保留官方和一手分析。4.2 有害内容过滤与敏感信息脱敏网安数据清洗里最重要的一块就是敏感信息处理。原始SRC报告和红蓝对抗报告里经常带着真实的IP地址、域名、账号密码样例、证书信息、业务截图。这些内容如果直接进入训练集轻则让模型记住不该记的资产信息重则造成真实泄密。我的脱敏规则分三类网络标识类IPv4/IPv6地址替换为保留网段地址域名替换为example.com邮箱替换为脱敏格式。身份信息类人名、工号、手机号、身份证号用正则识别后替换。业务信息类真实的数据库名、表名、API路径统一替换为通用占位符。只做这一层还不够。我还会用分类模型对训练样本做一次敏感度打分分数高的样本进入人工审核队列。别觉得这一步麻烦如果训练完的模型在某些输入下能联想到真实的SRC资产信息那出问题就不是损失一点精度的问题了。4.3 指令与问答对构造给数据装题型网安模型最终是要回答问题的。所以原始语料无论多好都需要转换成指令问答对。我常用的构造方式有四种。一是漏洞描述转问答。把CVE描述和结构化字段拼成分析评价型问答适合事实类问题。二是CTF writeup转推理问答。把一个writeup的解题链拆成题目描述-思路-步骤-答案的结构训练模型的推理能力。这里我会故意把最终答案留到output末尾让模型在生成时被迫先走完整条推理链。三是威胁报告转摘要问答。给定一篇报告的几个段落让模型输出攻击链摘要、受影响系统、失陷指标这本质上是把长文本压缩成安全情报。四是日志转检测问答。给一段HTTP日志或系统日志让模型判断是否存在可疑行为并说明依据。这种样本对检测场景非常有效。构造完成后我会统计题型比例。我的经验是事实问答题占40%选择题/判断题占20%推理题占30%开放写作题占10%。比例失衡会导致模型在回答风格上偏向某一种题型这块需要反复调整。4.4 数据质量评估与配比别让垃圾数据拖垮训练数据量不是越大越好。我见过不少团队把几千万条语料一股脑丢进去结果模型在领域问答上还是答非所问。问题往往出在两个地方一是数据质量分布不均二是训练阶段配比不合理。我的评估手段有三个规则校验。对含CVE编号的样本用正则从output中抽取编号与真实编号比对校验不一致的直接废弃。困惑度PPL筛查。用现有通用模型跑一遍训练样本PPL过高的样本多半是语料噪声大或与领域无关会单独抽出来检查。人工抽检。每批次至少抽200条请有渗透测试经验的人打分低于2分5分制的批次回炉重洗。配比方面如果做预训练网安语料占总体训练语料的5%到10%就够了比例过大会破坏模型通用能力如果做领域微调几千条高质量指令样本就足以看到明显变化关键是多样性不是绝对数量。5. 数据合规与安全必须守住的边界5.1 来源许可证与使用条款检查很多公开数据源并不是完全开放的。NVD数据使用有开放许可要求但仍需注意引用说明。GitHub仓库要看license。MITRE ATTCK有USE条款。我在这块踩过坑最初从某知识库导出了一批内容结构很好但license明确写着禁止用于模型训练只能全部删除。我的做法是建一个数据来源清单每一条记录包括来源、获取时间、license类型、是否允许商用、是否需要署名。在数据进入训练流程前先过这个清单。不要图一时方便用有争议的来源否则后续上生产会非常被动。5.2 模型记忆隐私风险即使文本脱敏了模型还有可能通过少量样本推断出原始信息。比如某个漏洞报告中出现了某个特有目录名脱敏只替换了IP但目录名保留了模型依然可能记住这个指纹。所以除了文本层脱敏我还会在数据组织时做跨样本混淆同一个业务系统在不同样本中随机使用不同占位符避免模型从多个样本中交叉推断出同一实体的完整画像。5.3 数据投毒风险现在的公开数据源里已经开始出现恶意投毒的情况有人在GitHub仓库里放看似正常的安全分析实际把错误结论或后门样本混进去。大模型拿到这些数据训练后可能会产生被诱导的行为。比如某个漏洞分析样本故意把某个后门函数描述成正常代码模型学到的就是在某些上下文中合理地引入后门。应对策略有三个优先使用可信来源、对下载文件做哈希校验、对高风险代码类样本做静态扫描。一条数据如果让你感觉到这个结论明显不对劲但说服力很强大概率有问题。6. 从数据到验证先跑通小样本闭环再上规模最后分享一个我个人的实操经验不要一上来就追求千万级语料。我先用大约2000条高质量CVE问答对和500条CTF推理样本微调一个小尺寸模型再去跑一轮真实安全问答验证。这个小闭环走通之后再扩大数据规模和训练量。这么做的原因很简单数据管线里的bug在千条级别就能明显暴露。比如指令格式错位、标签噪声过大、某些题目答案本身有误这些在小样本上可以通过人工抽检快速发现。等到几百万条数据灌进去再发现问题排查成本已经是灾难级别。我目前会用Ollama或一些轻量推理框架加载微调后的模型做快速验证把数据质量和模型效果绑定评估。每新增一批数据就做一次A/B对比同一批问题看新增数据前后的回答是否有实质提升。没有提升的数据批次直接回炉重洗不要留着占空间。数据获取这件事没有一劳永逸的终点。网安领域变化太快今天建好的语料库三个月后就可能缺了一大块。我现在固定每周跑一次增量采集每天清理一次噪声每次上线新数据批次前都跑完整质量评估。真正稳定的网安大模型背后一定有一条持续运转、不断纠错的数据流水线而不是某一批一次性数据。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。