跳到正文
博客园· 你好,星·· 4 小时前AI 评分38

如何自研漏洞挖掘 Agent:机器管账本、模型管判断

agent自研挖洞方向 - 你好,星

AI 导读

自研挖洞 Agent 的核心思路是让模型负责判断、Python 脚本负责执行与取证、机器负责核对收口,主循环固定为授权定界、登录落账、翻 JS、机械爬取、模型补语义、流量入账、跑通功能生命周期、转攻击面等步骤。

正文

https://www.cnblogs.com/nihao-xing/p/23302212
在上一篇文章中,我们大致探讨skill的编写和artex的源代码的分析。
下面我们来说下自研agent怎么写的大致思路。
本篇文章中大量观点引用L师傅,已经获得师傅授权。
再次感谢师傅教诲。
PixPin_2026-10-31_18-12-02

1.Agent、个人项目和纯模型区别

  • 纯模型:直接使用,本身也没有写skills,也没有别的提示词。
  • 个人项目:写了skill,生成了很多mcp工具,在cli运行,在过程中可以交互。没有最后一步接入。
  • 挖洞Agent:你写了一个项目,然后把项目利用这个python脚本接入,形成了所谓的挖洞agent。

2.如何写属于自己的挖洞Agent

核心点:
模型管脑子和判断,脚本管手和证据,机器管核对收口

agent擅长挖掘的是js逆向相关的未授权导致的各种敏感信息泄露。
别的不擅长但不代表挖不了。
(1). 开工授权
主要就是让你第一步把能给模型的都给它, 这样后面就方便测试了

===开工授权:请按顺序选择===
1.授权依据:[1]SRC平台授权;[2]书面授权;[3]自有或受控资产;[4]无授权(终止)
2.评估范围:[1]未认证面与已认证面;[2]仅已认证面
3.数据变更边界:[1]只读;[2]允许创建并清理测试对象
4.测试账号:[1]1个账号;[2]2个账号(A/B对照);[3]0个账号(无账号/免登录直进)
5.注册许可:[1]允许注册;[2]不允许注册
6.回连通道:[1]不提供(skip);[2]提供地址

Scope 不是网关的地址,先排除,不向排除的目标发送测试
如果你写的主循环那部分的代码有问题的话,就别再吭哧吭哧挖了,赶紧回去改代码。
主循环其实就是前面那六个步骤,写成一个主要的循环代码,比如main.py
也可以弄成命令行的形式,加各种各样的命令后缀,比如-target,-cookie等等
比如:

用法:
python agent/main.py --target <URL>[--max-turns 150]           开测授权目标
python agent/main.py --target <URL>--fresh                   全新复测(新目录,禁用旧证据/经验)
python agent/main.py --resume <state.json>                续跑默认追加150轮
python agent/main.py --selftest                    机制自检(不烧额度)

提醒一下,测ssrf的时候,要把回联地址给写上去,可以写在你的agent的配置文件里。

推荐的dns地址
requestrepo.com/requests

下面是流程展示,
PixPin_2026-10-31_18-23-49

===开工授权:请按顺序选择===
1.授权依据:[1]SRC平台授权:[2]书面授权;[3]自有或受控资产;[4]无授权(终止)
2.评估范围:[1]未认证面与已认证面:[2]仅已认证面
3.数据变更边界:[1]只读;[2]允许创建并清理测试对象
4.测试账号:[1]1个账号;[2]2个账号(A/B对照)[3]0个账号(无账号/免登录直进)
5.注册许可:[1]允许注册;[2]不允许注册
6.回连通道:[1]不提供(skip);[2]提供地址
回复6个编号(空格/逗号分隔或连写,如312211;q退出):122222
请输入回连地址/dnslog前缀:http://xxxxxxxx.requestrepo.com
授权与开工前置已落盘:D:\xxxxxxx\Ai-Auto-Pentest\captures\site-xxxxxx.xxxxx.exanple.com-fresh-20261022-204830
本次范围为“仅已认证面”,先完成登录再开工。
浏览器已打开登录页,请完成【账号A】登录。完成后回车;始终登不进去输入anonymous:
登录态已记录:authenticated
第二个浏览器已打开,请登录【账号B】(与A不同账号)。完成后回车;暂时没有第二个账号输入none:

