☰
从零开始挖逻辑漏洞:高校教务系统实战越权与支付绕过
2026/10/21 6:23:46 网站建设 项目流程

先泼一盆冷水:逻辑漏洞挖掘不是什么高深的黑客技术,它更像是“找茬”——别人写代码时脑子里少拧了一根弦,你顺着业务逻辑把那个“没想到”的岔路走通了。整个过程不需要你掌握栈溢出、不需要逆向二进制,甚至大多数场景下连SQL注入都轮不到。这篇就用我近期在某高校教务系统上的一次完整实战,把从选目标、捋业务、测思路到写报告的整个链路拆给你看,保证你有手就能跟着走一遍。

先说结论:那次挖掘前后花了大约两个下午,一共找到五个可确认的逻辑问题,其中两个能直接越权读取他人信息,一个能免费开通付费服务,两个属于低危的业务配置缺陷。整个过程没有使用任何扫描器,纯靠浏览器和抓包工具,这也是逻辑漏洞最迷人的地方——它拼的不是工具多先进,而是你对业务流程的理解够不够深。这篇文章适合完全零基础的新手,也适合那些工具流出身、想转手测思路的朋友。看完你会明白,为什么说“逻辑漏洞是安全圈性价比最高的入门方向”。

1. 逻辑漏洞的核心逻辑:先搞清楚它到底是什么

1.1 逻辑漏洞不是“bug”,是业务流程上的坑

安全圈常说的逻辑漏洞,指的是攻击者利用系统正常功能流程中的设计缺陷,让业务执行了开发人员意料之外的操作。它不是程序崩溃、不是内存越界,而是“流程设计本身就错了”。举个例子:你买东西付款,正常情况下是下单→付款→生成订单→发货。但如果这个系统允许你先下单、然后修改订单金额再付款呢?那你就用一分钱买到了原价商品——这就是典型的业务逻辑漏洞。

相比SQL注入、XSS这类技术型漏洞,逻辑漏洞有几个很明显的特征:

  • 不依赖特定技术栈:不管是Java、PHP、Python写的系统,只要业务逻辑有坑,原理都一样。
  • 不需要了解底层原理:不用会汇编,不用会看二进制,甚至不需要深入理解HTTP协议,知道GET和POST的区别就够了。
  • 自动化工具很难发现:扫描器只能扫出“通用型漏洞”,而逻辑漏洞是每个业务独有的,必须靠人肉去测。
  • 危害往往很直接:越权看别人订单、篡改金额、绕过付费——每一步都直接影响核心业务。

一句话总结:技术型漏洞是“程序写错了”,逻辑漏洞是“流程设计错了”。前者需要修代码,后者可能需要改产品设计,所以很多企业对这类漏洞更头疼。

1.2 五类最常见的逻辑漏洞场景

虽然逻辑漏洞千奇百怪,但绝大多数都能归到下面五个大类里。记住这五类,你就有了基本的“找茬框架”。

第一类是越权漏洞,又分水平越权和垂直越权。水平越权就是你只能看自己的订单,但把订单号一换,能看到别人的订单;垂直越权是你是普通学生,但把某个参数一改,能执行老师甚至管理员的操作。这类漏洞在电商、教务、OA系统里极其常见,核心原因是后端没有校验“当前登录用户”和“操作对象”的归属关系。

第二类是验证码与身份认证绕过。比如短信验证码不失效、验证码只在前端校验、修改响应包里的某个字段就能跳过验证步骤。这类漏洞多见于登录、密码重置、注册流程里,攻击面大,利用起来也最无脑。

第三类是支付与订单逻辑缺陷。比如下单时篡改金额字段、折扣计算负数、使用优惠券后不校验适用范围、支付回调没有验签。这类漏洞直接打钱,是黑产最爱的目标。

第四类是密码找回与注册逻辑问题。比如密码重置时可以使用任意手机号、修改响应包跳过“校验身份”步骤、注册时通过参数覆盖变成管理员。这类漏洞在各类Web系统中出现的频率极高。

