news 2026/10/7 8:11:57

SRC漏洞挖掘实战:从资产收集到漏洞验证与提交完整流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SRC漏洞挖掘实战:从资产收集到漏洞验证与提交完整流程

声明:本文所有技术手段仅适用于 SRC 平台明确授权范围内的目标,以及你拥有书面授权的资产。

未经授权的扫描、探测、数据读取均可能触犯《刑法》第 285、286 条与《网络安全法》。请对数据保持最小化原则:只验证、不落地、不传播。

引言:为什么你挖了半年还是"无漏洞"

很多刚接触 SRC 的同学都经历过同一个循环:打开某厂商 SRC 公告页,看到别人一个高危拿了几千块,于是打开 Burp 对着主站一通乱扫,结果要么被 WAF 拦成 403,要么提交上去被标记为"重复"或"忽略"。

问题的根因不在于工具不够强,而在于信息差没有建立起来。主站是所有人都盯着的地方,它经过了最多的安全测试,防护最厚、重复率最高。而真正出洞的地方,往往藏在:一个三年前上线的测试域名、一个被遗忘的 Swagger 接口、一个前端 JS 里硬编码的 AppSecret、一个只做了前端校验的越权接口。

SRC 挖掘的本质,是在授权范围内,用资产广度 × 参数深度 × 逻辑理解换取漏洞发现概率。本文按真实工作流拆解:资产收集 → 攻击面梳理 → 漏洞验证 → 报告提交,每一步给出可复用的代码与踩坑经验。

先说一个残酷但真实的观察:在多数 SRC 平台的漏洞统计里,核心域名的有效漏洞占比不到 20%,而子域、测试环境、边缘业务贡献了 70% 以上的有效漏洞。这不是因为核心站没有漏洞,而是因为它被太多人测过,防护体系(WAF、RASP、风控、统一鉴权网关)叠了好几层,任何可疑请求在到达业务代码之前就已经被拦掉。你花三天在主站上碰运气,不如花三小时把一个边缘子域的攻击面梳理清楚。

另一个常见误区是"工具依赖症":以为把 nuclei 的模板全跑一遍、把 xray 的被动扫描挂上,就能出货。但模板只能匹配已知特征,而 SRC 里真正值钱的是逻辑漏洞和业务鉴权缺陷——比如"订单号可枚举"“优惠券可叠加”“审批流可绕过"这类问题,没有任何一个扫描器能自动发现,必须靠人工理解业务流程、站在开发者视角去推测"这里有没有做服务端校验”。工具的作用是帮你把"可达资产"和"可控输入"快速铺开,最后的判断仍然要靠人。工具负责广度,人负责深度,两者缺一不可。

一、核心原理:把攻击面画成一张图

1.1 攻击面公式

一个可被利用的漏洞,本质上是三个集合的交集:

可利用漏洞 = 可达资产 ∩ 可控输入 ∩ 权限校验缺失
  • 可达资产:域名、IP、端口、API、小程序、App、第三方 SDK 回连地址;
  • 可控输入:URL 参数、Header、Body 字段、文件名、跳转地址、WebSocket 消息;
  • 权限校验缺失:水平越权(同角色跨用户)、垂直越权(低权限调高权限)、未授权访问。

绝大多数人只做了第一步的 30%,就直接跳到"扫漏洞",等于闭着眼睛开枪。

这三个集合,每一个都值得展开:

可达资产是最外层的漏斗。它不只是"域名列表",还包括:同一主域下的所有子域、同 C 段/同云厂商 IP、移动端 App 抓包后暴露的 API 域名、微信小程序的后端请求、公众号 H5、以及第三方登录/SDK 的回调地址。很多接口在浏览器里访问不到,但在 App 或小程序里是活的——这就是"资产"与"入口"的差异。

可控输入决定你能"碰到"什么。同样是GET /user/detail,如果参数是服务端从 Session 里取的,你没有可控点;如果参数是?uid=123,可控点就出现了。挖掘时要习惯性地问自己:这个请求里,哪些字段是我能改的?改了之后服务端会不会重新校验?Header 里的X-User-Id、X-Forwarded-For、Referer往往是鉴权逻辑的软肋。

权限校验缺失是最终能否成洞的关键。可达 + 可控只是前提,只有当服务端"信任了不该信任的输入"或"漏掉了归属校验",漏洞才成立。这三者构成的交集思维,能帮你在面对一堆接口时快速判断"哪些值得深挖"。