这个时候我拿蚂蚁的一个站点举例子。
要扫码登陆,
agent首先打开系统的默认浏览器。然后跳去你要挖的站点,因为你刚测试账号点的是二,所以会先弹出浏览器,让你扫一次码,保存A账户凭证。然后刷新页面,让你扫第二次码,然后再保存B账户凭证。
这样搞的优点是。不用你去burp一个个把账户凭证喂给ai。
尽量单独给agent漏洞挖掘给它一个单独的浏览器,上面不要装任何的插件,因为装插件的话,可能会导致各种各样杂七杂八的流量,可能会导致agent,浪费很多的token去解析。

(2). 业务梳理
功能点齐全、空白页面、功能点少,但还是有一部分
起一个可见浏览器去采集流量
翻JS:挖路由、网关、隐藏接口、参数结构
注意点:模型会漏掉一些二层结构,所以使用机器爬虫,不靠模型点
上了一个保险:模型去爬虫,补机器漏掉的
使用机器梳理:每个可见功能点跑完整生命周期 ,不一定只有增删改查。
打造业务地图 + 模型补语义:机器负责记录"有什么",模型负责解释"这是什么

·简单说就是:机器负责记录"有什么",模型负责解释"这是什么",两者分开存、互不覆盖。
打个比方-侦察一栋楼:
·机器账本business-map.json:摄像头式的事实记录。比如"3楼有个按钮叫发布',点了之后发了PoST/api/article/pubLish,参数有articleId、title"。这是浏览器爬到的真实控件、动作、
·模型注释business-annotations.json:侦探在旁边的批注。比如“这个‘发布‘功能是把草稿文章转为公开状态(purpose),操作的对象是文章(objects),依赖先有草稿才能发布
流量,机器自动写入,模型不许改(防止模型记错或脑补污染事实)。
(dependencies) "。
为什么分开?因为机器爬到的只是“点了什么按钮、发了什么请求",它不知道这个按钮在业务上意味着什么;而模型能理解语义,但模型记忆不可靠、容易编。所以:
·事实归机器→收口对账、覆盖检查都按机器账本来,没人能“觉得自己测过了”;
·语义归模型→后面提攻击假设时用(比如知道“发布是状态流转”,才会想到测“能不能越权发布别人的草稿");
·模型写注释必须有证据,不确定就写unknown,编不出来不许硬填。
机器画出地图的骨架,模型给地图上的建筑标注用途,标注错了不影响骨架本身

核心流程:

这套Agent 梳理业务的流程是"机器机械爬+模型补语义"两条线并行,一步步是这样的(依据Skill.md、playbooks/web.md、agent/main.py):
第θ步:开工定界(agent/main.py授权向导)
.固定六项授权菜单:授权/范围/写权限、账号数量、注册许可、0OB-—确定“能测什么、能不能建对象”。
·非fresh任务先读lessons.md(历史教训);匹配到平台画像(target-profile-match.json)只当经验提示,必须先probe验证再依赖。
登录态显式落盘:登成功后 mark-Login.mjs--statee authenticated(或anonymous),后面所有穷举/收口都以Login-state.json为准。
第1步:起浏览器采流量
·daemon-Launch.mjs拉起可见浏览器(browser-daemon),全量记录请求头/响应体/Websocket,用户可全程看。·声明双账号时,A登录后立即起独立B浏览器(account-b/目录、独立Cookie),为后面A/B越权对照备料。
第2步:翻JS(冰山下的部分,开工必做)
·discover-js-index.mjs→js-index.json:挖路由、网关、隐藏接口、参数结构:再合并出 api-endpoints-merged.json。
·这两个文件没产出前,checkpoint每轮都会点名催一可见页面只是冰山一角。
第3步:机械业务探索(机器爬,不靠模型点)
主循环每10轮跑discover-functions.mjs更新expected-functions.json(功能清单)。
·探索队列情空后还有未到模块/受阻动作时,点名让模型用browser-command.mjs亲自补爬。browser-daemon按持久队列递归处理菜单/下拉/标签/弹窗/表单,同一动作最多失败两次不空转;进度落在auto-explore-coverage.json。.
第4步:业务地图+模型补语义
·爬到的真实控件、动作、流量、参数进机器账本business-map.json-这个文件模型不许改。·模型只准在business-annotations.json 填有证据的业务语义(purpose/objects/dependencies),不确定写unknown。机器管“事实",模型管“理解",分开落账。
第5步:流量入账→业务工作流跑通
·每10轮coverage-Ledger.mjs--sync-traffic:流量里的业务端点自动登记进coverage.json覆盖台账,未入账不收口。业务地图摸清后,workfLow-runner.mjs 对每个可见功能点跑完整生命周期:创建→读回对象自带的全部操作(改/复制/导出/迁移/启停)→删除→查询确认;创建优先走UI,UI不行翻JS
建完对象必须钻进详情页/二级页采深层端点(编辑/部署/签发/下载只在有对象后才出现)。构造接口,占位数据合法(对象id真实存在就算建成功)。结果进workfLow-results/,站点级看workflow-site-summary.json。
第6步:业务地图转攻击面
·侦察面一摸清,立刻用hypothesis-Ledger.mjs把攻击假设登记进hypotheses.json(source/path/capability/impact/preconditions/proofRequired)。·主循环注入的 surface-chains/relationHints/deep-gaps 是候选线索,必须转成新假设实测;然后才是逐项真测、probe-record 留证、validate-replay 重放确认。
收口时的业务对账
expected-functions与auto-explore-coverage没对账不许收口;coverage-Ledger--check+hypothesis-Ledger--check双台账核对一功能面和假设都必须有归宿,沉默即漏测。
账本开测,全程机器管账本、模型管判断,最后双台账核对收口。一句话概括:授权定界→登录落账→翻JS→机器按功能清单机械爬(产business-map)→模型填语义注释→流量全入账→workfLow-runner跑通每个功能的完整生命周期→业务地图转成假设

(3). 挖洞Agent自研四个维度:

1. 信息收集与业务梳理(感知层)
2. 挖洞主线(决策与执行层)
3. 核验成果防假象(核对层)
4. 修bug防回归(工程线)
注:这四个维度不是先后顺序,而是运行三件套+工程一条线

纯机器和纯模型区别:

机器: 像扫描器 知识库payload
模型: 像胡乱测试,想到就测,没想到就不测,甚至可能违规测试
信息收集与业务梳理:
页面/菜单/路由探索、JS 全量端点、流量、多网关拼接、对象关系。机器全量,模型理解业务。
①采集(机器,全量不漏)
浏览器遍历+JS静态+被动流量+创建产物,全落账本,每条带证据
②结构(机器,粗加工)
端点账本、页面关系图、对象关系、网关拓扑、参数形状;覆盖率机器可算
③理解(模型,活的业务脑图)一-核心层
滚动更新一份站点级小结,只回答高手脑子里的问题:
这站干嘛的/核心资产是什么/有哪几种角色、权限边界画在哪/
数据流(谁可控→到哪→影响谁)/已解锁与未解锁的面
每条结论必须挂证据锚点(O②的账本条目ID),挂不出锚点=幻觉,机器打回
④长假设(模型主攻+机器播种兜底)
模型读脑图写假设(“B不该看到A的xx");机械hypothesis-seed降级为兜底

与挖洞主线的齿轮环(咬合点全部机器派单,不靠模型自觉):

感知→挖洞:脑图更新完成→派“读脑图写/改假设”
                  新端点入账→重新分级,high插队
                  “感知够了”达标→放行大规模挖洞
挖洞→感知:创建成功→派“下钻采集新解锁面”(详情页/子接口/截图入账)
                   测试执行完→派“看结果校脑图”(猜错的改掉)
                    发现异常信号→派“异常要不要长新假设”

挖洞主线:
粗分级 → 计划/假设 → API 创建解锁/UI兜底 → 下钻详情页→ 高价值假设 → 可执行测试单 → 机器执行 →穷举兜底。

注意:写agent的时候要尽量的去质疑ai,尽量少向AI去阐述你的思路,然后AI就可能会迎合你的思路,可能你的思路不是最优解,但是AI还会去迎合你,给你提供情绪价值,你要尽量的去质疑ai,就比如举例子。AI说啊,他找到一个未授权的上传接口。
你要质疑他这东西能干啥,能上传木马文件不,能上传xss的HTML不,能绕过waf吗。

(4).核验成果防假象

这个是属于在自研Agent比较重要的,因为这一点太松会导致模型偷懒,还会出现太多个假象,也就是幻觉。
证据五等级(每个结论都带等级)
L1形式真实:证据文件存在、路径/站点目录正确、机器账本锁未破(防伪造路径)
L2内容真实:证据内容真的包含所声称的对象/状态(status/effect/对象ID;防拿失败记录冒充成功)
L3时序真实:证据产于本轮/本工作流窗口,不是旧账混充(防吃老本)
L4语义真实:归属/A-B/OOB/浏览器执行/持久化读回,证明的是危害不是现象
L5结论一致:声称与所有台账、证据跨文件交叉核对无矛盾(防睁眼说瞎话)

(5).修bug防回归
实战发现bug

→先写失败用例复现(红)
→最小修改(绿)
→全量自测(python agent/main.py--selftest)
→全新上下文子代理独立审查diff
→单独commit(message写明治哪个病)
→典型站点fresh金丝雀对照
→运行对照评分(上一轮VS这一轮,指标化证明变好)
→再推广到其他类型站点验证
  1. 代码能跑通,不能还有语法错误
  2. 全新上下文来审查,就好比挑刺一样
  3. 单独的commit,意思就是每次改动都是单独的,便于实战的时候,某一部分出问题,可以最小化修改。
  4. 典型站点 那就是用同一个站去检验
  5. 看之前出现的bug或者一些没有按照预计去跑的过程有没有整改好
  6. 一个站点跑通,再复用到各种站点,有问题再继续修问题。
A 模块//创建数据后,去进行修改,有没有进行查看,有没有去结合其余的功能点来组合利用,增删改查
B 模块的同上
C模块 同上
最后所有测试完成后,去测删除功能

为什么不直接在a模块上进行增删改查呢,原因就是,可能a模块增加的数据,在b模块调用的,你在a模块测增删改查的时候测不出啥,然后你在b模块测增删改查的时候,发现需要a模块的数据,这个时候啊,如果按照原来增强改查的流程,你是不是还要把原来删掉的数据再创建一遍,这是不是多此一举。还有就是有的时候你在a模块创建的数据,如果你没创建,b模块是看不到的。等于是你把a模块的数据删了之后,可能会引发一连串的连锁反应,导致挖不到洞。
(6).大致agent的目录结构
PixPin_2026-10-31_19-54-27

agent
node_modules
playbooks
references
runtime
scripts
AGENTS.md
lessons.md
loongyuan.bat
README.md
Skil.md

Bat文件是为了后续换一台电脑,方便一键部署。你也可以把自己的关联的API key新建个文件,到时候相关脚本直接读取就行。
(7).门禁意识
可以参考https://www.cnblogs.com/nihao-xing/p/23302212
这篇文章的门禁规范

红线
只用授权账号;限速300ms/请求串行;429/挑战页立即熔断停手;不破坏、不拖库、不驻留、不社工;写操作默认只在自建对象上;
IDOR相邻id s5;不删他人线上数据。细则:references/methodology-scope-policy.md、references/spec-waf-
avoidance.md。
记忆纪律
每完成一个阶段更新站点目录session-notes.md(假设进展、关键id、已排除项)一一上下文压缩后从笔记恢复,不靠回忆。新发现/新
对象立即进objects.json。
工具导航 (通用件)
·覆盖台账:coverage-ledger.mjs(功能面登记/流量自动入账/划记/查表—一每轮先看表;clean必须evidence+checks)
·攻击假设:hypothesis-1edger.mjs(开放式假设/组合链登记、下一步选择、证据闭环;漏洞类型不设枚举)
·证据合并:evidence-merge.mjs(只合并l旧站点的结构化证据,不复制Cookie/日志/原始流量)
·存证链:probe-record.mjs(真发留证)→validate-replay.mjs(内容级重放;--shot 用登录态浏览器给reproduced的
GET PoC截图存证并回写pocs.json)→assess-gate.mjs(判定门禁)→closure-brief.mjs(审批页)
·报告:report-docx.mjs/poc-builder.mjs(Word 版完整证据、分步复现、截图,不脱敏,供SRC提交)
·各模块专用工具见对应playbook。
·references/仅存纪律与工程规范;references-archive/是历史知识文档,仅供查阅、不是必读。
2.允许/禁止
允许
·读操作全量自动测(GET/HEAD/OPTIONS及语义为读的POST)
·限速低频探测(默认每请求间隔≥100ms,串行)
·无痕/未登录状态探测
·登录后双主体对照(只用授权范围内自有账号)
·对已确认目标、有该点证据的请求形变换(应用过滤换写,见54)
·卡住时查阅公开情报(文档、源码映射、官方仓、历史快照),结论须接地后再回站内验证
·被动OSINT(WebSearch/WaybackCDX/crt.sh/GitHub代码搜索,只读公开源,不触碰目标之外的主动扫描):H1打分后端
点/参数信息不足时必做一轮(spec-hunt.md52.2)
写操作(默认禁止,脚本默认只记录)
·删除/修改/创建类操作默认不发送,只记录到「需人工测试」清单
·仅当用户明确允许(脚本传--a1low-write-test)才执行,且脚本只对每个写端点发1次裸请求确认(不携带删除/修改数据
体),结果只记录:
○返回非拒绝状态码→判定「写操作接口未授权可调用」(高危,写入报告)
。测试完清理自己创建的资源
·测试资源豁免(登录后越权测试前提):在测试账号内创建测试对象(订单/项目/发票等,每对象1个、最小化)用于越权测试一-
标准SRC做法;不创建用于破坏,不修改/删除他人或生产数据,测完清理。
·修改类验证必须走spec-write-safety.md快照-验证-恢复-复核协议(无before快照禁止发任何修改请求):删除类操作对他人数
据永不真发,只验证到「接口受理/语义上有权限」即止。
禁止(SRC高压线,通用)
·未授权目标/范围外资产的任何测试
·危害证据齐了之后继续利用、扩面、进内网
·大规模IDOR遍历(相邻IDS5);批量枚举、拖库、批量导出;敏感数据超过验证所需条数仍继续拉
·把测试中获得的敏感数据存成样本库或二次利用
·DoS/DDoS/高并发压测;扫描器式高频全量扫、无分析的路径/Payload字典
·删除、篡改、覆盖生产环境数据与配置;引起客诉或业务事故
·植入WebShell、后门、木马或任何持久化控制
·借用、购买、盗用他人账号;钓鱼、社工、口令碰撞
·员工号/未开放注册账号:证明能登录后仍继续测其数据或权限
·测试字符串使用涉政、涉黄、侮辱性内容
·未修复前公开/外传漏洞细节;利用漏洞牟利
·触发外部QOB回调到未授权地址
·硬刚网关熔断(挑战页、封禁、限速抬升、连续拦截样)

3. 限速与并发

项 默认
请求间隔 ≥100ms
并发 脚本内串行,多脚本不并行
单站点单日请求上限 与授权方约定;无约定 ≤5000

4. 拦截分流(熔断停,过滤可换形)

用 classifyIntercept 区分,禁止把两种拦法当成一件事。

现象 判定 做法
挑战页 / 封禁 / 限速抬升 / 连续拦截样 waf-circuit
熔断
该面标记中断、结果不可信;立即停。禁止再换形。受阻面记入 anomaly-notes(type: waf-blocked,含已试姿势);报告须列出受阻未测面并告知用户
路径型WAF(分类页 / waf_block.html / WAF_CLIENT_UNCLASSIFIED) waf-block 换形进展驱动(编码、浏览器通道、等价路径,与 spec-hunt.md);每次换形后响应语义有差异即可继续,同点上限8次;连续2发无差异即停。须写 bypassReason。收口后改测其他面。禁止对惩罚页堆恶意payload
关键字 / 规则剥字符(应用过滤) app-filter 按该点证据换等价形(编码、双写、换格式),进展驱动:有进展可继续至同点8次,连续2发无差异即停。须写 bypassReason。禁止词表喷雾
需要登录才见功能 — 走登录后轨道(explore / P6);JS拿不到端点时抓运行时请求补漏
JS混淆提取不到API — 深挖封装 concat;抓运行时请求

理论部分就先这样,主要是L师傅的思路。
后面会结合artex和harness的二开结果去写一款agent。
https://www.cnblogs.com/nihao-xing/p/23302212
建议结合上一篇文章不然你写的可能会漏很多东西。

来源:博客园 · cnblogs.com