第五类是业务配额与状态不一致。比如领取邀请码后不标记已领取、投票功能可以无限投、签到可以回拨时间反复签、文件上传后不校验下载权限等等。这类问题看起来“小”,但往往能产生连锁危害。

记住这五类框架,你在测一个系统时就不会毫无头绪。接下来我用自己的实战案例,演示一遍完整的挖掘流程。

2. 动手前的准备工作:选目标、搭环境、配工具

2.1 合法授权比技术本身重要一万倍

正式动手之前,我必须先把这条红线画清楚:任何漏洞挖掘行为,都必须在你有明确授权的范围内进行。你可以测自己公司的系统、可以测合作伙伴授权给你的系统、可以在本地搭靶场模拟,但绝对不要随便拿别人的网站练手。我这次的案例,是某高校委托正规安全团队做的授权测试,整个流程有合同、有范围界定、有应急联系人——这些不是走形式,而是保护测试者自己的关键前提。

在授权测试场景下,一般像“某高校教务系统”这种项目,最常见的目标是一个IP段内的Web应用群。你需要明确以下范围:

  • 允许测试的域名或IP范围
  • 允许测试的功能模块(比如只测选课系统和支付系统,不许动人事系统)
  • 测试时间段
  • 测试深度限制(能不能用扫描器、能不能进行DoS测试)

这些信息在你开始测试前,一定要落到纸面上并和甲方确认。

2.2 本地靶场:零基础小白的练手环境

如果你是零基础,我强烈建议你第一站不要直接上手真实系统,先在本地靶场把感觉找出来。推荐两个:

  • DVWA(Damn Vulnerable Web Application):业内最经典的练习靶场,自带多种漏洞场景,包括逻辑相关的模块,配合XAMPP或LAMP环境一条命令就能启动。
  • 自建模拟环境:如果你有编程基础,甚至可以自己写一个1分钟能跑起来的PHP+MySQL应用,故意埋几个逻辑漏洞进去(比如不校验订单归属、验证码不失效)。自己埋的坑,自己挖起来印象最深。

用本地靶场的好处有两个:第一是放心大胆随便测,不用怕把数据搞坏;第二是你能用源码对照着理解“为什么这里是漏洞”,这是任何真实系统都给不了你的学习条件。

我当时在正式测试某高校系统之前,就在本地靶场花了整整一周,把验证码绕过、越权、订单篡改这三类场景反复练了不下二十遍。等到看真实系统时,基本上一眼就能判断出“这个接口有没有校验”。

2.3 工具选型:真不需要多,顺手就行

逻辑漏洞测试对工具的要求低得惊人。我整个测试流程中,常态使用的也就这三样:

  • 浏览器:首选Chrome或Firefox,配合DevTools做基础抓包、改包操作。千万别小看浏览器自带的开发者工具,它能完成修改请求参数、重放请求、查看响应这些绝大多数操作。
  • Burp Suite Community版:当你需要更精细地拦截请求做修改时,Burp是必备的。我建议新手直接用社区版,功能足够支撑逻辑漏洞测试;如果后面需要自动化拼接请求,再考虑Pro版。
  • HTTP请求工具:Postman或者直接curl都行。有些场景你需要快速构造一个登录后的请求,用工具比浏览器更效率。

其他的像SQLMap、Nmap这类扫描器,在这个场景下几乎不用。逻辑漏洞讲究的是“顺着业务走”,不是“拿工具往系统上怼”。而且现在很多靶标系统都配了WAF,你一扫描,对方安保人员马上就会打电话来问,反而坏事。

2.4 关键的准备工作:把业务流程画出来

这一步很多人会忽略,但我认为它直接决定了你挖洞的效率。拿到授权后的系统,先不要急着点功能,而是花半小时把主要业务流程画出来。

以教务系统为例,核心流程大概是:

登录(学生/教师/管理员)→ 查看课程 → 选课 → 提交 → 确认课表 → 成绩查询

你的脑子里要清楚:这个流程里有哪些环节、每个环节接收哪些参数、哪些环节可以跳过去。画好这张流程图,接下来测试的逻辑就会非常清晰——你心里有地图,才知道哪里有条没走过的路。