1.2 边缘资产才是主战场

一个成熟厂商的资产分层大致是:

层级典型形态防护强度出洞概率
核心主站、核心 API 网关极高低
业务活动页、子品牌站、小程序后端中中
边缘测试环境、旧版系统、供应商系统、静态资源域低高

边缘资产的价值在于:它们往往由外包或不同团队维护,认证体系不统一,甚至直接暴露在公网且没有 WAF。一个test-xxx.com的子域,可能就是整个项目最容易进的入口。

为什么边缘资产这么"脆"?原因有三:其一,生命周期管理缺失——测试环境上线后没人下线,默认口令、调试接口一直开着;其二,团队边界模糊——外包交付的系统往往只保证"功能可用",安全配置靠默认值,Swagger、Actuator、Druid 监控页经常裸奔;其三,资产台账不全——安全团队自己都不知道这些域名的存在,自然不会纳入防护和巡检。

因此,实战中要特别关注这几类信号:域名里带test、dev、uat、pre、demo、old、beta的;标题里带"管理后台"“运维平台”"监控"的;指纹里出现Swagger UI、Spring Boot Actuator、Nacos、Jenkins、Druid、Grafana的。这些关键词一旦命中,优先级立刻拉到最高。此外,别忽略历史解析记录——一个域名现在指向 CDN,但它三个月前可能直接解析到一台没有 WAF 的源站 IP,通过 SecurityTrails、VirusTotal、微步等平台的被动 DNS 数据,往往能还原出真实 IP,从而绕过 CDN 直连测试。

二、资产收集:从域名到接口清单

2.1 子域名与存活探测

被动收集优先(不触发目标告警),证书透明日志(crt.sh)、被动 DNS、搜索引擎语法是主力。下面是常用的流水线脚本:

#!/bin/bash# 用法: ./recon.sh example.com# 仅用于已授权目标domain="$1"mkdir-pout# 1) 被动子域名枚举subfinder-d"$domain"-all-silent-oout/subs_raw.txt# 2) 证书透明日志补充(能挖到很多内网命名习惯的域名)curl-s"https://crt.sh/?q=%25.$domain&output=json"\|jq-r'.[].name_value'\|sed's/\*\.//g'|sort-u>>out/subs_raw.txtsort-uout/subs_raw.txt-oout/subs.txtecho"[+] 子域名数量:$(wc-l<out/subs.txt)"# 3) 存活 + 状态码 + 标题 + 指纹,一次请求全拿到httpx-lout/subs.txt-silent-sc-title-tech-detect-cdn\-oout/alive.txt# 4) 端口扫描(top 1000 足够,全端口留给重点 IP)naabu-lout/subs.txt -top-ports1000-silent-oout/ports.txt

关键点:httpx输出的tech-detect字段是后续漏洞匹配的核心依据。看到Spring Boot、Swagger UI、Nacos、Jenkins这些关键词,优先级立刻拉满。

这段脚本背后的原理值得说清楚。subfinder走的是被动源聚合路线:它本身不向目标发任何请求,而是从几十个公开数据源(证书日志、被动 DNS、搜索引擎、威胁情报)里把子域名字典拼出来,因此不会触发目标的 WAF 告警。而crt.sh查询的是证书透明日志(Certificate Transparency Log)——这是 CA 机构必须公开记录所有签发证书的机制,任何人只要为*.example.com申请过证书,其子域名就会永久留痕。很多公司给内网测试域名也签了证书,于是dev-internal.example.com、gitlab-test.example.com这类命名习惯就全暴露了。

实操中最常见的三个问题是:

  1. 子域名太多,无从下手。解决办法是分层排序:先按状态码过滤(只留 200/401/403/500),再按标题和指纹打标签,最后把带敏感关键词的(admin、test、api、manage)排在最前。
  2. 被动源覆盖不全。建议同时跑 subfinder、amass(passive 模式)、OneForAll,三者取并集,因为它们的上游数据源重合度并不高。
  3. 存活探测被 CDN 干扰。httpx -cdn会标记出哪些域名走 CDN,这些域名直连测试意义不大,真正要挖的是那些没有 CDN、直接回源的边缘域名。

2.2 JS 文件:被低估的接口金矿

现代前后端分离架构下,所有前端调用过的接口,都会在 JS 里留下痕迹。很多人只看了首页 JS,却忽略了懒加载的 chunk 文件。

