越权漏洞实战挖掘:从原理到案例,掌握水平与垂直越权防御

📅 2026/6/25 21:09:36
越权漏洞实战挖掘:从原理到案例,掌握水平与垂直越权防御
1. 项目概述从“越权”到“精通”的实战之路在安全测试和渗透测试的日常工作中越权漏洞Broken Access Control绝对是一个高频且极具价值的“猎物”。它不像SQL注入那样需要复杂的语法构造也不像XSS那样依赖精巧的载荷很多时候它更像是一个逻辑上的“后门”一旦被发现往往能直通核心数据或功能。这个项目标题——“几个常见的越权漏洞挖掘案例从零基础到精通收藏这篇就够了”——精准地戳中了安全从业者尤其是初学者的痛点渴望通过具体、可复现的案例快速掌握一种漏洞的挖掘思路和实战技巧。我自己在带新人或者做内部培训时也深有体会。很多朋友看了很多理论知道越权分为水平越权和垂直越权但一到实际环境面对一个真实的Web应用却不知从何下手。这篇文章我就想抛开那些教科书式的定义直接带你钻进几个我亲手挖过或者复现过的经典案例里。我们会从最基础的“改个ID”开始一步步深入到需要结合业务逻辑、参数污染甚至时间竞争的复杂场景。我的目标很简单让你读完这篇文章后不仅能看懂这些案例更能建立起一套属于自己的、可迁移的越权漏洞挖掘思维模型。无论你是刚入门的安全爱好者还是想查漏补缺的开发者这篇文章里总结的“套路”和踩过的“坑”都值得你仔细琢磨。2. 越权漏洞核心原理与分类精讲在深入案例之前我们必须把地基打牢。越权漏洞的本质是应用程序在对用户访问某个资源或执行某个操作进行授权验证时出现了逻辑缺陷导致用户能够执行其本不被允许的操作。这个“验证”可能发生在后端代码的权限判断语句里也可能隐藏在前端参数、Cookie、甚至是请求的顺序中。2.1 水平越权同级别用户的“串门”事故水平越权Horizontal Privilege Escalation是最常见的一种。它指的是攻击者能够访问或操作与其拥有相同权限级别的其他用户的资源。举个例子用户A和用户B都是普通会员理论上A只能看自己的订单B只能看自己的订单。但如果存在水平越权A通过某种方式比如修改请求中的用户ID参数就能看到B的订单详情。核心攻击点任何用于标识用户唯一身份或资源的参数。最常见的就是数字ID如user_id123、order_id456。此外用户名、邮箱、手机号甚至是文件路径如/download?fileuserA_contract.pdf都可能成为目标。后端漏洞的典型场景后端代码接收了前端传来的用户标识如从JWT token或session中解析出当前用户是A但在执行“查询用户B的订单”这个操作前没有再次校验“当前用户A是否有权查询B的订单”。代码可能直接执行了SELECT * FROM orders WHERE order_id ${input_order_id}而完全忽略了user_id的关联校验。这就是一个赤裸裸的水平越权。2.2 垂直越权普通用户的“僭越”之梦垂直越权Vertical Privilege Escalation的危害性通常更大。它指的是低权限用户能够执行高权限用户才能执行的操作。例如一个普通论坛用户通过某种方式能够访问到管理员的后台功能页面或者调用只有管理员才能使用的API接口比如删除其他用户的帖子、修改系统配置。核心攻击点功能入口、权限标识参数、角色参数。比如一个“添加管理员”的接口正常情况下前端根本不会对普通用户展示这个功能的按钮。但攻击者可以通过爬虫、目录扫描或者分析JS代码直接找到这个接口的路径/admin/addUser。如果后端仅仅依靠“用户是否登录”来判断而没有校验“用户角色是否为管理员”那么垂直越权就发生了。一个常见的混淆点很多人认为垂直越权一定要看到管理员界面。其实不然。有时一个普通的“修改个人资料”功能如果后端没有对可修改的字段做严格限制攻击者通过修改请求参数给自己添加一个roleadmin的字段并且后端真的将这个值更新到了数据库这也是一次成功的垂直越权攻击权限提升。2.3 不安全的直接对象引用与业务逻辑越权OWASP TOP 10 中常提到的“不安全的直接对象引用”IDOR是导致越权的主要原因之一它更多是水平越权的具体实现方式。而“业务逻辑越权”则是一个更宽泛的概念它可能不依赖于修改某个ID而是利用业务流程上的缺陷。例如在一个“申诉重置密码”流程中用户输入邮箱系统发送一封含有临时token的邮件。用户点击邮件链接进入重置密码页面URL中带有token。漏洞在于进入重置页面后后端只验证token有效但未将token与待重置的账号邮箱进行二次绑定。攻击者可以先用自己的邮箱获取一个合法token然后在重置页面将请求中的“新密码”和“确认密码”参数保持不变但偷偷修改“邮箱”参数为受害者的邮箱。如果后端仅凭token就允许重置那么攻击者就利用业务流程漏洞越权重置了他人密码。这类漏洞的挖掘需要测试者对应用的业务流程有深入的理解思考“每一步的验证是否充分”、“状态是否可被恶意绕过”。注意越权漏洞的修复核心原则是“服务端强制授权”。永远不要信任前端传来的任何关于权限和身份的信息包括隐藏域、Cookie、Header。每次处理敏感操作或请求敏感数据时后端都必须根据当前已认证的用户会话Session/JWT payload去数据库或缓存中重新查询并确认其是否有权进行此操作。3. 案例一骑士CMS靶场 - 经典水平越权漏洞复现与分析骑士CMSKnight CMS是一个经典的PHP内容管理系统其历史版本中存在的水平越权漏洞是安全入门练手的绝佳材料。我们通过这个案例来具体拆解一次完整的漏洞挖掘过程。3.1 环境搭建与目标定位首先你需要一个测试环境。可以在虚拟机中安装PHPStudy等集成环境然后下载骑士CMS的历史漏洞版本例如某个已知存在漏洞的旧版本。安装完成后我们重点关注“会员中心”功能。通常用户登录后可以查看和编辑自己的个人信息。我们的攻击目标是用户A越权查看或修改用户B的个人资料。常见的入口是“修改资料”页面其URL可能类似于/member/index.php?mmembercindexaedit。3.2 漏洞挖掘过程参数操纵与响应分析正常操作观察用两个测试账号userA和userB分别登录。登录userA后进入资料修改页面。使用Burp Suite或浏览器开发者工具抓包观察提交修改资料的HTTP请求通常是POST请求。寻找关键参数在请求中我们很可能发现一个名为userid、id或uid的参数其值是一个数字比如userid5假设这是userA的用户ID。同时表单中还会有username、email等字段。发起越权测试保持Burp Suite的拦截功能开启或使用Repeater模块在userA的会话下将POST请求中的userid参数值修改为userB的ID比如userid6而其他字段如username修改为一个新的值如userA_hacked。然后转发这个被篡改的请求。结果验证场景一查看越权如果请求是获取资料GET修改userid后响应返回了userB的资料信息则存在信息查看水平越权。场景二修改越权如果请求是更新资料POST修改userid和username后服务器返回“更新成功”。随后我们退出userA登录userB发现userB的用户名果然被改成了userA_hacked。这就证实了存在数据修改水平越权危害极大。3.3 漏洞代码根源分析问题出在后端PHP处理代码上。我们来看一段高度简化的漏洞代码模拟// member/edit.php (漏洞版本) $userid $_POST[userid]; // 直接从用户输入获取目标用户ID $new_username $_POST[username]; // 假设当前登录用户的ID从session中获取 $current_uid $_SESSION[user_id]; // 致命的缺失这里没有检查 $userid 是否等于 $current_uid // 正确的逻辑应该加上if ($userid ! $current_uid) { die(无权操作); } $sql UPDATE user_table SET username$new_username WHERE id$userid; $result mysql_query($sql); if ($result) { echo 资料更新成功; }这段代码盲目信任了$_POST[userid]没有将其与当前登录用户的身份$_SESSION[user_id]进行比对。这就是“不安全的直接对象引用”的典型例子。3.4 挖掘技巧与注意事项不要只测数字ID除了userid还要测试所有可能标识对象的参数如orderid、messageid、fileid甚至是username、email这种非数字参数。尝试将usernameuserA改为usernameadmin。注意POST和GET越权可能发生在任何HTTP方法中。对于查看类操作多测试GET请求的参数对于更新、删除操作多测试POST/PUT/DELETE请求的参数。使用工具提高效率Burp Suite的 Intruder 模块可以用于自动化爆破ID范围。你可以设置userid参数为 payload快速遍历一个数字区间如1-100观察哪些ID返回了数据状态码200且有内容哪些返回了错误403或空数据。留意响应差异有时服务器不会直接返回目标数据但响应长度、状态码或错误信息会因ID是否有效而不同。通过对比这些差异可以判断ID是否有效从而间接发现越权信息泄露。实操心得在测试水平越权时我习惯先创建一个“靶子”。比如先用userB账号创建一个便签、订单或上传一个文件记下其唯一ID如note_id100。然后在userA的会话中直接尝试访问/note/view?id100。这种针对已知目标资源的测试成功率往往比盲目爆破更高。4. 案例二基于功能路径的垂直越权探测垂直越权的挖掘往往需要一点“好奇心”和“地图”。我们不再满足于修改参数而是要去寻找那些本不该出现在我们视线里的“隐藏房间”。4.1 功能路径的发现与枚举爬虫与目录扫描使用工具如gobuster、dirsearch或 Burp Suite 的Content Discovery功能对目标网站进行目录和文件扫描。寻找像/admin/、/manage/、/backend/、/console/这样的敏感目录。关键词列表可以加入admin、manage、config、upload、dashboard、api等。前端代码分析有些管理功能的入口在前端代码JavaScript中是存在的只是通过权限判断隐藏了UI。在浏览器开发者工具的“源代码”Sources或“网络”Network面板中仔细搜索admin、role、delete、editAll等关键词可能会发现被注释掉或动态加载的API接口路径。参考错误信息与机器人协议有时访问一个不存在的管理页面会暴露真实路径。也可以查看robots.txt文件有些开发者会不小心在这里列出管理后台的路径。4.2 漏洞利用绕过前端渲染与接口调用假设我们通过扫描发现了/admin/userList.php这个路径它显然是一个列出所有用户的管理员功能。直接访问测试在普通用户登录的状态下直接在浏览器地址栏输入https://target.com/admin/userList.php并访问。观察响应情况A直接访问成功页面正常加载显示了所有用户列表。这是最严重的垂直越权说明该页面零权限校验。情况B跳转或提示页面可能跳转到登录页或显示“权限不足”。这并不绝对安全需要进一步测试。深入测试情况B检查Cookie/Session管理员和普通用户的会话标识可能有区别。尝试将普通用户的Cookie中的role或level字段如果存在且可被篡改修改为admin或1。测试API接口/admin/userList.php可能只是一个前端页面数据通过AJAX从后端API获取例如/api/admin/getUsers。直接尝试调用这个API接口可能绕过前端页面的权限检查。请求方法绕过有时权限检查只针对GET方法。尝试用POST、PUT等方法访问同一个路径可能会有意外收获。4.3 一个真实的逻辑缺陷案例某次审计中我发现一个系统的权限判断逻辑如下# 伪代码 if request.path.startswith(/admin/): if not current_user.is_authenticated: return redirect(/login) if not current_user.role admin: return render_template(403.html) # 返回无权限页面 # 执行管理员操作看起来没问题但系统还有一个“超级管理员”功能模块路径是/superadmin/。开发者在检查时只写了startswith(/admin/)而遗漏了/superadmin/路径。导致任何登录用户无需admin角色都能直接访问/superadmin/下的所有功能造成了严重的垂直越权。挖掘技巧在目录扫描时思维要发散。不要只扫常见目录要结合应用特点。比如一个教育系统可以尝试/teacher/、/headmaster/一个电商系统可以尝试/merchant/、/operator/。5. 案例三结合业务逻辑的复杂越权漏洞挖掘越权漏洞的“高级玩法”往往与具体的业务逻辑深度绑定。这类漏洞的挖掘要求测试者不仅是一个“黑客”更要是一个“业务专家”。我们来看两个需要动脑子的例子。5.1 案例A密码重置流程中的“Token与邮箱解绑”这是一个非常经典的业务逻辑越权案例我们详细拆解。正常流程用户在忘记密码页面输入邮箱victimexample.com。系统向该邮箱发送一封邮件内含一个一次性重置链接如https://target.com/reset?tokenabc123。用户点击链接进入重置页面。页面表单里可能有一个隐藏的email字段值为victimexample.com或者后端从token对应的缓存记录中读取邮箱。用户输入新密码提交。后端验证token有效且未过期然后将victimexample.com的密码更新。漏洞流程攻击者访问忘记密码页面输入自己的邮箱attackerexample.com。攻击者收到重置链接https://target.com/reset?tokendef456。攻击者点击链接进入重置页面。此时攻击者打开浏览器开发者工具或使用Burp Suite拦截提交新密码的POST请求。攻击者发现POST请求的参数中除了new_password和confirm_password还有一个email参数其值当前是attackerexample.com。关键步骤攻击者将email参数的值修改为victimexample.com而token参数保持不变tokendef456然后提交请求。漏洞触发后端服务器收到请求后执行了如下有缺陷的逻辑验证tokendef456有效因为它确实是系统刚发给攻击者的合法token。但后端没有检查这个token是否与提交的email参数绑定。它直接使用请求中的email参数victimexample.com作为要重置密码的账户。于是系统将受害者victimexample.com的密码重置为攻击者设定的新密码。漏洞根源密码重置的token必须与最初申请重置的邮箱账号在服务器端进行强绑定。验证时应该用token去查对应的邮箱而不是接受客户端传来的邮箱。正确的逻辑是reset_email cache.get(token); if reset_email ! submitted_email: error。5.2 案例B订单流程中的“平行权限”滥用在某电商平台用户下单后可以申请“仅退款”不退货。流程如下用户A对订单1001申请仅退款。商家审核拒绝。用户A可以对此拒绝决定进行“申诉”提交补充材料。漏洞场景用户B也有一个被拒绝退款的订单1002。用户B在提交申诉时抓包发现请求中包含参数order_id1002和appeal_reason...。用户B将order_id修改为1001用户A的订单然后提交。后端检查发现订单1001的退款申请确实被拒绝了状态符合并且当前登录用户B“有订单”但没检查是不是这个订单于是允许了申诉操作。结果用户B成功以自己身份为用户A的订单发起了申诉可能干扰平台判责或泄露申诉信息。漏洞根源在申诉这个子流程中后端只校验了“订单是否处于可申诉状态”但没有严格校验“发起申诉的用户是否是该订单的所属用户”。这属于业务流程中权限校验的缺失。挖掘这类漏洞的心得绘制业务流程图对于核心业务登录注册、支付、订单、审核、提现等亲手画一画它的正常流程。寻找状态转换点关注那些能改变业务状态的环节如“提交审核”、“确认收货”、“发起退款”、“撤销申请”。这些环节往往是权限校验的关键点。问自己两个问题在这个环节系统如何知道“你是谁”系统如何确定“你有权操作这个对象”如果这两个问题的答案依赖于前端参数、可预测的ID或是不完整的校验那么漏洞就可能存在。6. 越权漏洞的自动化辅助与高级挖掘技巧手动测试是基础但效率和深度离不开工具的辅助和一些进阶思路。6.1 工具链配置与使用Burp Suite - Intruder爆破与模糊测试用途自动化修改参数并发送大量请求用于发现有效的ID范围、遍历目录、测试权限参数。配置示例针对id参数设置Payload类型为“Numbers”从1到1000步长为1。然后根据响应长度、状态码或关键词如“订单号”、“用户名”来筛选可能成功的请求。Cluster bomb攻击类型当需要同时测试两个相关参数时如user_id和order_id可以设置两个Payload集进行组合测试。Burp Suite - Scanner被动扫描在浏览网站过程中Burp会自动分析流量有时能标记出潜在的IDOR不安全的直接对象引用点。但这只是提示需要手动验证。自定义脚本Python对于复杂的业务逻辑测试或需要处理会话、Token的场景编写Python脚本会更灵活。示例任务自动完成“获取重置Token - 篡改邮箱 - 提交重置”的全流程测试。import requests # 1. 使用攻击者邮箱获取token s requests.Session() resp1 s.post(https://target.com/forgot, data{email: attackermail.com}) # (假设通过邮件或API获取token这里简化) token abc123 # 2. 使用该token但尝试重置受害者邮箱 resp2 s.post(https://target.com/reset, data{token: token, email: victimmail.com, # 篡改的参数 new_password: Hacked123!}) if success in resp2.text: print([!] 可能存在密码重置越权漏洞)6.2 高级技巧参数污染、时间竞争与间接引用HTTP参数污染当后端同时接收来自多个位置的同名参数时如URL查询参数和POST body中都有user_id处理逻辑可能出现混乱。尝试在GET参数和POST参数中提供不同的id值观察后端以哪个为准这有可能绕过某些校验。时间竞争条件在某些并发操作中权限检查和使用资源不是原子操作。例如用户A发起“转账给B”的请求后端先检查A的余额是否充足通过但在扣款前有一瞬间延迟。在同一瞬间用户A急速发起另一个“转账给C”的请求。如果后端没有做好并发锁两次检查可能都通过导致A用一笔钱完成了两笔转账。这本质上是越权使用了“未来的余额”。间接对象引用有时前端显示的不是真正的数据库ID而是一个经过编码或映射的“引用ID”。你需要尝试找出其编码/解码规律。例如订单号显示为ORD-ABC123在请求中却是id789。你需要测试789是否对应其他用户的订单。或者尝试对ORD-ABC123进行简单的变换如ORD-ABC124、ORD-ABD123看是否能访问到其他数据。6.3 漏洞挖掘思维框架我将越权测试总结为一个四步循环的思维框架标识定位找到所有标识用户、资源、操作对象的参数。不仅是数字ID还包括UUID、用户名、邮箱、文件名、哈希值等。请求操纵系统地修改这些参数。包括递增/递减、替换为同权限其他用户/资源标识、替换为高权限标识如admin、置空、删除参数、重复参数、使用非法字符等。差异分析仔细观察每次请求的响应。对比状态码、响应长度、响应时间、返回数据内容、错误信息。任何差异都可能是突破口。逻辑推理基于差异推测后端校验逻辑。是完全没有校验是校验了但可以被绕过还是校验逻辑存在缺陷然后设计新的测试用例去验证你的推测。7. 常见问题排查与防御方案实录在挖掘和修复越权漏洞的过程中会遇到各种“坑”。这里记录一些典型问题和解决方案。7.1 漏洞挖掘中的常见“假阳性”与排查响应状态码都是200但内容不同修改ID后服务器可能返回了一个通用的错误页面或空数据模板状态码仍是200。不要只看状态码要对比响应体内容、长度。使用Burp的“Comparer”工具进行差异对比非常高效。依赖全局登录状态测试越权时务必确保你的每个测试请求都携带了正确的会话CookieSession Cookie或Token。有时在Burp Repeater中不小心清除了Cookie会导致请求被视为未登录而返回302跳转这容易被误判为“权限校验有效”。CSRF Token干扰很多表单提交带有CSRF Token。如果你在Repeater中重放一个旧请求Token可能已失效。需要先GET一次表单页面获取新的Token再构造POST请求。自动化测试时需要编写脚本处理这种动态Token。请求频率限制大量爆破ID可能会触发IP或账号的速率限制。需要调整工具的发包间隔或者使用代理池。7.2 开发者视角如何从根本上防御越权漏洞作为开发者必须在设计之初就树立“永不信任客户端”的原则。最小权限原则每个功能、每个API接口在代码层面明确定义其所需的最小权限。服务端强制校验所有涉及资源访问的操作必须在服务端进行“用户-资源”所有权或权限关联校验。正确代码示例Python Flask SQLAlchemyapp.route(/api/order/int:order_id, methods[GET]) login_required def get_order(order_id): current_user_id session.get(user_id) # 关键查询时关联当前用户ID order Order.query.filter_by(idorder_id, user_idcurrent_user_id).first() if not order: return jsonify({error: Order not found or access denied}), 404 return jsonify(order.to_dict())使用不可预测的标识符避免使用连续的数字ID作为资源标识。可以使用UUID、随机生成的字符串或者对数字ID进行加密签名如JWT并在服务端验证签名的有效性。统一的权限检查中间件/装饰器对于Web应用可以设计一个全局的权限检查中间件。对于API可以使用装饰器。将权限校验逻辑集中管理避免在每个函数里重复编写和遗漏。# 权限装饰器示例 def check_ownership(model_class, id_paramid): def decorator(func): wraps(func) def wrapper(*args, **kwargs): obj_id kwargs.get(id_param) current_user get_current_user() obj model_class.query.filter_by(idobj_id, user_idcurrent_user.id).first() if not obj: raise PermissionDeniedError() return func(*args, **kwargs) return wrapper return decorator app.route(/post/int:post_id/delete, methods[POST]) login_required check_ownership(Post) # 使用装饰器自动检查 def delete_post(post_id): # ... 删除逻辑到这里已经确认用户有权删除此post pass定期进行代码审计与渗透测试将越权检查作为代码审查和自动化安全测试SAST/DAST的必选项。定期邀请安全团队或使用第三方工具进行黑盒/白盒测试。7.3 对测试者的建议编写有效的漏洞报告当你发现一个越权漏洞后一份清晰、可复现的报告至关重要。标题明确直接点明漏洞类型和位置如“【高危】XX系统用户资料修改功能存在水平越权漏洞”。详细复现步骤测试账号信息可匿名化。具体的操作步骤点击哪里输入什么。关键的HTTP请求和响应用代码块展示脱敏敏感数据。证明漏洞存在的截图或视频。影响分析说明这个漏洞能导致什么后果如查看他人隐私、篡改他人数据、提升权限等。修复建议提供具体的代码修复方案参考上面的防御措施。这能极大提升你的专业度并帮助开发团队快速解决问题。越权漏洞的挖掘是一场与开发者逻辑思维的博弈。从简单的ID修改到复杂的业务逻辑绕过其核心始终在于理解“系统认为你是谁”和“系统允许你做什么”之间的校验是否严密。保持好奇心多问“如果...会怎样”并辅以系统的测试方法你就能在纷繁复杂的Web应用中找到那些不该存在的“权限后门”。