我这次的目标系统就是如此:在画流程图的时候,我注意到一个细节——选课系统里有一个“退课”功能,它接收的参数包含了课程ID和学生ID。当时我就想,学生ID如果我没登录或者不是本人,后端是否校验?结果就是这一念头,引出了本次最大的一个漏洞。

3. 实战全记录:在某高校教务系统上的一次完整挖掘

3.1 第一步:身份梳理与功能摸底

拿到授权后,我先对该校教务系统做了一遍轻量级的信息收集。所谓“轻量级”,就是不用扫描器,只通过浏览器正常访问,把这些信息记下来:

  • 系统类型:该校用的是某厂商的教务管理平台,版本号在首页footer能看到
  • 主要角色:学生端、教师端、管理员端三个入口
  • 核心功能模块:选课、退课、成绩查询、课表、信息维护、缴费
  • 认证方式:统一身份认证中心登录,登录后返回一个Session

这里有个小技巧:多注册一个账号作为测试账号。我注册了两个学生账号(A同学和B同学),这样测试水平越权时可以互相验证——用A的Cookie请求B的数据接口,如果返回了B的信息,那就是实锤。这个准备工作非常重要,没有第二个账号,很多越权问题你根本不敢确认。

3.2 突破口一:课程退选接口的水平越权

整个测试中最让我印象深刻的,就是退课接口的越权问题。具体流程是这样的:

正常操作是:学生A登录系统 → 进入我的课程 → 点击退课 → 系统弹出确认框 → 确认后课程被移除。

用Burp抓这个“确认退课”的包,我发现请求是这样的:

POST /api/course/drop_course Cookie: PHPSESSID=xxxxx Content-Type: application/x-www-form-urlencoded course_id=12345&student_id=10001

各位读者,问题就出在student_id=10001这个参数上。这个参数按理说应该由后端从Session里读取当前登录用户,而不是由前端传过来。但它就是在前端传参里的,那我是不是可以试试改成别人的ID?

我立刻用B同学的ID(10002)替换掉原来的10001,请求发出后,返回结果显示“退课成功”。再登录B同学账号一看——他的一门课真的被退掉了。这就实现了水平越权:我作为A同学,可以退掉任何人的课。

危害看起来只是“让他选不上课”,但在教务系统里,如果退课发生在选课截止时间前那一刻,可能会导致对方学分修不够,影响毕业,这就不是小事了。而且同一套参数在后端通常都会被其他接口复用,我随后检查了“退课”同一系列的接口,发现“自主选课”接口也存在相同问题——可以用B的ID替别人选课。这就变成了破坏选课系统的完整性漏洞。

3.3 突破口二:验证码与手机号解绑的逻辑漏洞

继续沿着个人设置模块测试,我发现了一个更有意思的问题。系统里提供“手机号码解绑”功能,正常逻辑是:

  1. 用户输入手机号
  2. 系统向该手机号发送验证码
  3. 用户输入验证码
  4. 验证通过后解绑成功

验证码是6位数字,有效期5分钟,错误次数限制是5次。前4步看似没有问题,但我注意到在发送验证码的时候,浏览器发出的请求是:

POST /api/user/send_unbind_code Cookie: PHPSESSID=xxxxx phone=13812345678

这里我直接把phone参数换成了另一个不在系统里的手机号,结果返回居然是“验证码已发送”。这一点说明:后端没有校验这个手机号是否属于当前登录用户。也就是说,我可以往任意手机号发送解绑验证码,然后如果我拿不到那个手机的验证码,其实还有后半招——但问题不止如此。

我又仔细看了一下“验证解绑码”的接口,发现它接收的参数除了验证码之外,还带了一个user_id。我突发奇想:如果我把user_id改成B同学的用户ID,同时把验证码改成A同学手机收到的那个,会发生什么?

结果验证通过了——然后页面提示“解绑成功”。我赶紧去B同学账号一看,B同学的手机号真的被解绑了。这就进一步升级成了身份解绑漏洞:任何一个登录用户,只要知道别人的user_id,就能用自己的验证码给别人解绑手机号。而后续密码找回、登录验证都会用到手机号,解绑后用户基本就失去了账号的保护能力。