importre,sys,requestsfromurllib.parseimporturljoin# 匹配 JS 中的路径与接口字面量PATTERN=re.compile(r"""["'`]((?:/|https?://)[A-Za-z0-9_\-./?=&%{}:]{4,140})["'`]""")deffetch(url,timeout=10):try:r=requests.get(url,timeout=timeout,verify=False,headers={"User-Agent":"Mozilla/5.0"})returnr.textifr.status_code==200else""exceptException:return""defextract(js_url,target_domain):text=fetch(js_url)hits=set()forminPATTERN.findall(text):# 只保留目标域及相对路径,过滤第三方 CDNifm.startswith("http")andtarget_domainnotinm:continueifany(m.endswith(ext)forextin(".png",".jpg",".svg",".woff",".css")):continuehits.add(m)returnhitsif__name__=="__main__":domain=sys.argv[1]js_files=[l.strip()forlinopen("out/js.txt")ifl.strip()]apis=set()forjsinjs_files:apis|=extract(js,domain)forpinsorted(apis):print(p)

拿到接口清单后,重点看三类:

  1. /api/v1/internal/、/actuator/、/swagger-ui.html—— 未授权访问高发;
  2. 带数字 ID 的接口—— 水平越权高发;
  3. export、download、batch类接口—— 逻辑漏洞与信息泄露高发。

为什么 JS 是金矿?因为现代前端用 Webpack/Vite 打包,接口路径、参数名、甚至部分密钥都会以字符串字面量的形式被编译进产物。首页加载的往往只是app.js这个主入口,真正的业务接口分散在chunk-vendors.js、1.a3f2.js、page-order.[hash].js这些懒加载分片里——它们只有当用户点到对应页面时才会被浏览器请求,但文件名通常记录在主 chunk 的映射表里,可以顺着提取出来。很多人只抓了首页 JS 就收工,等于只挖了 10% 的接口。

补充两个进阶技巧:

  • 找 sourcemap:如果产物里存在//# sourceMappingURL=app.js.map,或者站点没关掉.map文件,直接下载就能还原出近乎完整的源码,接口、注释、内部字段一览无余。这是 SRC 里性价比极高的一个点,但要注意——只读取、不落地敏感数据。
  • 搜硬编码密钥:在 JS 里正则匹配AKIA、accessKey、appSecret、secret、token、Authorization: Bearer等关键词,经常能挖到对象存储密钥、第三方 API Key。这类问题提交时要注意脱敏,并说明"密钥已泄露、建议立即轮换"。

