ShadowScan:让 AI 参与判定的影子端点扫描器
原创
aerfa21
aerfa21
我的安全视界观
2026年11月2日 06:06
北京
去阅读
上一篇《影子端点专项扫描:AI \"用进\"安全的一次实践》讲了背景、定位和整体设计。这篇重点写 AI 怎么参与判定、三次改版,以及被真实目标打出来的工程坑。项目已开源:https://github.com/Aerfa21/shadowscan
一、为什么做这个
做资产排查时一直有个盲区:Druid 监控台、Swagger 文档页、Spring Boot Actuator、.git源码目录、中间件管理台。这些端点不在业务系统设计文档中,资产台账上也查不到,但一旦暴露,往往直接可读配置、密钥、内存转储,或者还原源码。
常规漏扫扫不到它们,原因主要在路径上:只测/admin、/login这类固定路径;不认/portal/V1这样的上下文前缀;靠 200/404 判断,而 Java 应用对任意路径都可能返回 200 或统一错误页;未带 cookie 时返回登录页,容易被判成“不存在”。这类端点需要一套专门的路径和签名,通用漏扫加大字典并不能解决。
二、先试过的两条路
最早试过两个方向:从应用日志里做路径规则,以及收到告警后自动验证。两者都受限于同一个前提 - - 先有日志或告警,才有后面的检测。从SRC漏洞数据分析来看,影子端点又多次出现在没有日志、没有告警的资产上,所以效果一直有限。
三、工具怎么设计
定位很窄:只做影子端点这一类,不做 SQLi/XSS/命令注入,也不做组件 CVE Nday扫描。
核心链路:
资产清单 → 站点发现(域名解析 + 34 个端口 + HTTP/HTTPS 存活) → 框架指纹 + 上下文前缀收集 → 规则库扫描(81 条规则 × 9 类,内容签名判定) → AI 自适应扩探(扫描期) → AI 证据验证(扫描后) → AI 研判与报告(扫描后)
图 1:规则引擎负责找得到,三层 AI 负责看得准。AI 不可用时自动降级为纯规则扫描。
规则库是“端点路径 × 命中签名”的清单,新增一条只需加一行记录。命中判定用内容签名,不用状态码 - - 这是为了规避 Java 应用统一 404 页带来的假阳性。
AI 部分分三层,但每层都守四条约束:解耦(AI 层不 import 扫描器)、降级(LLM 失败时扫描照跑)、可审计(记录模型、置信度、耗时)、脱敏(不向 LLM 发口令明文)。降级是工程上的容错,不代表 AI 可有可无;AI 不可用时扫描照跑,但降级结果只能算候选集,不能当结论。
给 AI 提议权之后,真正起作用的是方法 + 副作用的约束,路径白名单只是其中一层:只用GET/HEAD、禁止 query string、只取状态码与声明长度、不提交任何凭据、23 个危险动词黑名单。一次自适应运行里,放行 117 条、拒绝 11 条,每条都留了理由。
四、AI 部分的三个版本
4.1 V1:只喂结论
最初的做法很直接:把命中记录(url、status、框架、描述)发给 LLM,让它判真伪、定风险。
跑 mock 靶标时效果很好。第一次跑真实数据就出了问题:34 条命中,AI 判了 33 条真阳性 + 1 条假阳性。人工逐条抓真实响应复核,发现其中几条是误报:
- 某站点的/api/jsonws返回{\"msg\":\"…认证失败…\",\"code\":401},AI 判真阳性,还列为高危;
- 某站点的/druid/login.html302 跳到 Nextcloud 登录页,AI 判真阳性;
- 某站点的 Harbor:8080/api/systeminfo308 跳到 8443,和 8443 的真实发现重复,AI 没识别。
模型判断力没问题,问题出在喂进去的东西:模型看到的只有“扫描器说这是 Liferay JSONWS 未授权”,它从没见过那个 401。扫描器判错了,它自然跟着错。
4.2 V2:喂真实响应
于是加了验证层:先回抓真实响应构建证据包,再连同证据交给模型。
证据包包含 9 项:状态码、Content-Type、长度、正文片段(脱敏)、重定向链、认证失败特征、catch-all 比对、双视角对照、有界下一跳追问。同一批 34 条,改造后自动排除 3 条误报,和人工逐条复核的结论完全一致。
其中“双视角对照”是做的过程中发现的细节:扫描器为绕开 CDN 会直连解析出的源站 IP,可能报出“公网经 CDN 实际打不到”的端点。验证层同时用两种视角各取一次,不一致就降级为“仅源站可达”。
4.3 V3:给 AI 提议权,但执行权留在代码里
到 V2,AI 已经判得比较准,但角色还是事后复核。接着的问题是:规则库没想到的端点,谁来发现?
做法是让 AI 提议,但执行权留在代码里。所谓“提议”,是让模型基于当前证据输出一组“建议继续探测的路径 + 理由”;模型不持有 HTTP 客户端,也不执行请求,只产出候选列表,由代码逐条查白名单、决定放行还是拒绝。
扫描到某站点 → 发现命中 → AI 提议“再探这几个端点”(附理由) ↓ 代码查白名单:放行 / 拒绝(逐条留痕) ↓ 只执行放行的 → 结果回填 → AI 决定“还要再探吗” → 收敛
同一批 34 条,V3 自动排除 6 条误报,比 V2 多 3 条;还发现了规则库外的端点 - - 它自己提出要探 Prometheus的/api/v1/status/tsdb、/api/v1/metadata,这些手工白名单里一个都没有。
图 2:同一批 34 条命中,误报排除从 0 到 3 再到 6。V3 的关键,是让 AI 只提议、执行权留在代码里。
五、踩过的坑
5.1 AI 侧
推理模型“想太多”。报告里塞满思考过程,正文为空。原因是max\_tokens约束的是content + reasoning\_content之和;预算不足时,模型先把额度花在推理上,正文就没了。改法是给足预算(6000/8000),并且 content 为空一律判失败,绝不拿reasoning\_content冒充答案。
并发一高就被限流。并发 8 路触发网关限流,大量超时。后来做模型分工:逐条研判用轻量模型,报告用强模型;并发降到 3~4。
审计字段和实际不符。审计里写的是强模型,实际调用的是轻量模型。安全工具的审计准确性不能含糊,改成记录实际调用的模型。
5.2 工程侧
这几个都是被真实目标打出来的,没有一个和模型有关。
重试导致请求翻倍。最初“有响应但未命中”也重试,后来改成只在无响应时重试,请求量减半。
端口探测被限速拖慢。限速误约束了 TCP 探测;改成端口探测不受--rate-limit约束,限速只压 HTTP。
catch-all 站点误报。任意路径都返回首页,内容签名会被首页命中。加了四层防护:前缀堆叠去重、JSON 端点校验、self\_path校验、catch-all 守卫(随机路径探一次,与首页同正文就判否)。
302 型兜底。随机路径跳/login,Druid 登录页被误命中。改法是签名加组件独有端点,并识别 302 型兜底。
认证失败页回显路径。错误页把/jsonws回显进正文,命中 Liferay 规则。新增认证失败特征判定,正文含 401/403/认证失败/unauthorized 一律判否。
http/https 重复上报。80 端口 301 跳 443,同一发现报两次。加了跨站点 http/https 去重,42 → 34 条。
还有一个性能优化值得说:猜测的兜底前缀(/app/web/manage/admin)先用 3 个探针判断是否存在,不存在就整组跳过。每站点探测数从 372 降到 96,3.9 倍。原来 78% 的探测都花在猜前缀上。
图 3:catch-all、302 兜底、认证失败页回显,都在这里被挡掉。
六、实测结果
6.1 内网第一轮(30 个域名)
命中 16 条,去重后 10 个“站点 + 端点”;误报治理 103 → 22 → 16;逐条抓真实响应复核,未发现高危,真实暴露均为低危,主要是 Actuator 信息暴露(3 个站点)和 Nacos 命名空间元数据(1 个站点);xxl-job 控制台需登录,不算漏洞。
6.2 公网域名(725 个可达域名)
2026-10-14 15:05 → 10-15 19:59,29 小时,限速 10 req/s,全流程退出码 0。
图 4:725 个域名、1927 个站点,最后人工确认 27 条,真实率 82%。
人工复核结论:27 真、4 误报、1 重复、1 已修复。
图 5:本地 mock 靶标(16 条命中)的报告首页,仅作界面示意。
这轮跑完,比 27 条命中更值得记的是:33 条里有 6 条需要人工修正。这直接促成了后面的证据验证层。
七、开源地址与适用场景
项目已开源:https://github.com/Aerfa21/shadowscan(Apache-2.0)
仓库只保留最小核心:shadowscan.py、ai\_layer.py、验证层与探测策略、批量编排、自检工具,以及 README、运行指引、AI 层说明。
适合谁用:
- 做资产排查、影子资产治理的安全团队;
- 需要在上线前检查 Actuator、Swagger、Druid、.git等端点的研发 / DevSecOps;
- 想研究“LLM 如何参与安全判定”的同行。
不适合谁用:
- 想找 SQLi/XSS/命令注入/组件 CVE 的 - - 这个工具不做;
- 想拿它直接打非授权资产的 - - 命令必须带--authorized,
且只应扫描已获书面授权的资产。
快速开始:
git clone https://github.com/Aerfa21/shadowscan.gitcd shadowscancp env.example.sh env.sh # 填 LLM 端点与 key;不启用 AI 可跳过python3 shadowscan.py --targets assets.txt --production --authorized -o out
--production等价于--ai --adaptive。AI 不可用时会自动降级为纯规则扫描,不阻塞流程。
八、最后
这个工具最初只是想补上“端点漏扫扫不到”这个盲区。做的过程中发现,扫得到只是第一步,真正难的还有判得准;判得准的关键,是让 AI 看到真实响应,而不是只看扫描器的结论。
另一个体会是:给 AI 自由度的地方,得同时给它边界。自适应扩探能发现规则库外的端点,靠的是让 AI 提议;但真正能上生产,靠的是白名单、只读约束和审计留痕。
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。










评论