“卡冷却池”的本质是:伪造“刚登录游戏”的请求,让服务端重复结算离线时间。
封包:
29 02 01 00 00 00 00
解析为:
29 02 数据包 ID 553:CGAskMail
01 00 00 00 数据长度 1
00 ASK_TYPE_LOGIN
正常客户端登录时会发送一次这个请求。旧服务端收到后调用:
Obj_Human::OnHumanLogin()
该函数读取角色最后下线时间:
nOfflineTime = 当前时间 - LastLogoutTime;
m_DB.HeartBeat_Cooldown(nOfflineTime);
冷却池中的每项大致保存:
总冷却时间 m_nCooldown
已经经过时间 m_nCooldownElapsed
登录结算会执行:
m_nCooldownElapsed += nOfflineTime;
当:
m_nCooldownElapsed >= m_nCooldown
服务端就认为技能冷却完成。
漏洞在于角色登录后,数据库中的 LastLogoutTime 仍然是上一次真正下线的时间。攻击者重复发送 ASK_TYPE_LOGIN,服务端就会反复计算并累加同一段离线时间。
例如:
技能剩余冷却:3600 秒
角色登录前离线:1200 秒
发送一次:增加 1200 秒
发送两次:累计增加 2400 秒
发送三次:累计增加 3600 秒,冷却完成
普通战斗技能的冷却通常远小于离线时间,因此重放一次封包就可能全部冷却完成。这不是客户端视觉错误,服务端冷却数据确实被推进了,所以技能可以再次释放。
此外,重复调用 OnHumanLogin() 还会反复执行:
- 离线效果倒计时
- 登录 Lua 事件
- 离线 Impact 清理
- 反击列表清理
- 冷却和效果列表重新下发
修复后,每个连接只允许首次执行 ASK_TYPE_LOGIN。再次发送会记录安全日志并按协议错误断开连接,普通邮件查询不受影响。当前测试服需要替换为新编译的 Server 后修复才会生效。
|