3.4 突破口三:支付回调不验签,免费开通付费服务

第三个漏洞是在缴费模块里挖到的。该校的教务系统接入了统一的支付平台,用户在线支付教材费、考试费之后,系统根据支付结果开通对应服务。流程大概是:

用户提交订单 → 跳转支付平台 → 支付成功 → 支付平台回调系统后台 → 后台确认支付结果,更新订单状态

在逻辑漏洞挖掘里,支付回调接口是名副其实的高危区域。我在这类接口的测试思路固定是两步:第一步,完成一笔小额真实支付,拿到完整的回调请求;第二步,重放这个请求,看系统是否重复入账或额外开通权限。

但这次我连真实支付都省了,因为我发现回调接口的日志里有明文记录——理论上这些回调请求应该处理得非常小心,但可能存在一个问题:后端是否验证回调请求的来源和数据签名。

事实是,我用Burp拦截了一次浏览器触发“查询订单状态”的请求,发现前端在支付成功后调用了一个“通知后端开通服务”的本地接口:

POST /api/payment/notify Cookie: PHPSESSID=xxxxx order_id=20250610001&status=paid

当时我的第一反应是:等等,这个接口只传了 order_id 和 status,没有任何签名参数。那我直接补发一个虚构的order_id=99999999&status=paid会怎样?

发送后,系统竟然返回“订单状态更新成功”,然后我刷新页面——没有实际扣费记录的订单居然变成了“已支付”,对应的一门付费课程也解锁了。我又试了用不同手机号登录查看,发现这个虚构订单也能让其他账号受益吗?后来发现不是,它只会解锁“当前用户”的对应课程,但这已经够了——任何学生都可以通过伪造回调响应,免费开通付费课程。这个漏洞在真实业务里的危害非常直接:学校损失的是真金白银的学费收入。

3.5 后两个低危问题,也顺手记下来

接下来我又发现两个低危问题,虽然分数不高,但写报告时会体现专业度。一个是“课表接口泄露”问题:任课老师在系统里有开课班级的联系方式导出功能,导出接口没有做权限区分,登录学生身份也能调用,只是前端不给入口。直接POST到接口,返回一个Excel文件,里面包含所有选课学生的姓名和手机号。这个问题是信息泄露,属于中危偏低。

另一个是“重复签到”问题。该系统有一个讲座签到功能,用于考勤计分。正常情况下每个用户对同一个活动只能签到一次。但我发现签到的逻辑是先查询“该用户是否签到过”,如果没记录就插入,插入完成后再更新状态——如果并发请求过来,就可能造成多次签到。我用Burp把同一个签到请求重放了几次(开了并发线程),发现系统最终生成了三条签到记录。给用户带来的好处是:一场讲座加了三倍考勤分。虽然是给自己“谋利”,从学生视角是刷分,从系统安全性来说,是接口缺少幂等性设计,同样是业务逻辑上的一个拦路坑。

4. 方法论沉淀:从“瞎点”到“系统化”的逻辑漏洞挖掘心法

写到这里,可能有读者感觉我挖到的漏洞很“简单”。确实是简单——但“简单”恰恰是因为我脑子里有一套属于自己的“找坑清单”,而大多数新手亏就亏在不知道这个清单。

4.1 找坑的核心三问:参数、身份、状态

我在测试任何接口时,都会在脑内循环这三个问题:

  1. 与我无关的数据,能不能塞进参数里?(即参数是否可控且无归属校验)
  2. 换个身份做同一件事,能不能被拒绝?(即有没有做权限校验)
  3. 按不同的顺序做同一件事,结果会不会不一样?(即业务流程状态是否混乱)

这三个问题对应三类最典型的逻辑漏洞。后面的越权、验证码解绑、伪造回调,本质上都是在回答第一和第二问。而重复签到,就是在回答第三问。

4.2 一条完整的接口测试清单,直接拿去用

