做渗透测试的人,最先被消耗掉的往往不是精力,而是耐心。一次授权范围内的渗透任务,前期信息收集可能要花掉两三个小时:跑子域名、扫端口、识别指纹、核对版本号,接着再去漏洞库一条条比对。等到真正需要经验去判断漏洞的时候,脑子已经被各种输出刷屏刷到麻木了。
所以当“AI Skill”这个概念出现在网安圈时,很多人都在问同一个问题:能不能让 AI 帮我干这些重复活,我专心做漏洞研判?这篇文章就从这个需求出发,讲清楚 AI Skill 到底能不能用来自动化挖漏洞,它的边界在哪里,以及如何从零写出一个合规、可落地、真正能减少重复劳动的安全巡检 Skill。
先给一个明确判断:AI Skill 能解决的,不是“AI 自己发现 0day 并完成利用”,而是把渗透测试中大量流程化、格式化的环节自动化,比如资产枚举、结果整理、版本比对、报告生成。它更像一个“会按流程办事的安全实习生”,而不是一个替你躺赢的漏洞之王。读完这篇文章,你会理解 AI Skill 的核心原理、适用的安全场景,并能照着完整示例跑通一个授权范围内的自动化安全巡检助手。
1. 这篇文章真正要解决的问题
先说一个很多渗透测试工程师都经历过的场景:你拿到一个企业授权范围,目标是一个主域名,想要做一轮常规巡检。第一件事是信息收集,用 subfinder 跑一遍子域名,得到几十条记录,然后过滤存活、解析 IP、扫端口,再用 httpx 识别 web 服务、标题、指纹、状态码。这些命令本身不复杂,复杂的是数据整理。
等你把这些数据从各种输出里抠出来,填进表格,时间已经过去了一个小时。接下来还要把每个服务的版本号拿去和 CVE 库比对,手工判断哪些命中,哪些存在潜在风险。最后写报告的时候,还要把这些片段重新组织成结构化的 Markdown 文档。真正考验安全能力的“漏洞研判”环节,反而被压缩到了很短的篇幅里。
这就是 AI 和网安结合最值得做的切入点:信息收集和结果整理是高重复度工作,但它们的流程非常固定,完全可以标准化;模型负责理解任务和产出结论,工具负责执行命令,两者的组合就是 AI Skill 的雏形。
从技术趋势看,AI Agent 已经能调用搜索引擎、代码解释器、浏览器等工具,但通用 Agent 并不了解渗透测试的流程和禁忌。Skill 相当于给 Agent 安装了一个“网安技能包”,让它在特定任务里具备专业流程、工具调用方式和安全约束。对个人来说,这能把很多琐碎活交给自动化;对团队来说,可以统一资产巡检的标准流程,减少因为人工疏漏导致的误报漏报。
这篇文章适合以下读者:在做合法授权渗透的 SRC 白帽子或安全工程师;想了解 AI Agent 如何跟真实工具链结合的安全新人;以及已经接触过 ChatGPT、Claude,但希望把自己的经验沉淀成可复用技能包的开发者。
2. 什么是 AI Skill:先理解“给 AI 装技能包”这件事
要理解 AI Skill,可以先从 AI Agent 说起。
2.1 AI Agent 和普通聊天的区别
普通聊天是“你问我答”:你问一个问题,模型根据训练知识给出答案。但一旦涉及真实工作,比如扫描一个域名、读取一个文件、执行一段命令,模型就不能光靠“张嘴”来完成了,它需要工具。
AI Agent 在这里的定位是一个“调度大脑”。它会接收一个目标,把目标拆解成若干步骤,然后逐步调用工具完成任务,根据工具返回的结果判断下一步动作。整个链路可以概括为:理解目标 -> 拆解任务 -> 调用工具 -> 读取结果 -> 继续决策 -> 输出结论。
举个例子,你让普通聊天模型“收集 example.com 的子域名”,它只能回答你“你应该用 subfinder”。但你让一个具备工具的 Agent 去做这件事,它会自己去执行 subfinder 命令,拿到真实结果,再清洗数据、格式化输出。
2.2 Skill 到底是一个什么东西
Skill 可以理解为 Agent 的“岗位技能包”。它的核心是一个描述文件,比如 SKILL.md,里面写清楚这个技能是做什么的、在什么场景下启用、使用步骤是什么、有哪些硬性约束。技能包还可以附带脚本、模板、数据文件等资源。
可以这样类比:一个刚入职的安全实习生,你直接丢给他一台 Kali,他可能不知道从哪开始。但你递给他一份 SOP,上面写着“第一步做什么、第二步做什么、遇到什么情况要停下来”,再给他配好工具和脚本,他就能按部就班完成一部分任务。这份 SOP 加工具集,就是 Skill。
从工程结构上看,一个 Skill 通常是这样组织的:
skills/ └── authorized-scanner/ ├── SKILL.md # 技能说明和指令 ├── scripts/ # 辅助脚本 │ └── security_toolkit.py ├── data/ │ └── local_vuln_db.json # 本地漏洞库样例 └── assets/ # 模板、报告等静态资源SKILL.md 是核心,它告诉 AI 模型在什么条件下使用这个技能、分几步执行、有哪些边界。scripts 是具体干活的部分,模型通过调用脚本来完成自己无法直接完成的命令操作。
2.3 Skill 和 Prompt 的差异
很多读者会问:这不就是一段更长、更详细的 Prompt 吗?其实不完全一样。两者对比一下会清楚很多:
| 对比维度 | 普通 Prompt | AI Skill |
|---|---|---|
| 内容重点 | 语义描述、角色设定 | 流程定义、工具调用、约束条件 |
| 是否包含代码 | 通常不包含 | 通常包含可执行脚本 |
| 可复用性 | 单次会话复用有限 | 按目录结构组织,可跨项目复用 |
| 能力边界 | 靠模型自己发挥 | 有明确工具集和终止条件 |
| 适合场景 | 闲聊、单轮问答 | 多步任务、需要外部工具执行的流程 |
简单说,Prompt 是“告诉 AI 怎么答”,Skill 是“给 AI 一套能跑起来的流程”。在网安场景里,你要的不是 AI 给你背一遍渗透测试流程,而是它能把扫描结果拿到、清洗、汇总,再给出专业判断,这必须依赖 Skill。
2.4 一个 Skill 的标准目录结构
以当前社区中常见的 Skill 组织方式为例:
- SKILL.md:元数据和指令文件,相当于这个技能包的说明书和流程图。
- scripts/:存放可执行脚本。Agent 在执行任务时,会调用这些脚本完成工具扫描、数据解析、结果格式化。
- assets/:报告模板、静态字典、指纹库等资源。
- data/:任务运行时产生的临时数据或本地知识库,例如漏洞版本对照表。
这种目录结构的好处有两个:一是每个技能包可以独立分发,团队成员可以复用;二是它能强制把指令固定下来,任何模型加载这个 Skill 时,都按照里面定义的流程走,而不是自由发挥。
3. AI + 网安:自动化边界与安全前提
在动手写代码之前,必须先想清楚一个问题:AI 在安全自动化里到底能做哪些事,不能做哪些事。如果盲目相信“AI 自动化挖漏洞”,很容易把方向跑偏,既不安全也不合规。
3.1 适合自动化的环节
根据目前的安全工具链现状,下面几类工作非常适合通过 AI Skill 来增强:
| 环节 | 典型任务 | 自动化程度 | AI 的价值 |
|---|---|---|---|
| 信息收集 | 子域名枚举、IP 解析、C 段资产发现 | 高 | 统一调度多个工具,清洗重复数据 |
| 端口服务识别 | 端口开放、服务版本、banner 抓取 | 高 | 将扫描输出转为结构化 JSON 和表格 |
| Web 指纹识别 | 应用类型、框架、中间件、标题 | 高 | 自动合并指纹与历史结果,去重 |
| 漏洞匹配 | 服务版本与 CVE 库比对 | 中 | 过滤命中项、按风险等级排序、解释影响面 |
| 报告生成 | 汇总漏洞、输出处置建议 | 高 | 按模板生成初稿,节省大量排版时间 |
在这些环节里,AI 的角色更像“工头”:调度工具、收集产物、做初步判断、生成报告。它不需要完全理解漏洞原理,只要能把数据流转起来,就已经能节省大量时间。
3.2 不适合自动化的环节
要特别清醒地认识到,AI 并不能包办一切。以下场景目前仍然依赖经验丰富的安全人员:
- 0day 挖掘:未知漏洞的发现需要抽象思维和大量领域知识,目前 AI 只能做辅助分析,不能替代专业研究人员。
- 复杂业务逻辑漏洞:例如越权、支付逻辑、验证码绕过,这类漏洞往往藏在业务流程里,没有现成指纹和模板,AI 很难自动识别。
- 漏洞利用链组合:把多个中低危漏洞组合成一条高危利用链,需要极强的上下文理解和实时研判能力,自动化工具目前还非常脆弱。
- 社工与钓鱼:涉及人的因素,不确定性极大,不应该通过自动化方式实施,也需要特别谨慎对待。
所以,更稳妥的做法是把 AI Skill 定位成“安全巡检助理”,而不是“自动攻击机器人”。它的产出是结构化数据和报告,最终的漏洞确认与处理必须由安全人员完成。
3.3 必须遵守的安全前提
在网安领域聊自动化,最重要的不是效率,而是合规。无论是渗透测试、红队演练还是漏洞挖掘,都必须满足以下前提:
- 授权先行:只允许在用户明确提供、且有书面授权或合同约定的范围内执行扫描和验证。
- 范围最小化:严格限定目标列表、端口范围和时间窗口,禁止横向扩大的操作。
- 禁止破坏性操作:不执行清库、删表、格式化、拒绝服务等可能影响业务的动作。
- 日志留存:所有命令执行、结果输出都要留痕,便于事后审计。
- 数据脱敏:不把扫描过程中取得的敏感数据直接回传第三方模型服务,优先使用本地化模型或做好脱敏处理。
这也是下面示例中反复强调“授权”和“约束”的原因。脱离授权的自动化扫描不是挖洞,而是违规行为,必须坚决避免。
4. 环境准备与项目规划
本文的示例采用“本地工具 + 本地模型接口”的组合方式,尽量降低对外部服务的依赖。实际落地时,你可以根据团队情况替换模型后端。
4.1 技术栈选择
- 操作系统:Linux 或 macOS,因为 nmap、httpx、subfinder 等安全工具在这些环境里支持最好。
- Python:3.10 及以上版本。版本请以实际项目为准,本文重点演示通用思路,在任意主流 Python 3 版本上均可运行。
- 安全工具:nmap(端口服务识别)、subfinder(子域名枚举)、httpx(Web 服务探测与指纹识别)。如果你只需要演示某一部分,至少保证 nmap 和 Python 环境可用。
- 模型服务:任意兼容 OpenAI Chat Completions 格式的本地或云端模型都可以。示例中使用
http://127.0.0.1:8000/v1作为 base_url,这是为了强调数据不出内网的安全考虑。 - Python 依赖:
requests、pyyaml。
工具安装部分,以 Debian/Ubuntu 类系统为例,示例命令如下:
# 更新软件源并安装网络工具 sudo apt update sudo apt install -y nmap python3 python3-pip # 安装 Python 依赖 pip install requests pyyaml # subfinder 可以通过官方 release 或 go install 安装 # httpx 推荐使用 ProjectDiscovery 官方发行版如果你的环境里没有 subfinder 或 httpx,也不用担心,工具脚本会做一个“探测”动作:命令存在就调用,命令不存在就跳过并以提示信息代替结果,以保证示例能跑通。
4.2 目录规划
建议按下面的结构创建项目:
ai-sec-skill/ ├── skills/ │ └── authorized-scanner/ │ ├── SKILL.md │ └── scripts/ │ └── security_toolkit.py ├── data/ │ └── local_vuln_db.json ├── config.yaml ├── agent_runner.py ├── requirements.txt └── logs/这样的目录结构,把技能包、配置、代码、日志分开,方便后续维护。如果以后想添加第二个 Skill,比如“报告生成助手”,只需要在skills/下新增目录就可以。
5. 完整示例:从零实现一个“授权安全巡检”Skill
下面进入实操部分。我会分三步写一个最小可用的 Skill:先写 SKILL.md 定义技能流程和边界,再写 Python 工具脚本,security_toolkit.py负责调用系统安全工具并格式化结果,最后写一个调度入口agent_runner.py,它负责组织整个任务流程并调用模型生成报告。
5.1 编写 SKILL.md
文件路径:skills/authorized-scanner/SKILL.md
name: authorized-scanner description: 在授权范围内对目标资产进行子域名枚举、端口服务识别、Web指纹探测和本地漏洞库版本比对,并生成结构化巡检报告。 version: 0.1.0 allowed-tools: - nmap - subfinder - httpx - python3 instructions: | 你是安全巡检助手,只接受授权范围内的目标。执行任何任务前,必须确认目标来自用户显式输入,且授权信息有效。 任务流程: 1. 资产枚举阶段 - 调用 subfinder 收集目标主域名的子域名; - 去重并输出存活子域名列表。 2. 端口与服务识别阶段 - 调用 nmap 对存活主机或目标 IP 进行端口扫描和服务版本识别; - 将结果整理为 JSON 格式。 3. Web 指纹识别阶段 - 调用 httpx 对 Web 服务进行探测,提取状态码、标题、技术栈和响应头指纹。 4. 漏洞匹配阶段 - 使用 security_toolkit.py 中的 match-cve 子命令,把识别到的软件版本与本地漏洞库比对; - 只输出匹配到的 CVE 编号、风险等级和影响面描述,不生成任何攻击载荷。 5. 报告生成阶段 - 汇总以上结果,按清晰 Markdown 格式输出巡检报告; - 报告必须包含目标、扫描时间、工具版本、资产清单、命中漏洞列表和处置建议。 硬性约束: - 禁止对未授权目标发起任何探测行为; - 禁止尝试绕过认证、提权、横向移动、写入后门等行为; - 禁止将原始日志和敏感数据上传到第三方服务; - 当任务描述出现“未授权”“绕过”“攻击生产库”等要求时,必须拒绝执行并提示需要合法授权。这段指令的核心作用,是把安全边界写进 Agent 的工作流程。模型加载 SKILL.md 以后,会把它当成系统规则来执行。
5.2 编写工具脚本
文件路径:skills/authorized-scanner/scripts/security_toolkit.py
#!/usr/bin/env python3 """ security_toolkit.py 授权安全巡检工具:封装子域名枚举、端口扫描、Web指纹获取和本地漏洞库比对。 仅用于授权范围内的安全测试。 """ import argparse import json import subprocess import sys from pathlib import Path def run_command(cmd, timeout=60): """执行外部命令并返回标准输出,超时或失败时返回空字符串。""" try: proc = subprocess.run( cmd, capture_output=True, text=True, timeout=timeout, check=False, ) return proc.stdout.strip() except Exception as exc: print(f"[WARN] command failed: {cmd}, error: {exc}", file=sys.stderr) return "" def collect_subs(domain): """使用 subfinder 枚举子域名,返回去重后的列表。""" if not domain: return [] output = run_command(["subfinder", "-silent", "-d", domain], timeout=120) if not output: return [] subs = [] for line in output.splitlines(): line = line.strip().lower() if line and line not in subs: subs.append(line) return subs def scan_ports(host): """对单台主机执行 nmap 端口和服务版本识别,返回结构化结果。""" output = run_command( ["nmap", "-sV", "-Pn", "-T4", "--host-timeout", "60s", host], timeout=120, ) ports = [] if output: for line in output.splitlines(): parts = line.split() if len(parts) >= 2 and parts[0].isdigit(): port_proto = parts[0] try: state = parts[1] except IndexError: state = "filtered" ports.append({"port": port_proto, "state": state}) return {"host": host, "ports": ports} def fetch_fingerprint(url): """通过 Python 标准库发起请求,提取 Web 服务基本指纹。""" import urllib.request try: req = urllib.request.Request(url, method="GET") with urllib.request.urlopen(req, timeout=15) as resp: headers = dict(resp.headers.items()) status = resp.status title = "" body = resp.read(2048).decode("utf-8", errors="ignore") if "<title>" in body.lower(): start = body.lower().find("<title>") + 7 end = body.lower().find("</title>", start) if end > start: title = body[start:end].strip() return { "url": url, "status": status, "title": title, "server": headers.get("Server", ""), "headers": headers, } except Exception as exc: return {"url": url, "error": str(exc)} def match_cve(software, version, vuln_db_path): """在本地漏洞库中匹配软件版本对应的 CVE 列表。""" db_path = Path(vuln_db_path) if not db_path.exists(): return [] try: with open(db_path, "r", encoding="utf-8") as f: records = json.load(f) except Exception as exc: print(f"[WARN] cannot load vuln db: {exc}", file=sys.stderr) return [] software = software.lower() matched = [] for record in records: rec_name = record.get("software", "").lower() rec_version = record.get("version", "") if rec_name == software and version and version == rec_version: matched.append(record) return matched def load_targets(file_path): """从文件中读取目标列表,每行一个域名或 IP。""" path = Path(file_path) if not path.exists(): return [] return [ line.strip() for line in path.read_text(encoding="utf-8").splitlines() if line.strip() ] if __name__ == "__main__": parser = argparse.ArgumentParser(description="authorized scanner toolkit") subparsers = parser.add_subparsers(dest="command", required=True) sub_cmd = subparsers.add_parser("collect-subs", help="collect subdomains") sub_cmd.add_argument("--domain", required=True) port_cmd = subparsers.add_parser("scan-ports", help="scan ports") port_cmd.add_argument("--host", required=True) finger_cmd = subparsers.add_parser("fingerprint", help="fetch web fingerprint") finger_cmd.add_argument("--url", required=True) cve_cmd = subparsers.add_parser("match-cve", help="match cve by version") cve_cmd.add_argument("--software", required=True) cve_cmd.add_argument("--version", required=True) cve_cmd.add_argument("--db", default="data/local_vuln_db.json") args = parser.parse_args() if args.command == "collect-subs": print(json.dumps(collect_subs(args.domain), ensure_ascii=False, indent=2)) elif args.command == "scan-ports": print(json.dumps(scan_ports(args.host), ensure_ascii=False, indent=2)) elif args.command == "fingerprint": print(json.dumps(fetch_fingerprint(args.url), ensure_ascii=False, indent=2)) elif args.command == "match-cve": print(json.dumps(match_cve(args.software, args.version, args.db), ensure_ascii=False, indent=2))这段脚本的关键设计是:把工具调用封装成简单的子命令,模型或调度程序只需要传入参数、读取 JSON,不需要理解每个安全工具的参数细节。这样降低了 AI 调用真实工具的复杂度,也让代码更好测试。
5.3 编写 Agent 调度入口
文件路径:agent_runner.py
#!/usr/bin/env python3 """ agent_runner.py 授权安全巡检任务调度入口:解析配置、调用工具、调用模型生成报告。 """ import json import time from pathlib import Path import requests import yaml from skills.authorized_scanner.scripts import security_toolkit as toolkit def load_config(path="config.yaml"): with open(path, "r", encoding="utf-8") as f: return yaml.safe_load(f) def call_llm(config, messages): """调用兼容 OpenAI Chat Completions 格式的模型服务。""" url = config["provider"]["base_url"] + "/chat/completions" payload = { "model": config["provider"]["model"], "messages": messages, "temperature": config["provider"].get("temperature", 0.2), } headers = { "Authorization": f"Bearer {config['provider']['api_key']}", "Content-Type": "application/json", } resp = requests.post(url, json=payload, headers=headers, timeout=180) resp.raise_for_status() data = resp.json() return data["choices"][0]["message"]["content"] def run_scan_flow(target, config): """执行完整的巡检信息收集流程,返回结构化原始结果。""" result = { "target": target, "scan_time": time.strftime("%Y-%m-%d %H:%M:%S"), "subdomains": [], "ports": [], "fingerprints": [], "cve_matches": [], } # 阶段1:子域名收集 if not target.startswith(("http://", "https://")): result["subdomains"] = toolkit.collect_subs(target) # 阶段2:端口扫描。演示场景仅扫描单个目标,实际接入时需严格遵守授权范围。 result["ports"].append(toolkit.scan_ports(target)) # 阶段3:Web 指纹。对常见 HTTPS 端口进行探测。 http_url = f"https://{target}" result["fingerprints"].append(toolkit.fetch_fingerprint(http_url)) # 阶段4:漏洞匹配。这里从指纹中提取 server 字段做演示匹配。 if result["fingerprints"]: fp = result["fingerprints"][0] server = fp.get("server", "") if server: name_part = server.split("/")[0].lower() version_part = server.split("/")[1].split(" ")[0] if "/" in server else "" result["cve_matches"].extend( toolkit.match_cve(name_part, version_part, config.get("vuln_db_path", "data/local_vuln_db.json")) ) return result def build_report(target, scope, raw): return { "target": target, "scope": scope, "raw_data": raw, "message": "请基于以上扫描结果,生成一份结构化的授权安全巡检报告,并对命中的 CVE 逐一给出影响说明和修复建议。" } def main(): import argparse parser = argparse.ArgumentParser(description="authorized security audit runner") parser.add_argument("--target", required=True, help="授权目标,例如 example.com") parser.add_argument("--scope", default="授权测试环境", help="授权范围说明") parser.add_argument("--config", default="config.yaml", help="配置文件路径") args = parser.parse_args() config = load_config(args.config) log_dir = Path(config.get("log_dir", "logs")) log_dir.mkdir(exist_ok=True) print(f"[*] 开始对 {args.target} 执行授权巡检,授权范围:{args.scope}") raw = run_scan_flow(args.target, config) # 保存原始扫描结果到本地日志 log_path = log_dir / f"scan_{int(time.time())}.json" log_path.write_text(json.dumps(raw, ensure_ascii=False, indent=2), encoding="utf-8") print(f"[*] 原始扫描结果已保存到 {log_path}") # 调用模型生成报告 messages = [ { "role": "system", "content": ( "你是一名安全巡检助手。你只能处理授权范围内的安全检查任务。" "你的输出必须专业、克制,不包含任何攻击性payload,不包含任何未授权操作建议。" ), }, {"role": "user", "content": json.dumps(build_report(args.target, args.scope, raw), ensure_ascii=False)}, ] print("[*] 调用模型生成巡检报告...") report = call_llm(config, messages) print("\n" + "=" * 60) print(report) print("=" * 60) # 保存报告 report_path = log_dir / f"report_{int(time.time())}.md" report_path.write_text(report, encoding="utf-8") print(f"[*] 报告已保存到 {report_path}") if __name__ == "__main__": main()同时准备配置文件config.yaml:
provider: base_url: http://127.0.0.1:8000/v1 api_key: sk-local-test model: local-llm temperature: 0.2 tool: nmap_path: /usr/bin/nmap subfinder_path: /usr/bin/subfinder httpx_path: /usr/bin/httpx security: allow_scan: true max_hosts: 10 log_dir: ./logs vuln_db_path: data/local_vuln_db.json再准备一个最小漏洞库示例data/local_vuln_db.json:
[ { "software": "nginx", "version": "1.18.0", "cve": "CVE-2021-23017", "risk": "high", "description": "nginx 1.18.0 存在 DNS 解析相关安全风险,请结合厂商公告评估是否受影响。演示数据,请勿直接作为生产判断依据。" } ]5.4 关键逻辑说明
这段示例代码有三个关键点:
第一,工具调用要能被失败容忍。实际环境里工具可能没装、目标可能过滤请求、命令可能超时。所以run_command使用check=False并捕获异常,任何工具失败都不会中断整个巡检流程。
第二,模型只负责解读,不负责执行命令。在agent_runner.py中,模型拿到的是已经结构化好的 JSON 数据,它的任务是写报告、给建议,而不是自己拼命令。这样即使模型幻想了某些信息,真实扫描结果仍然保存在本地日志里,可以通过审计追溯。
第三,安全边界通过代码约束。SKILL.md 用自然语言约束模型行为,配置和脚本则从工程上限制执行范围。两层组合在一起,才是相对可靠的安全设计。
6. 运行验证与效果评估
先跑工具脚本单元测试,确认环境没问题,再跑完整流程。
6.1 验证工具脚本
cd ai-sec-skill python3 -m skills.authorized_scanner.scripts.security_toolkit collect-subs --domain example.com如果 subfinder 不存在,脚本会返回空列表或警告,不会报错崩溃。测试端口扫描:
python3 -m skills.authorized_scanner.scripts.security_toolkit scan-ports --host 127.0.0.1在本地回环地址上扫描,属于安全行为,可以验证 nmap 调用和输出解析逻辑。
6.2 运行完整巡检流程
假设你有一个授权测试环境域名staging.example.com,并且本地模型接口已经启动在127.0.0.1:8000,可以这样运行:
python3 agent_runner.py --target staging.example.com --scope "内部授权测试环境,IP段 192.0.2.0/24"预期会在控制台看到类似这样的流程提示:
[*] 开始对 staging.example.com 执行授权巡检,授权范围:内部授权测试环境... [*] 原始扫描结果已保存到 logs/scan_1710000000.json [*] 调用模型生成巡检报告...模型返回的内容是一份 Markdown 巡检报告,包含资产清单、端口信息、命中 CVE 列表和处置建议。同时logs目录下会生成两个文件:
scan_*.json:原始扫描数据,可用于审计和二次分析。report_*.md:模型生成的报告初稿,后续由安全工程师复核后使用。
6.3 如何判断成功
一个可用的巡检 Skill,至少要满足三个标准:
- 流程完整:子域名收集、端口扫描、指纹探测、漏洞匹配四个阶段都执行了,没有中途失败退出。
- 结果可追溯:每次运行的原始 JSON 都保存在日志目录,能定位到执行时间和目标。
- 报告可读:模型输出的报告不是空话套话,而是基于真实扫描数据的结构化内容。
如果运行失败,先看控制台输出的[WARN]和异常堆栈,大多数问题集中在工具命令不存在、网络请求超时、模型接口地址错误这三类原因上。
7. 常见问题与排查思路
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 子域名收集结果为空 | subfinder 未安装、目标网络屏蔽 DNS 枚举 | 手动执行subfinder -silent -d example.com看是否有输出 | 安装或升级 subfinder,或者启用被动 DNS 数据源 |
| nmap 扫描超时 | 目标主机关机、防火墙过滤 | 先执行ping和nmap -Pn -p 443 目标快速验证 | 调整超时参数,或改用更轻量的 TCP 连接探测 |
| 模型接口返回 401 | API Key 配置错误 | 检查config.yaml中 provider 配置 | 换成正确的 Key 或本地模型服务地址,本地地址可用任意值 |
| 模型返回内容与扫描结果无关 | temperature 过高、上下文过大 | 检查调用模型时的 messages,确认扫描 JSON 已传入 | 降低 temperature 到 0.1 左右,精简输入数据 |
| Python 依赖冲突 | 全局环境安装了多个版本 | 查看当前环境的pip list | 新建虚拟环境,通过requirements.txt固定依赖 |
| 版本比对没有命中任何 CVE | 本地漏洞库数据过少或版本匹配逻辑简单 | 打开local_vuln_db.json核对记录 | 接入更完整的漏洞数据源,或升级为语义化版本比较 |
一个容易被忽略的点是,很多 AI Agent 在长流程里会把系统指令“忘掉”。如果你发现模型试图执行未授权的探测动作,建议在 SKILL.md 的硬性约束里把“拒绝执行”写得更明确,同时在agent_runner.py里对输入目标做一层前缀校验,从根本上缩小可执行范围。
8. AI + 网安落地的最佳实践
写一个能跑通的最小 Skill 只是开始,真正要在团队或项目里落地,还需要考虑工程、安全和协作问题。
8.1 授权与范围管理
自动化工具比人工操作更容易造成“扫描范围失控”。你只想扫一个 IP,命令写错了可能扫成整个 C 段。所以建议:
- 用配置文件统一记录授权范围,并在脚本启动时打印出来。
- 在工具脚本里增加目标白名单前缀校验,目标不在白名单则直接拒绝执行。
- 每次运行结束,把授权信息和扫描日志打包归档,方便未来审计。
8.2 最小权限和沙箱
运行安全工具的系统账号应当最小化权限,不能使用 root 运行调度脚本。更推荐在容器或虚拟机里运行,防止工具参数异常时影响宿主机。
# 示例:创建受限用户运行巡检任务 sudo useradd -r -m audit-runner sudo -u audit-runner python3 agent_runner.py --target staging.example.com如果你用的是 Docker,建议加上--network host时谨慎评估,因为网络攻击面会扩大到宿主机。更稳妥的是限制容器网络和资源配额。
8.3 日志审计和结果复核
AI 生成的报告只能当“初稿”来看。安全工程师必须复核每一个命中项,尤其是高危漏洞。建立一个简单的复核流程:
- 查看原始扫描 JSON 中和 CVE 匹配相关的字段。
- 人工确认软件版本是否真实存在于目标环境。
- 在测试环境验证修复方案,再反馈给业务方。
不要在未确认的情况下,直接把 AI 报告转发给生产业务团队,这是最容易出问题的环节。
8.4 工具链选型建议
- 优先选择可输出 JSON 格式的工具,例如 subfinder、httpx、nuclei、nmap 的
-oX或-oJ参数。JSON 数据比纯文本更好被 Agent 解析。 - 漏洞库推荐可离线更新的方案,让版本比对在本地完成,避免把目标资产信息发送到外部服务。
- 如果团队内网有 GPU 服务器,可以部署本地模型,数据安全等级更高。
8.5 团队协作
Skill 的价值在于复用。建议把目录结构纳入 Git 管理,每次修改 SKILL.md 或工具脚本都要走 MR 评审。新人加入时,直接 clone 仓库,按 README 配置好环境,就拥有了和团队一致的安全巡检流程。这样既沉淀了经验,也减少了把个人习惯带进团队任务的偏差。
9. 总结与后续学习方向
这篇文章从“渗透测试重复劳动多”这个真实痛点出发,解释了 AI Skill 的基本原理,并完整演示了一个授权安全巡检 Skill 的写法。它做的事情是明确的:统一调度 subfinder、nmap 等安全工具,把扫描结果变成结构化 JSON,再让模型基于真实数据生成报告初稿。让 AI 直接读 nmap 输出然后自由发挥,和让 AI 读取结构化扫描结果再写报告,后者的稳定性和可审计性明显更好。
如果你希望沿着这个方向继续深入,建议按下面的路径来:
- 先把渗透测试的基础知识补齐,了解端口扫描、服务识别、常见 Web 漏洞的基本原理,否则你很难判断 AI 给出的建议是否正确。
- 然后掌握 Python 和命令行工具,重点练习用 subprocess 调用外部工具、用 JSON 处理中间结果。
- 接着尝试给 Claude、ChatGPT 或本地模型写自己的 Skill,从报告生成这类低风险任务开始,逐步加入资产发现和版本比对。
- 最后一定要在授权的靶场环境或 SRC 测试范围里验证,不要因为工具自动化了,就放松对授权底线的审查。
推荐一个务实的起步方式:不要一开始就追求“全自动挖洞”,先做一个让 AI 帮你整理信息收集结果的 Skill。等它稳定可靠了,再慢慢加入更多环节。每一个自动化步骤都必须保留人工复核的口子,安全这个领域,你可以用 AI 提效,但最终的责任人永远是你自己。