认证前攻击面榨干、只剩登录态时,答案往往在源码里——国产二开系统的源码经常就躺在 GitHub 上。靠这套流程挖到过一个通用型 0day。
什么时候该转白盒
- 黑盒测绘拿到明确产品指纹(某框架二开、某厂商国产系统)
- 认证前合规面榨干,剩下的全是 L0/L1(只证明存在,拿不到东西)
- 目标是通用型产品——挖出来就是通杀
三条都中,别在黑盒上磨了。
Phase 0:指纹提取
第一步不是搜,是提取本地证据里的”独特串”(GitHub 搜约等于零才算独特)。五级:
| 级别 | 类型 | 举例(脱敏) |
|---|---|---|
| 1 | 自研 API 路径 | /api/folder/fwh/ 这种拼音缩写路径,别家不会有 |
| 2 | 中英报错整句 | 框架的中文报错原句,注意弯引号原样保留 |
| 3 | 厂商/产品标识 | 厂商名、SaaS 域名、客户子域模式 |
| 4 | 技术栈组合 | 框架+存储+服务器+响应封装格式 |
| 5 | chunk/组件命名 | webpack chunk hash、Vue 组件路径 |
从哪提:前端 bundle 正则抠 /api/...、报错堆栈包名、页面厂商标识(webpack bundle 一条正则抠全路由)。普通词(login、list、index)只作”星座组合”成员,多条 AND 并用。
Phase A:反搜与落地
反搜:独特串扔进 GitHub code search(带 text_matches 上下文)、Gitee、Sourcegraph 交叉;命中后至少 3 条指纹命中(单串 + 自定义响应封装 + 模型字段)才算同源。
批量落地:代理下 git clone 大仓库必断(fetch-pack early EOF),codeload 下 zip 也断,走 API:
GET /repos/{owner}/{repo}/git/trees/{sha}?recursive=1列出全文件清单raw.githubusercontent.com/{owner}/{repo}/{sha}/{path}逐文件拉取
小文件走代理很稳(实测 127/127);ref 用 commit SHA。
版本锁定看部署配置:docker-compose 里的 jar 文件名给出基座版本(如 xxx-module-system-2.4.5.jar);接口行为 diff 也说明问题——仓库 POST 而部署只认 GET 则部署版更新,判定以线上为准。
Phase B:五路并行审计
源码到手后拆五路并行,每路一份独立报告:
- 鉴权矩阵:全 Controller 端点 × 鉴权注解 × anon 白名单对照
- SQLi 污点追踪:全部 Mapper XML 的
${}逐枚,Source→Sink 画链 - 文件链:上传白名单→落盘路径→webroot 可达→解析执行
- 业务逻辑:每个状态转移查三样(操作者身份/数据归属/状态前置)
- 基座与依赖:过滤链逐行读、pom 版本比对已知 CVE
拆路不为快,为的是每路有 checklist 和产出契约(证据必须 文件:行号、置信度分四级)。上一轮靠路 2 挖到框架自带接口的 SQLi。
Phase C:实例判定
白盒结论必须回线上实例判定——低频、只读、单发。JeecgBoot/Shiro 系这张响应矩阵直接判 anon 边界:
| 响应 | 含义 |
|---|---|
参数校验错误 JSON(Required String parameter...) | 穿过过滤器到 Controller = anon 放行 |
500 + AuthenticationException: token为空 | 被过滤器拦 = 不在 anon 清单 |
405 不支持GET请求方法 | 到 handler = anon 放行(GET 打 POST 端点,零副作用判定法) |
| Tomcat 404 | 无 handler,模块不存在 |
| 超时 | 别急着判 WAF,拉长超时拿真实异常(可能是后端基建故障) |
红线
- 实例验证只读、低频(秒级间隔)、单次判定,禁真实上传、禁删改、禁批量
- 挖到的凭据只记录不验证,报告里打码
- 写操作需明确授权才动
- 代码引用必须来自真实读过的文件(文件:行号),推演部分标出
小结
黑盒榨干之后,源码就是答案,而源码经常就在 GitHub 上。