另外,提取接口时一定要把相对路径和绝对路径分开处理:相对路径要拼上来源 JS 所在域的 base,绝对路径要判断是否属于目标域,第三方 CDN 的地址(如https://cdn.xxx.com/lib.js)要过滤掉,否则接口清单会被噪音淹没。

三、漏洞验证:从可疑点到可提交的 PoC

3.1 最小化验证原则

发现可疑接口后,不要批量跑。正确的做法是:

  1. 用 A 账号请求一次,记录响应结构;
  2. 换成 B 账号(或去掉 Cookie),请求同一个 ID;
  3. 对比响应:如果 B 能看到 A 的数据,越权成立;
  4. 立刻停止,只保留 1~2 条证据(响应片段截图 / 请求响应报文),不下载、不导出、不扩散。

批量拉取数据不仅会触发风控告警,还可能被认定为"超出授权范围",直接导致漏洞被忽略甚至账号被封。

这条原则之所以重要,是因为 SRC 审核的核心判断标准是"你是否证明了危害,同时把影响控制在最小"。你拉取 1000 条订单,和拉取 2 条订单,证明的都是"存在越权",但前者在审核眼里是"恶意利用",后者是"合规验证"。很多新手明明挖到了真洞,却因为"拖库式验证"被平台判定为违规,得不偿失。记住:验证是点到为止,不是数据搬运。

3.2 一个真实场景:从 JS 到未授权越权

某次授权测试中,从app.xxx.com的 chunk JS 里提取到:

/api/v1/user/profile?uid=10086 /api/v1/order/detail?orderId=2023xxxx

直接去掉 Cookie 请求profile接口,返回401,说明有认证。但把uid从自己的改成别人的,仍然返回了对方手机号前三位与昵称——典型的认证有、鉴权无。这种"参数级越权"是 SRC 里最常见也最容易拿中危的场景。

这个案例的典型性在于,它完美对应了 1.1 节的攻击面公式:接口可达(JS 里泄露)、输入可控(uid是明文参数)、鉴权缺失(服务端只校验了"是否登录",没校验"这个 uid 是不是你的")。很多开发者会想当然地认为"用户登录后只能看到自己的 uid",于是只做了认证不做鉴权,而这恰恰是越权漏洞的温床。类似的还有:把userId放进 Header、把资源 ID 直接拼在 URL、分页接口的pageSize不设上限(导致信息泄露)等等。

3.3 越权批量验证脚本(带节流)

当你确认了越权模式,需要小范围证明影响面时,用下面这个脚本,注意严格限速 + 只读 + 不落地:

importrequests,random,timefromconcurrent.futuresimportThreadPoolExecutor COOKIE_A="session=YOUR_LOW_PRIV_SESSION"# 低权限账号URL="https://api.example.com/api/v1/order/{id}"HEADERS={"Cookie":COOKIE_A,"User-Agent":"Mozilla/5.0"}defcheck(rid):try:r=requests.get(URL.format(id=rid),headers=HEADERS,timeout=8)# 只判断状态码与是否存在业务关键字段,不保存响应正文ifr.status_code==200and'"orderId"'inr.text:return(rid,r.status_code,len(r.text))exceptExceptionase:return(rid,"ERR",str(e)[:40])returnNone# 随机取样,避免连续 ID 造成"遍历"嫌疑ids=random.sample(range(200000,999999),50)withThreadPoolExecutor(max_workers=3)aspool:# 并发压到 3forresinpool.map(check,ids):ifres:print(res)time.sleep(0.3)# 主动节流,避免影响业务

脚本输出的每一条200都是证据。验证到 3~5 条即可证明危害,不必继续跑。

这里的三个设计点值得强调:random.sample是为了避免连续 ID 遍历——如果从 100001 顺序扫到 100050,日志里就是明显的"枚举行为",风控秒级告警;max_workers=3是把并发压到极低,避免对业务造成压力;time.sleep(0.3)是主动节流。最后的输出只保留(id, status, length)三元组,不落地任何响应正文,这样即使被审计,也能证明你只做了"存在性验证"而非"数据窃取"。

四、报告与提交:让审核一眼看懂

4.1 报告结构模板

一份被快速通过的报告,通常包含以下要素:

【漏洞标题】xxx系统 /api/v1/order/detail 接口水平越权(可读取他人订单) 【漏洞类型】越权访问(CWE-639) 【危害等级】高危 / 中危(按 SRC 规则) 【影响范围】https://api.example.com 【复现步骤】 1. 使用账号 A(138****0001)登录,获取 Cookie; 2. 请求 GET /api/v1/order/detail?orderId=10001,返回 A 的订单; 3. 将 orderId 修改为 10002(属于账号 B),其余不变,重放; 4. 响应 200,返回账号 B 的收货人姓名、手机号、地址。 【请求报文】...(完整原始请求) 【响应报文】...(关键字段脱敏,保留结构证明) 【危害说明】任意登录用户可遍历 orderId 获取全站订单,涉及用户隐私数据泄露。 【修复建议】服务端基于当前登录态校验资源归属(order.user_id == session.user_id), 并对 orderId 做不可预测化处理(UUID / 加盐哈希)。

4.2 提高通过率的三个细节

  • 标题带接口和危害,不要写"某处存在越权";
  • 证据链完整:请求 + 响应 + 账号归属对比,缺一不可;
  • 危害描述克制:不要写"可导致全站数据泄露、影响千万用户",审核最反感夸大,如实描述影响面即可。

再补充几点实操经验。第一,复现步骤要"可被审核独立复现"——审核人员手里没有你的账号,所以你要么提供测试账号,要么用清晰的前后对比截图说明"账号 A 拿到了账号 B 的数据"。第二,响应报文要脱敏但保留结构——手机号中间四位打码、身份证号只留头尾,但字段名、层级、状态码必须完整,让审核能判断"这确实是敏感数据"。第三,修复建议要落到代码层面——"加强鉴权"这种空话没人看,写清楚"在OrderService.detail()里加if (order.getUserId() != currentUser.getId()) throw new ForbiddenException()"才有价值。一份好的报告,本质上是让审核在 3 分钟内完成"看懂 → 相信 → 定级"三步。

五、踩坑与优化建议

坑一:把扫描器结果直接提交。扫描器的Possible SQL Injection十有八九是误报,提交后被忽略会拉低你的信誉分。所有提交必须有人工验证的 PoC。

坑二:忽略授权边界。很多 SRC 的授权范围只包含*.example.com,但不包含其供应商系统、云存储桶、第三方 SaaS。越界测试一次,可能直接封号。

坑三:重复率管理。提交前先搜索该 SRC 的历史漏洞公告和公开 writeup,同一接口的同类问题大概率已被提交过。建议用接口路径、参数名、业务模块等关键词在平台漏洞库、Google、GitHub 上交叉检索,确认无人提交后再动手。

坑四:只测一个参数就下结论。很多人发现uid越权后,提交完就结束了。但同一个接口往往还有orderId、fileId、addressId等多个资源 ID,同类问题应当合并成一份报告,而不是拆成十条提交——后者会被判定为"刷漏洞",反而影响信誉。

坑五:忽略认证状态的变化。验证越权时,一定要明确"当前是登录态还是未登录态"。同样是越权,未登录可访问(未授权访问)的定级通常高于登录态的水平越权,报告里要写清楚前置条件。

优化建议:建立自己的"资产台账",用表格记录每个目标的域名、指纹、测试进度、已提交漏洞,避免重复劳动;同时维护一份"接口模式库",把?id=、?uid=、?orderId=这类高风险参数沉淀下来,遇到新目标时优先套用。

六、常见问题 FAQ

Q1:没有授权,能不能先测再补授权?
绝对不行。未授权测试在国内属于明确违法行为,且 SRC 平台也不认可"事后补票"。正确顺序是:先在 SRC 平台确认目标在授权范围内,阅读其测试规范(是否允许扫描、是否允许自动化),再动手。

Q2:子域名收集了几千个,怎么快速筛出高价值目标?
用"状态码 + 指纹 + 关键词"三层过滤:先保留 200/401/403 的存活站,再筛出含Swagger、Actuator、Nacos、Jenkins等指纹的,最后用admin|test|api|manage|internal关键词排序。通常几十个目标里就能出 1~2 个高价值入口。

Q3:越权漏洞提交后总被标"重复",怎么办?
越权是重灾区,重复率极高。提高命中率的关键是找到别人没测过的边缘接口——比如从 App 抓包、小程序、旧版 API 里提取的接口,而不是主站首页那些人人都在测的接口。另外,同一系统的越权点如果有多个,优先提交影响面最大的那个。

Q4:验证时被 WAF 拦了怎么办?
先判断是"误拦"还是"真拦"。可以尝试调整请求频率、更换 User-Agent、去掉明显的扫描特征(如sqlmap的默认 Header)。但不要尝试绕过 WAF 去攻击——如果目标明确禁止绕过,绕 WAF 本身就可能违规。遇到强 WAF 时,更聪明的做法是转去测没有 WAF 的边缘资产。

Q5:报告提交后多久有反馈?被忽略怎么办?
各平台不同,通常 3~15 个工作日。如果被忽略,先看审核理由:若是"无法复现",就补充更清晰的证据链;若是"危害不足",就重新评估影响面,必要时升级为组合漏洞(如"越权 + 信息泄露")。切忌反复提交同一份内容,那只会消耗你的信誉分。


以上流程的核心,其实就是把"运气"变成"方法":用资产收集扩大分母,用攻击面梳理聚焦分子,用最小化验证控制风险,用清晰报告完成闭环。

更多硬核网安与AI工具包,请扫码获取完整源码!
工具会过时,但这套以攻击面为中心、以合规为边界的思维方式,在任何目标上都适用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 8:10:57

二叉树の递归遍历

学习一下卡哥的递归思路 原帖&#xff1a;二叉树的递归遍历 | 递归 | 二叉树遍历 | 代码随想录-全网最全算法数据结构刷题学习路线|图文视频教程|免费开源 每次写递归&#xff0c;都按照这三要素来写 确定递归函数的参数和返回值 确定哪些参数是递归的过程中需要处理的&…

作者头像 李华
网站建设 2026/10/7 8:08:49

可穿戴健康数据指标体系拆解:从50项原始指标到3个可读分数

本文要处理的问题&#xff1a;把五十多项原始生理指标&#xff0c;收敛成用户能读懂、且长期稳定的少数几个分数。一、问题&#xff1a;指标越多&#xff0c;用户越不读可穿戴设备采集能力的提升&#xff0c;并不自动带来使用率的提升。以一款主打夜间监测的指戴设备为例。它的…

作者头像 李华