基于刚才的三个问题,我在实战里总结了一套接口测试清单。每测一个功能点,我都会把以下这些“攻击姿势”在脑子里快速过一遍:

测试点具体操作对应漏洞类型
对象归属操作某个资源时,替换资源ID或用户ID为他人ID水平越权
角色切换用低权限Cookie访问高权限接口垂直越权
参数篡改修改金额、数量、折扣、状态等参数业务参数篡改
验证码绕过修改响应包中的验证结果字段、重复使用旧验证码认证绕过
明文秘密检查前端JS是否硬编码管理口令、API密钥敏感信息泄露
回调重放重放支付成功、状态更新的回调请求重放攻击
状态颠倒跳过步骤A直接请求步骤B,如未注册先登录流程绕过
重复提交同一请求并发多次,观察是否多次生效幂等性缺失
未授权访问未登录或退出登录后请求内部接口访问控制缺陷
文件类型上传非预期类型的文件(如HTML、SVG)存储型XSS

每测一个功能,就在清单里打勾。这个清单不是死的,你遇到的具体业务还可以往里加。但有了这份清单,你在测接口的时候至少不会像无头苍蝇一样乱撞。

4.3 为什么大多数逻辑漏洞都藏在“接口”而不是“页面”

这个我多说一句。很多新手喜欢盯着页面上的表单看、点击按钮看弹窗,其实真正的漏洞全藏在接口交互层。原因是:前端页面为了用户体验做了很多限制(比如按钮置灰、验证码提示),但接口层面往往只负责接收参数,未必会再校验一遍。

举个例子:学生选课页面上,未到选课时间时按钮是灰色的、点击无效——这仅仅是前端禁用了按钮,后端接口依然在运行。我用Burp直接向选课接口POST一个请求,即使时间没到,后端依然会受理。这个在逻辑漏洞领域叫“前端校验与后端校验不一致”。

所以正确的做法是:忽略页面表现,直接把所有操作的请求发给Burp,然后在“原生请求”层面逐一测试条件。页面只是水面上的冰山,接口才是水面下的本体。

4.4 并发测试,最容易产出“意外惊喜”

说实话,并发漏洞在纯手工测试里属于比较难想到、但回报率极高的方向。很多业务的防重逻辑防的是“连续两次”,防不住“同一毫秒发来50次”。

这里的实操其实不需要多复杂的工具,Burp自带Repeater,我直接用Turbo Intruder插件敲两行Python脚本就能搞定。当然新手可以不用插件,直接在Burp Repeater里手点“Send”打个几十次也有效果,只是慢一些。关键在于抓准“写入前先查询”这种非幂等的代码逻辑。碰到签到、领取优惠、投票这种功能时,不妨下意识并发几次试试。

4.5 手动测完这些点,才算完整闭环

除了接口本身,别忘了周边的配置项。比如文件上传接口有没有校验文件内容?JSON请求Content-Type是否校验?JSON里的多余字段会不会被覆盖?这些细节性问题常常和上面的基础清单叠加出现,造成连环漏洞。我在某高校那次,最后还顺带测了上传头像处的文件类型校验绕过,配合之前的越权,能够把恶意文件挂到一个用户的号上。这条链虽然当时没继续深挖,但它展示了漏洞利用的“组合拳”思路。

5. 常见问题与避坑指南:你踩过的坑我都踩过

5.1 为什么我就是测不出来漏洞?

这是新手最多的问题,也最打击信心。我自己的体会是,“测不出来”往往不是因为目标系统真的很安全,而是因为你测的姿势不够深度。回顾自己第一次做真实系统测试时,我也是只测登录页有没有万能密码、主页有没有XSS,结果当然是零产出。后来我才学会“把流程走完再回头看接口”。漏洞常在平时没人碰的“边角功能”里:找回密码、个人资料修改、批量导入、数据导出。这些功能开发周期短、测试资源少,最容易留坑。

所以如果你暂时没有产出,我建议你做一件事:把你授权系统中的每个功能点都点一遍,然后对着第4节的清单挨个测。测完第一遍,保底也能挖到一两个低危问题。

5.2 测试时把一个账号的数据弄坏了怎么办?

