挖了100个漏洞之后,我发现自己真正学会的,不是哪个函数危险、哪个参数好测,而是一套反复在实战中被验证的底层逻辑。很多人问我,漏洞挖掘是不是靠运气?是不是要特别聪明?其实都不是。漏洞挖得多了你会发现,它更像是一门“找异常”的手艺,有迹可循,有法可依。这篇内容就把我这100个漏洞背后的思考方式和实操路径,完整复盘一遍。
1. 挖洞这件事,先想明白再动手
1.1 为什么是100个漏洞,而不是10个
刚开始接触漏洞挖掘的时候,我也和大多数人一样,喜欢逛各种漏洞报告,看大神们写的高级利用链,觉得自己看懂了一些偏门技巧,就能上手挖洞。结果动手一测,全不是那么回事。今天试了个SQL注入,明天试了个XSS,后天对着一个登录框发了一堆数据包,最后什么都没出。后来我才发现,看别人的漏洞报告和亲自挖到第一个漏洞之间,隔着一条巨大的鸿沟。这条鸿沟不是技巧,而是思维模式。
我从第1个漏洞走到第10个漏洞,用了将近两个月。但从第10个到第50个,只用了一个多月。从第50个到第100个,就更快了。不是因为我的工具变强了,也不是因为我挖的站点变简单了,而是因为我在第10个漏洞之后,终于把“怎么找漏洞”这件事,从一个个零散的点,串成了一条完整的线。这条线,就是我后来一直跟人强调的“底层逻辑”。
很多人高估了漏洞挖掘的技术门槛,觉得得先精通汇编、逆向、内核,才能开始挖。但事实上,大部分Web层面的漏洞,考验的不是你会多少技术栈,而是你能不能快速理解一个系统的业务逻辑,然后找到逻辑断裂的地方。100个漏洞的意义,不在于数量本身,而在于它逼着我把所有撞过的墙、踩过的坑,沉淀成了一套可以复用的方法论。
1.2 找漏洞到底靠什么:知识、经验还是直觉
有人会问,挖漏洞的时候,是靠脑子里积累的漏洞模式,还是靠临场反应?我的答案是:前期靠知识,中期靠经验,后期靠直觉,但直觉本质上是前两者的快速检索。
举个简单的例子。看到一个搜索框,新手会直接输入单引号看看报不报错,或者输入一个<script>看看弹不弹窗。但挖到一定数量之后,你看到搜索框的第一反应是:这个搜索功能部署在哪个服务上?它的索引是什么?它返回的数据结构是什么样的?有没有搜索建议接口?这个接口是不是内网SSRF的最佳跳板?这些思考路径,就是靠长期实战喂出来的“条件反射”。
所以,我在这篇文章里反复强调“底层逻辑”,并不是要灌输什么高深理论,而是想帮你把每次测试时的思考过程,从“毫无章法地试”变成“有假设、有验证、有结论”的科学流程。这就像做实验,优秀的测试者一定是在不断提出假设并验证,而不是漫无目的地发请求。
2. 底层逻辑拆解:漏洞是怎么跑到代码里的
2.1 一切的起点:入口与数据流
挖了这么多漏洞之后,我把所有漏洞归纳成一句话:一切漏洞都是数据流在某个环节没有按照预期流转造成的。换句话说,只要数据从输入到输出的路径上,存在某个环节对数据没做够校验、够清洗,或者错误地信任了某些数据,这里就是漏洞的藏身之处。
理解了这一点,你就能明白为什么每次测试都要先梳理入口。入口是什么?入口就是所有你能控制数据进入系统的地方。URL参数、POST请求体、请求头、Cookie、文件上传的二进制内容,甚至WebSocket消息,都是入口。你要做的是画一张简单的心智地图:你输入的数据到哪个函数处理了,经过了哪些过滤,最后在哪里被输出或拼接。
我拿一个经典案例来说。某次我测试一个站内搜索功能,发现搜索关键词会被带回页面高亮显示。这就是一个典型的“反射型XSS”入口,但因为系统做了转义,直接注入<script>是不行的。我后来把目光从URL参数转移到请求头,发现搜索服务在记录用户搜索日志时,会把User-Agent原样写入日志文件,管理后台又能查看这段日志。于是UA头里的恶意构造内容,就在后台页面里被原样执行了。这就是跟着数据流走,在某个意想不到的节点安全措施断裂的例子。
所以实操的第一步永远是:梳理入口,跟踪数据流,寻找信任边界。不用急着拿扫描器乱扫,先把系统怎么跑的搞清楚,再动手。
2.2 信任边界:攻击者和开发者打架的地方
第二个底层逻辑是信任边界。任何一个稍微复杂一点的系统,都不可避免地存在信任边界。开发者默认用户永远不会传负数、永远不会传超长字符串、永远不会传两个同名参数、永远不会直接用旧版本资源文件。但攻击者的每一分每一秒,都在试探这些“默认”是否可以被打破。
最常见的信任边界,就是身份与权限。例如,一个普通用户在修改个人资料时,请求里带了user_id=10086。开发者可能自信地认为,用户只能通过界面修改自己的资料,所以接口不需要再做归属校验。但攻击者把user_id改成10087呢?如果后端直接信了,这就是越权漏洞。这类漏洞我在100个漏洞里遇到得非常多,尤其在中小型系统里,几乎是重灾区。
这类逻辑漏洞为什么难防?因为它在编码阶段不会触发任何异常,功能测试时也测不出来,因为它遵循了界面操作流程,只是攻击者手工修改了请求数据。边界信任的建立,有时候甚至不是开发者的问题,而是产品设计层面的问题。但攻击者不管这些,他们只关心这个“边界”存不存在。
因此,在你测试任何业务功能时,都该养成习惯性怀疑:既然我提交这个数据,那后端拿它做了什么?它有没有和我已有的身份绑定?如果我换成别人的身份来调用,会发生什么?
2.3 业务逻辑漏洞:不按套路出牌
业务逻辑漏洞,是我个人认为性价比最高的一类漏洞,同时也是很多人最容易忽略的。它不需要你懂多高深的技术,只需要你对业务流程足够敏感。比如订单支付时先创建订单再扣款,那如果我先选择商品生成订单,再并发地分别调用支付,会发生什么?比如优惠券在结算时被用掉了,那如果我在两个选项卡里同时使用同一张券呢?
这类漏洞更考验“产品思维”。你需要站在开发者和产品经理的角度推演:这个流程在正常业务里应该是怎样的?在异常场景下会变成怎样?举个例子,一个积分商城,兑换礼品的接口接收goods_id,兑换成功后扣除积分。那如果我在兑换的同时,用另一个请求不断刷新积分余额,或者用两个账号同时操作,有没有可能把同一个商品兑换两次?这些情况如果后端没有做好幂等控制,就会被薅穿。
还有一类业务漏洞发生在状态转换上,比如订单状态从“待支付”变成“已支付”。如果状态变更的校验只发生在前端,那通过接口直接请求状态变更,配合参数伪造,就能绕过支付环节。这类漏洞在低代码平台、快速迭代的业务站点中尤其常见。
所以,业务逻辑漏洞的挖掘方式,和传统注入类完全不同。一条实用的路子是:把你在前端完成的每一个操作步骤都记下来,然后逐步回放,思考哪些步骤是可以缺省、可以重复、可以调换顺序的。
3. 从0到1的实操路径
3.1 第一阶段:搭好环境和思维框架
很多人一上来就想挖真实系统,这是不对的。挖洞和练武一样,先在可控环境里把基本动作做标准,再出去实战。我强烈建议你在本地搭一套靶场,可以先从包含常见漏洞的开源靶场环境开始,有的可以模拟SQL注入、XSS、文件包含、命令执行等经典场景,有的更贴近真实业务逻辑。
搭靶场的过程本身也是学习的一部分。你要了解PHP、MySQL、Apache这几种组件如何协同工作,这能帮你直观地理解“数据流”是怎么回事。更重要的是,在靶场里你可以放心大胆地破坏,可以反复调试,可以观察漏洞触发前后的系统行为。
有句话我特别认同:在靶场里“造轮子”不是浪费时间。你在靶场里把每一个漏洞的触发原理、请求构造过程、响应差异都吃透了,再到真实系统里,面对一个被WAF保护、存在复杂权限体系的目标时,才不会手足无措。
另外,思维框架也可以在这一阶段建立起来。我给自己定了一个简单的测试清单,每次测一个功能点时都会过一遍:第一,有没有参数可以控制?第二,这个参数会不会被拼接到代码里?第三,参数回显在哪里?第四,有没有权限校验?这套清单撑起了我早期绝大部分漏洞的发现。
3.2 第二阶段:选择合理的目标和策略
有一定基础后,就可以找一些授权范围内的目标来练手了。这里我强调一下,漏洞挖掘的前提必须是合法合规,一定要在获得授权的前提下进行,或者选择公开的漏洞众测项目,或者公司内部授权的安全测试项目,这些渠道既能保证法律安全,也能让你接触到真实业务系统。
选目标也有策略。我个人的选择顺序是:优先选择功能丰富但防护相对薄弱的站点,例如老旧的内部管理系统、客户门户、API接口平台等。这些系统往往开发周期短、业务逻辑复杂,安全测试覆盖也不充分,出现漏洞的概率比核心主站要高得多。
选定目标后,第一步是注册一个账号,把能点的功能都以正常用户身份过一遍,记录下每个功能对应的URL、参数、请求方法,第二步是查看前端代码找找有没有接口列表,第三步才是针对每个接口展开参数调校和逻辑分析。
这里分享一个小习惯:我会把每一个请求都保存下来,按模块分类存放。这看起来有点笨,但当你在一个系统里测到第三天、第四天的时候,这些历史请求会成为你排查问题、对比差异的重要依据。很多时候,你在第一天注意到的一个小异常数据,会在第三天的另一个功能里和某个漏洞串联起来。
3.3 第三阶段:验证、利用与收尾闭环
当你发现一个可疑点时,不要急着上报,也不要急着用工具猛打。先手工构造请求,做最小化验证。比如怀疑SQL注入,先用单引号和逻辑运算符观察响应差异,再用延时函数测时间盲注,每一步都保持可控。验证通过后,再考虑如何进一步利用,但不要做破坏性操作。
在提交漏洞报告时,也要讲究方式方法。一个高质量的漏洞报告,至少要包含:漏洞位置、影响范围、复现步骤、请求示例、影响分析、修复建议。我见过太多人挖到漏洞但因为报告写得敷衍,导致审核人员看了半天都没看懂,草草关闭。这非常可惜。报告不是写给你自己看的,是写给一个完全不了解你测试思路的审核者看的,所以要尽可能清晰、可复现。
闭环的最后一步是修复验证。很多人在提交报告后就不再跟进,但如果你能提供复测,确认漏洞被彻底修复,这会大大增加你在平台上的可信度,后续获得高质量项目的概率也会更高。
4. 挖洞过程中踩过的坑
4.1 为什么你的漏洞都被忽略
我自己早先挖洞时最郁闷的事,就是提交了一个“自认为很严重”的漏洞,结果被平台标记为“忽略”。后来我才逐渐摸清问题所在。大部分被忽略的漏洞,都是因为影响范围被高估了。
比如你找到一个自用的、没有任何用户信息、也无法被打到公网的接口,产生了一次SQL报错。这个报错确实存在,但它既不涉及数据泄露,也无法形成实际危害,在平台的价值评估体系里,优先级就非常低。还有些人喜欢把Cookie中某个参数的加密值解密出来,报告“加密算法不安全”,但如果没有配套利用链,这只是一个信息展示。
所以,在动手之前,先判断一下这个漏洞的“可触达性”和“业务影响”。这个接口是登录后才能访问的吗?能造成横向影响吗?敏感数据是访客可读还是仅限管理员?这些思考,能帮你避免做大量无用功。
另一个常见的忽略原因是重复。尤其是排名靠前的目标,很多漏洞早被别人提交过了。这时候你不必气馁,可以在已有思路上换一个绕过姿势,或者换个参数继续深挖。很多SQL注入漏洞之所以能绕过WAF,就是因为攻击者换了一种编码方式、一个位置、一个函数,才在边界处找到突破口。
4.2 容易被忽视的高频高危点
我会建议你把注意力放在几个“高频高危”功能模块上:登录认证、密码找回、文件上传、订单支付、消息通知、数据导出、批量查询接口。
先说登录认证。暴力破解本身价值不高,但“用户名枚举”能帮你确认账号是否存在,从而配合密码喷洒。更值得关注的是验证码可否重复使用、是否存在万能验证码、登录响应是否泄露了不同的错误信息。这些细节一旦出现问题,整个认证体系就基本是透明的。
文件上传这个功能,几乎是高危漏洞的温床。很多系统虽然对后缀名做了限制,却忽略了文件内容的校验。你上传一个包含PHP代码的图片文件,再想办法让服务端解析它,就可以拿到WebShell。这里的难点在于如何找到一个可解析的上传路径。测试时关注上传文件后的URL反馈,以及文件名是否被重命名。
批量查询接口也值得多花时间。这类接口通常被设计为接收一个ID列表,然后返回多条数据。如果后端没有做数据权限过滤,那么通过遍历ID,你就能把本不该公开的记录全捞出来。这类“越权查询”漏洞在内部管理系统、订单平台中极其常见。
4.3 实战排查技巧实录
记忆里有这么一次测试,目标是一个在线学习平台。我注册了学生账号,发现课程详情页有一个“下载课件”的功能,请求URL里包含了course_id和file_name两个参数。一开始我没当回事,因为file_name看起来是经过编码后的随机字符串。但我在学员群里发现有人分享了另一个课程的下载链接,URL里course_id不同,但file_name的格式极其相似。我把两组链接放在一起对比,发现file_name前半部分疑似时间戳,后半部分疑似文件ID。
于是我开始尝试遍历course_id,同时保持file_name不变,连续访问了几十个请求后,竟然真的拉取到了好几节其他课程的视频课件。最后确认,后端只校验了用户是否登录,没有校验该用户是否购买了对应课程,也没有校验文件与课程的关联性。这就是一个因为没有做资源归属校验导致的越权漏洞。
这类问题怎么排查?核心技巧是“对比法”。用两个不同权限的账号访问同一个资源,或者访问两个相似资源,对响应做对比。差异点往往就是漏洞所在。再有一个技巧是“控制变量法”,比如你已经怀疑某个参数可疑,那就只改动这个参数,其他条件完全保持一致,逐步缩小问题范围。
5. 回到底层逻辑:把“找漏洞”变成一种习惯
挖了100个漏洞,我最大的改变不是技术变强了,而是看任何系统都比以前“刻薄”。看到一个搜索框,我会下意识想想它后面的查询语句长什么样;看到一个文件下载接口,我会思考它有没有校验下载者身份。这种思维模式一旦建立起来,漏洞挖掘就从一项任务变成了一种习惯。
在这个过程里,你积累的工具、语法、技巧都会过时,但你对系统的理解方式、对信任边界的敏感度、对数据流的追踪能力,会一直沉淀下来。我也建议你给自己定一个小目标,不用急于求成,先在一个靶场环境里连续挖出10个漏洞,把每一个都写成笔记,形成自己的知识库。技术可以学习,但挖洞的底层逻辑,必须通过无数次实践来内化。
说到底,漏洞挖掘就是在人意料之外的地方寻找必然。每个漏洞背后都藏着一个开发者没有说出口的假设。我们做的,就是去审视这些假设到底站不站得住脚。保持好奇,保持谨慎,再多一点耐心,你也能慢慢摸清这条路的门道。