业务逻辑绕过漏洞挖掘实战:从原理到SRC报告撰写
1. 项目概述从“找洞”到“挖洞”的思维跃迁做SRC安全应急响应中心漏洞挖掘很多新手朋友一上来就直奔SQL注入、XSS、文件上传这些“显性”漏洞拿着扫描器一顿狂扫结果往往颗粒无收或者只能捡到一些别人早就提交过的低危、无效漏洞。其实真正能让你的报告在SRC平台脱颖而出甚至拿到高额奖金和厂商认可的往往是那些扫描器发现不了、需要你动脑分析的“业务逻辑漏洞”。而“业务逻辑绕过漏洞”正是这类漏洞中的“常青树”和“高价值目标”。我干了十多年安全从乙方渗透测试到甲方安全建设再到如今专职做SRC和漏洞研究一个深刻的体会是技术工具大家都会用但挖掘漏洞的“思维”才是分水岭。业务逻辑绕过漏洞考验的不是你对某种攻击技术的掌握深度而是你对一个业务流程的“理解深度”和“破坏性想象力”。它就像一场“猫鼠游戏”你需要站在开发者的角度去理解他设计的流程然后再以攻击者的视角去寻找这个流程中“想当然”的信任缺口。简单来说业务逻辑绕过漏洞的核心就一句话前端限制得再花哨后端没做强制校验一切白搭。攻击者通过拦截并修改客户端如浏览器、APP发送给服务器的请求参数就能跳过关键步骤、篡改关键状态直接达成业务目的。比如本该“提交申请-等待审核-通过”的流程你抓个包把状态从“待审核”改成“已通过”后端如果直接信了那这个审核环节就形同虚设。这类漏洞复现起来往往不需要复杂的Payload一个Burp Suite一双善于发现流程的眼睛就能让你有所收获。今天我就以一个老鸟的身份带你彻底拆解“业务逻辑绕过漏洞”。我们不只讲原理和复现更要深入背后的设计缺陷成因分享我实战中总结的“狩猎”思路并给你一份能直接拿去用的、高通过率的SRC报告模板。无论你是刚入门的安全爱好者还是想提升挖洞效率的SRC玩家这篇文章都能让你对逻辑漏洞有一个全新的、实战级的认识。2. 漏洞原理深度剖析信任的边界在哪里要挖洞先懂原理。业务逻辑绕过漏洞之所以存在根源在于“信任链”的断裂。现代Web应用通常是前后端分离的架构前端负责展示和交互逻辑后端负责核心业务逻辑和数据持久化。一个健康的业务流程其状态流转应该由后端牢牢掌控。2.1 核心缺陷前后端校验不一致绝大多数逻辑绕过漏洞都源于一个经典错误开发者将业务流程的控制权部分或全部交给了不可信的前端。前端限制是“建议”前端通过JavaScript禁用按钮、隐藏表单、进行条件判断例如if(status ! ‘approved’) { 显示审核中 }这些操作都发生在用户的浏览器里。攻击者可以轻易地禁用JavaScript、修改本地HTML/JS文件或者直接使用代理工具拦截请求完全绕过这些限制。后端校验是“法律”后端服务器接收到的每一个请求都应该被视为“不可信的”。它必须重新、独立地校验用户的身份你是谁、权限你能做什么以及当前请求在业务流程中的合法性你现在做这件事合规矩吗。如果后端盲目信任前端传来的参数漏洞就产生了。举个例子一个优惠券使用流程前端用户选择商品和优惠券计算总价。如果优惠券已过期前端JS会弹出提示“优惠券无效”并禁用提交按钮。后端错误设计接收订单请求{“goods_id”: “123”, “coupon_code”: “EXPIRED123”, “total_price”: 10}。它只检查了优惠券码EXPIRED123在数据库中是否存在发现存在就直接扣减了金额没有校验该优惠券的status或expire_time字段。攻击用户拦截订单请求即便使用的是过期优惠券码后端也成功处理了订单。这就是典型的“后端缺乏状态校验”导致的逻辑绕过。2.2 常见漏洞场景模式化总结根据我多年的经验业务逻辑绕过漏洞高发于以下几类场景你可以把它们当成你的“重点检查清单”状态跃迁绕过这是最经典的场景。任何有状态流转的地方都是富矿。审核流程待审核(0)-审核通过(1)/审核拒绝(2)。尝试直接修改为“通过”。订单流程待支付(0)-已支付(1)-已发货(2)-已完成(3)。尝试从“待支付”直接修改为“已完成”或“已发货”。任务流程未开始-进行中-已完成。尝试直接标记为“已完成”。关键点寻找请求中的status、state、step、phase等参数。条件竞争绕过这类漏洞在业务高峰期或高并发设计不佳的系统中尤其有效。限量领取限量100份的优惠券在最后一份被领取的瞬间多个用户同时发起领取请求后端如果没有做好“原子性”校验如数据库行锁、分布式锁可能导致超发。余额并发扣款检查余额和扣款不是原子操作。用户同时发起两笔消费两笔请求都检查到余额充足然后都执行了扣款导致余额扣成负数。测试方法使用Burp Suite的Turbo Intruder或Python多线程脚本同时发送数十个相同的关键请求。流程步骤跳过业务流程被设计成必须按顺序完成A、B、C步骤。密码重置流程为1.输入账号 - 2.验证身份短信/邮箱验证码- 3.设置新密码。攻击者能否直接访问步骤3的接口通过修改用户ID参数来重置他人密码实名认证1.提交身份证信息 - 2.人脸识别 - 3.认证成功。在步骤2人脸识别时抓包能否修改某些参数直接跳到步骤3关键点分析每个步骤的API接口尝试不按顺序调用或者直接调用最终步骤的接口。参数篡改实现越权通过修改请求中的ID类参数访问或操作不属于自己的数据。垂直越权普通用户修改请求中的roleadmin试图提升自身权限。水平越权用户A修改user_id123为user_id456从而查看、修改或删除用户B的订单、地址、个人信息等。关键点密切关注所有包含id、user_id、account、phone等标识用户或资源对象的参数。实操心得在测试时不要只盯着“改数字”。很多开发会使用枚举字符串作为状态比如status”pending”、status”approved”。尝试修改为status”approved”或者status”success”。同样注意JSON格式和表单格式的差异有时候一个参数放在URL里、Body里或者Header里都可能被后端不同模块处理存在校验不一致的可能。3. 实战狩猎如何系统性寻找逻辑绕过漏洞知道了漏洞长什么样下一步就是去“打猎”。漫无目的地测试效率极低我们需要一套系统性的方法。3.1 目标选取与信息收集不是所有系统都值得投入大量时间。优先选择以下目标业务流程复杂的企业应用OA系统、CRM系统、ERP系统、在线教育平台、电商后台。这些系统充满了各种审批、流转、状态管理。刚上线或经历重大改版的功能新功能往往测试不充分逻辑漏洞高发。带有“流程”、“审批”、“状态”、“订单”、“支付”、“认证”、“兑换”等关键词的功能模块。这些是逻辑漏洞的天然温床。信息收集阶段除了常规的目录扫描、子域名收集要特别关注API接口文档如果目标有Swagger、OpenAPI等接口文档那是金矿。仔细阅读每一个涉及状态变更的接口。前端JavaScript文件全局搜索status、state、step、check、verify等关键词可以快速定位前端定义的状态枚举值和关键API调用。使用爬虫如Burp的爬虫功能遍历整个应用重点关注不同权限角色如用户、管理员访问同一功能时参数和接口的差异。3.2 测试流程与工具使用我的标准测试流程可以概括为“观察-操作-拦截-修改-验证”五步循环。观察业务流程以一个正常用户的身份完整地走一遍目标流程。用笔或思维导图记录下一共分几步每一步的URL是什么页面元素按钮、提示有何变化哪些信息是前端展示的如“审核中”哪些是后端返回的正常操作并抓包使用Burp Suite作为代理开启拦截。再次操作流程确保Burp捕获到从第一步到最后一步的所有HTTP/HTTPS请求。特别关注POST、PUT等非幂等的修改请求。关键请求分析在Burp的Proxy - HTTP history中筛选出可能改变业务状态的请求。查看其请求参数。你需要像侦探一样思考这个参数如status0代表什么012分别对应什么状态这个参数是用户可控的吗它是下拉框选的还是前端写死的修改这个参数业务结果会有什么不同除了主参数有没有其他隐藏参数如is_checked,is_verified篡改与重放这是核心步骤。在Burp的Proxy - Intercept或Repeater模块中修改你怀疑的参数。数字/字符串枚举如果status0尝试改为1, 2, 3, 99, -1或”approved”,”success”,”true”。布尔值翻转如果need_audittrue尝试改为false。ID篡改将user_id改为其他用户的ID。步骤跳过尝试直接访问流程最后一步的API并携带必要的参数。删除参数有时删除某个校验参数如token、code反而能绕过。验证结果发送修改后的请求然后回到浏览器界面查看业务状态是否发生了非预期的改变。是否跳过了某个步骤是否看到了不该看的数据是否完成了本不能完成的操作工具链推荐主力代理Burp Suite Professional。它的Repeater重放、Intruder爆破/模糊测试、Comparer对比响应是逻辑测试的神器。社区版也足够完成大部分测试。浏览器插件EditThisCookie或浏览器开发者工具的Application面板用于快速修改Cookie、LocalStorage测试会话状态相关的逻辑。辅助脚本对于条件竞争测试可以用Python的threading或asyncio库快速编写并发请求脚本。笔记工具Obsidian或Typora。好记性不如烂笔头详细记录每一个测试用例、请求和响应这对后续编写报告至关重要。注意事项在测试修改状态参数时务必注意请求的“幂等性”。例如一个将订单状态从“待支付”改为“已支付”的接口如果重复调用是否会导致重复支付测试时要考虑这种业务副作用避免对目标业务造成实际损害。最好在测试账号或测试环境中进行。4. 漏洞复现案例详解从发现到利用光说不练假把式。我们用一个高度模拟真实场景但经过脱敏的案例来完整走一遍漏洞挖掘流程。假设目标是一个“企业内部活动报名系统”。4.1 案例背景与正常流程系统有一个功能员工可以报名参加公司培训报名后需要直属上级审批。员工登录进入培训报名页面选择课程点击“提交报名”。页面显示“您的报名已提交等待经理审批”。经理登录后台可以看到待审批列表点击“通过”或“拒绝”。员工页面状态相应变更为“已通过”或“已拒绝”。正常请求抓包分析 员工提交报名时Burp抓到如下请求POST /api/training/apply HTTP/1.1 Host: internal.company.com Content-Type: application/json Authorization: Bearer eyJhbGciOiJIUz... { training_id: T2024001, applicant_id: EMP10001, apply_time: 2024-05-20 10:00:00, status: submitted, // 前端固定传“submitted” remark: 申请参加本次培训 }响应为{ code: 200, message: 报名成功等待审批, data: { apply_id: APP202405200001, status: pending_approval // 后端返回的实际状态是“待审批” } }经理审批通过时抓包POST /api/training/approve HTTP/1.1 Host: internal.company.com Content-Type: application/json Authorization: Bearer eyJhbGciOiJIUz... (经理的Token) { apply_id: APP202405200001, action: approve, // 动作approve 或 reject comment: 同意 }4.2 漏洞挖掘与利用过程第一步寻找状态控制点对比员工和经理的请求我发现员工提交的请求里有一个status: “submitted”参数。经理审批是一个独立的接口 (/api/training/approve)传的是action。 一个猜想浮现员工提交接口的status参数后端是否真的在用还是说它只是前端的一个“摆设”真正的状态是由经理审批接口来改变的第二步试探性测试我将员工提交的请求发送到 Burp Repeater尝试修改status参数修改为”approved”重放。响应变成了{ code: 200, message: 操作成功, data: { apply_id: APP202405200001, status: approved // 状态直接变成了“已通过” } }刷新员工前端页面果然报名状态显示为“已通过”并且收到了系统通知“您的报名已通过审批”。漏洞原理确认后端在处理/api/training/apply接口时完全信任了前端传来的status参数并没有校验该参数是否与业务流程匹配即员工只能提交“submitted”状态。同时后端也没有校验执行“通过”操作的用户身份和权限。这导致了两个问题1. 状态参数可控2. 权限校验缺失。两者结合构成了一个完整的业务逻辑绕过漏洞。第三步漏洞影响扩大化思考高阶技巧一个优秀的白帽子不能只满足于“发现漏洞”还要评估其“最大危害”。这个漏洞还能怎么利用批量自动化绕过写一个脚本自动遍历所有可报名的培训课程 (training_id)并直接以status: “approved”提交瞬间完成所有课程的“自动报名并通过”。为他人报名并绕过审批修改请求中的applicant_id为其他同事的IDstatus设为”approved”即可在未经他人同意和经理审批的情况下替他人报名并强制通过。探测其他状态值用 Burp Intruder 对status参数进行模糊测试尝试”rejected”,”cancelled”,”completed”,”paid”等看是否能触发其他未预期的状态。4.3 漏洞修复方案逆向分析作为攻击方我们找到了漏洞作为防守方或给厂商提建议我们需要知道怎么修。这个案例的修复核心在于“状态机”和“权限校验”的服务器端强制实施。移除客户端可控的状态参数/api/training/apply接口不应接收status参数。提交申请时状态应由后端根据业务逻辑自动设置为初始状态如”pending_approval”。实现服务器端状态机在业务逻辑层明确定义状态流转规则。例如初始状态pending_approval合法流转1pending_approval-approved(仅可由rolemanager的用户执行)合法流转2pending_approval-rejected(仅可由rolemanager的用户执行)合法流转3pending_approval-cancelled(仅可由申请人自己执行)任何不符合上述规则的流转尝试都应被后端坚决拒绝并记录日志。关键操作增加权限校验在改变业务状态的接口如本案例中任何能修改training_application表status字段的地方前必须插入权限校验中间件。检查当前用户是否有权执行此操作是否是对应资源的负责人或管理员。实操心得在测试时多思考“这个功能的设计初衷是什么”。比如审批功能初衷是让有权限的人经理做决定。那么任何让“非经理”用户能直接影响审批结果的路径都可能是漏洞。这种“业务意图”与“实际实现”之间的差距就是逻辑漏洞滋生的土壤。5. SRC漏洞报告撰写指南与模板挖到洞只是成功了一半一份清晰、专业、令人信服的漏洞报告是你能获得认可和奖励的关键。很多新手挖到了洞却因为报告写得含糊不清、证据不足而被忽略或定为低危。5.1 报告核心要素一份高水平的SRC报告通常包括以下部分我称之为“八股文”但非常有效漏洞标题一句话概括漏洞本质。要包含“哪里”有“什么”漏洞导致“什么”后果。差“发现一个漏洞”优“XX公司活动报名系统业务逻辑绕过漏洞允许普通员工篡改状态直接通过审批”漏洞等级根据漏洞的CVSS标准或SRC平台自定标准给出建议等级高危、中危、低危。逻辑绕过通常涉及权限或流程突破定高危的情况很多。漏洞描述这是报告的灵魂。用简洁的语言描述漏洞的位置、成因和危害。遵循“在什么情况下通过什么操作因为什么缺陷导致了什么后果”的逻辑链。影响范围说明漏洞影响哪些业务、哪些用户、哪些数据。量化影响如影响所有用户、所有订单流程更能体现严重性。复现步骤像食谱一样提供一步步可操作的复现方法。确保审核人员能按照你的步骤100%复现漏洞。这是报告可信度的基石。证明材料截图截图截图重要的事情说三遍。关键请求和响应需脱敏、漏洞利用前后的界面对比最好配上简短的文字说明。修复建议给出具体、可操作的修复方案。展现你的专业性不要只说“加强校验”要说明“在哪个接口、校验什么、怎么校验”。时间线可选但建议记录你发现漏洞、报告漏洞的时间便于厂商跟进。5.2 高质量报告模板可直接套用以下是我根据多年经验总结的模板你只需要替换[]中的内容。漏洞标题[厂商名称] [系统/模块名称] 存在业务逻辑绕过漏洞导致[具体危害]漏洞等级高危漏洞描述 在[具体URL或接口地址如https://xxx.com/api/v1/apply]接口中由于后端服务器未能对客户端提交的业务状态参数[参数名如status]进行有效的合法性校验和权限控制存在业务逻辑设计缺陷。 攻击者普通用户身份可通过拦截修改HTTP请求将[参数名]的值从[正常值如0待审核]篡改为[异常值如1已通过]从而直接绕过[被绕过的环节如管理员审核]流程使得业务申请未经授权即生效。 该漏洞破坏了[业务名称如培训报名]流程的完整性与安全性恶意用户可借此批量提交非法申请、伪造审批记录对业务数据的真实性与管理秩序造成严重威胁。影响范围影响所有使用[相关功能]的用户。导致[具体业务流程如报名审核]机制完全失效。可能引发数据混乱、违规业务生效等业务风险。复现步骤使用普通用户账号[账号信息如testuser]登录[系统名称]。进入[功能页面如培训报名页面]填写必要信息点击提交。同时使用Burp Suite等代理工具抓取该请求。捕获到的请求示例如下已脱敏POST /api/training/apply HTTP/1.1 Host: internal.company.com ... {training_id:T001, status:submitted}将请求中的status参数值由submitted修改为approved。转发修改后的请求。服务器返回成功响应状态直接变为approved。返回Web界面刷新可见报名状态已变为“已通过”无需经理审批。证明材料 此处用文字描述截图内容实际报告附截图图1正常提交报名时抓取的请求包显示status: “submitted”。图2在Burp Repeater中修改参数为status: “approved”并发送。图3服务器返回成功响应data.status为”approved”。图4Web前端页面显示报名状态为“已通过”。修复建议后端强制校验在服务端业务逻辑层移除对客户端传入的status等关键状态参数的依赖。业务对象的状态变迁应由服务端根据明确规则驱动。实现状态机为[业务实体如培训申请]设计明确的状态机。定义唯一的状态集和合法的状态转换路径例如pending - approved只能由审批接口触发。任何非法状态转换请求都应被拒绝。增加权限校验在状态变更的关键接口如审批通过前增加严格的权限校验中间件确保只有具备相应角色如manager的用户才能执行对应操作。补充操作日志对所有涉及状态变更的操作进行详细日志记录包括操作人、时间、原状态、新状态等便于事后审计与溯源。5.3 报告撰写避坑指南避免模糊表述不要说“有个地方可能有问题”要精确到URL、参数、值。证据链完整请求、响应、界面变化三者截图要能串联起来形成闭环。脱敏脱敏脱敏截图和代码中务必抹去真实的敏感信息如Token、真实ID、内部域名等。可以用马赛克或替换为示例值。语气专业客观报告是给厂商技术人员看的用词要专业、客观指出问题而非指责。多用“存在设计缺陷”、“建议加强校验”这类表述。一次一洞一个报告只描述一个明确的漏洞。不要把多个不同的问题混在一个报告里。6. 进阶技巧与防御视角当你掌握了基本的逻辑漏洞挖掘方法后可以尝试一些更深入的技巧同时从防御者角度思考能让你挖得更准。6.1 进阶挖掘技巧多步骤流程的“跳步”测试对于复杂的多步流程如注册-实名认证-绑卡-交易不要只测试相邻步骤。尝试从第一步直接跳到第三步或者从最后一步倒推。查看每一步的接口是否对前置条件如session里存的标志位、数据库里的状态字段做了严格校验。参数污染与HTTP方法滥用参数污染同时提交两个同名的参数如status0status1看后端如何处理。不同的Web框架如PHP的$_GET/$_POSTSpring的RequestParam可能有不同的解析顺序可能导致非预期的值被采用。HTTP方法滥用一个查询列表的GET /api/orders接口尝试改成POST、PUT、DELETE方法看是否会触发非预期的操作。或者一个本应使用JSON Body的POST接口尝试将参数放在URL查询字符串中提交。时间窗口与竞态条件关注那些涉及“库存”、“余额”、“限量”的操作。使用工具并发发送数十上百个请求观察是否会出现超卖、超额兑换、余额为负等情况。业务规则逆向推导仔细阅读业务规则说明。例如“新用户首单立减10元”。那么如何定义“新用户”是看注册时间还是看是否有过订单尝试注册后不下单修改资料里的注册时间或者直接调用“标记为首单”的接口看能否重复享受优惠。6.2 从开发视角构建防御理解如何防御能帮你更好地理解漏洞的根源。在和开发人员沟通修复方案时也能更有说服力。设计阶段引入威胁建模在业务功能设计初期就进行简单的威胁建模。问自己这个流程的核心状态是什么谁有权改变它改变的条件是什么哪些数据来自不可信的客户端遵循“服务器端权威”原则永远不要相信来自客户端的任何关于业务状态、用户权限、流程进度的信息。这些都必须由服务器端根据会话标识如User ID和持久化存储的数据重新计算和校验。实现状态机引擎对于复杂业务流程建议在后台引入状态机库如Spring StateMachine。将状态和转移规则以配置或代码的形式明确定义。任何状态变更请求都必须通过状态机引擎的检查确保转移合法。关键操作幂等与加锁对于支付、扣减库存等关键操作要保证接口的幂等性多次请求结果相同并对涉及的核心资源如用户余额行、商品库存行进行加锁如数据库悲观锁、分布式锁防止并发操作导致的数据不一致。全面的日志与监控对所有业务关键操作尤其是状态变更操作记录详细的操作日志谁、在什么时候、通过什么接口、把什么从什么状态改成了什么状态。并设置监控告警对异常的状态跳变如大量“待审核”瞬间变“已通过”进行实时告警。挖洞的过程本质上是一个不断学习和理解系统的过程。业务逻辑漏洞的魅力在于它没有固定的“招式”需要你真正沉浸到业务场景中去思考。每一次成功的挖掘不仅是一次技术的胜利更是一次对复杂系统理解能力的提升。保持好奇心多问“如果……会怎样”你的漏洞挖掘之路就会越走越宽。

相关新闻