在真实系统的授权测试中,哪怕甲方已经同意,你依然要避免破坏数据。有一次我在测一个删除功能时,不小心把某测试账号的所有历史记录都删光了,虽然不是线上生产数据,但那种心跳漏半拍的感觉很不好。我的经验是:凡是删除、修改、新增类的操作,先挑测试账号自己的数据下手,绝不碰其他身份或管理员的真实数据。如果必须动共享数据,测试前一定要提前和甲方确认能否回滚,并且做好完整截图记录。

再补充一个细节:测试过程中,每一步操作都要截图。截图不仅是写报告的材料,也是出了纠纷时自证清白的依据。

5.3 被WAF拦得死死的,还怎么测?

现在的目标系统十个里有八个都挂了WAF。WAF其实不拦逻辑漏洞,因为逻辑漏洞的请求看起来“极其正常”——就是正常用户操作接口、改了个参数而已。WAF拦的是SQL注入、XSS这些带特征的行为。所以遇到WAF,我的建议是:别和WAF硬碰硬,回归业务逻辑本身。你改参数、改ID、改顺序,这些都是“合规”的HTTP请求,WAF基本不会报警。

不过有一点要注意:不要对登录接口做爆破,不要对任意接口发起高频请求,这些是被WAF拦截甚至触发封禁IP的高发行为。逻辑漏洞测试的核心是:每次只发一个经过你深思熟虑的“正常”请求。

5.4 如何区分“漏洞”和“系统特性”?

这个界限有时确实很模糊。比如我用A账号可以查看到B账号公开的个人简介,这叫信息公开,不算漏洞;但如果我能看到B账号的手机号、家庭住址,那就是越权。有次某甲方的开发人员来质问一个提交问题,说“系统本来就允许手动改状态”,但实际情况是那是一个通知学生已缴费的确认接口——不该由学生自主触发。区分特性与漏洞的唯一标准就是危害性以及业务预期:功能设计时是否有意让这个能力暴露给当前角色?如果不是,就是漏洞。

另外提醒一句:逻辑漏洞的定性要保守。拿不准的,先在本地环境验证,再找团队负责人商量,最后写进报告时标明“待验证”。

6. 实战复盘总结(写给想精进的人)

最后分享几个我踩过坑之后才真正想明白的点,算是给后来者的私货。

第一,逻辑漏洞挖掘的真功夫在于“理解业务”。技术只是工具,真正值钱的是你能看懂一个系统“正常应该怎么运转”。只有知道正常,才能识别出反常。我碰到一些测试者,技术上能打,但看到业务流程图就头疼,这种人在逻辑漏洞方向走不远。

第二,练手不用到处找目标。把我文章里提到的DVWA和自己动手搭的模拟环境练透,比你在真实系统上乱试一百遍都有效。我个人的提升路线是:DVWA把基础越权练熟,然后在一个授权测试项目中跟着前辈学具体业务的挖掘思路,第三个月才独立上手输出有价值的漏洞报告。这套路线,我可以负责任地推荐给有耐心的读者。

第三,边测边写记录,最后报告会好写很多。很多人测的时候不记笔记,到写报告时天长日久已经忘了漏洞的触发路径,又得重新复现一遍。我的习惯是建立Excel表格,列十个字段:发现时间、漏洞类型、功能模块、请求包、响应包、危害说明、复现步骤、涉及参数、影响范围、修复建议。每挖到一个就填一行,最后报告直接从这个表里拉数据,效率极高。

第四,如果你在测试过程中发现敏感数据,比如大量学生身份证号、教师工资表,千万不能外传,也不要用这些数据去做任何验证以外的事情。这不仅是职业操守,更是法律底线。安全测试做久了,你会发现“信任”比“技术”稀缺得多。

这是一条越走越有意思的路。逻辑漏洞挖掘的门槛低,不代表天花板低——往深了走,你能学会以产品经理的视角审视系统,以攻击者的思维推演路径,以开发者的逻辑预判缺口。这套能力,放进任何互联网公司都是硬通货。希望这篇实战记录能帮你推开这扇门。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询