逆向工程实战手册 第 80 章

第 80 章 竞态条件与并发漏洞(Race Window)

竞态条件(Race Condition)是"两个操作并发访问同一资源,顺序影响结果"导致的漏洞:TOCTOU、双花、重复兑换、越权并发。它在 Web 逻辑漏洞、内核漏洞、区块链攻击(闪电贷)中都是核心主题。竞态挖掘 = 找"检查与使用之间的时间窗"。

📍 知识点地图 | 主题:竞态漏洞 | 前置:第58章 | 后续:— | 核心概念:TOCTOU、重复兑换、Turbo Intruder、原子性

80.1 竞态漏洞分类学

按资源: 文件(TOCTOU)/ 状态(检查-使用)/ 数据(重复操作)
按场景:
  Web 逻辑: 重复兑换/双花/库存超卖/限速绕过
  内核: 并发引用计数/锁缺失(第 79 章常见)
  区块链: 闪电贷原子性攻击(第 46 章)
  桌面/移动: 文件系统竞态(符号链接攻击)

核心模式: TOCTOU(Time-Of-Check-To-Time-Of-Use)
  1. 程序检查某条件(有权限/未使用/余额够)
  2. 另一个线程在"检查后、使用前"修改了状态
  3. 程序按"检查时的状态"继续执行 → 错误操作

80.2 Web 竞态漏洞(最常见的实战目标)

重复兑换(Double-Spend)

场景: 优惠券/积分/兑换码"只能使用一次"
漏洞: 服务端"检查是否已用 → 标记已用"两步不是原子的
攻击: 并发发送 N 个兑换请求 → 全部通过检查 → 兑换 N 次

复现:
  1. 抓兑换请求
  2. 并发重放(Burp Intruder 并发/Turbo Intruder)
  3. 观察是否多次成功

库存超卖

场景: 商品库存 1 件
漏洞: "检查库存 > 0 → 扣库存"非原子
攻击: 并发下单 → 多人都"买"到同一件

余额竞态

场景: 转账/提现
漏洞: "检查余额 → 扣款"非原子
攻击: 并发多次提现 → 都通过余额检查 → 超额提现

限速/验证码绕过

场景: 登录限速/验证码一次性
漏洞: 计数检查非原子
攻击: 并发爆破绕过限速

80.3 竞态挖掘方法论

1. 找"检查-使用"模式:
   □ 读状态 → 判断 → 写状态(三步)
   □ 判断和写在不同的请求/函数/锁之外
2. 找"幂等缺失":
   □ 重复执行同一请求是否产生多次效果(兑换/转账/创建)
3. 找"共享可变状态":
   □ 全局计数器/用户余额/库存/状态字段

工具:
  Turbo Intruder(Burp 扩展,并发神器)
  racepwn(竞态测试专用工具)
  自写 Python(线程池并发请求)

80.4 并发测试实操(Turbo Intruder)

# Turbo Intruder 模板(并发重放)
def queueRequests(target, wordlists):
    engine = RequestEngine(endpoint=target.endpoint,
                           concurrentConnections=20,
                           requestsPerConnection=1)
    for i in range(100):                    # 100 并发
        engine.queue(target.req, i)

def handleResponse(req, interesting):
    if req.status != 200:
        table.add(req)
复现流程:
  1. 正常请求抓包 → 标记竞态候选
  2. Turbo Intruder 并发重放(100-500 并发)
  3. 观察: 多次成功? 状态变化异常?
  4. 验证: 重复兑换/超卖/绕过生效

80.5 竞态漏洞的根因与防御(分析视角)

根因模式:
  □ 非原子操作(检查与使用分离)
  □ 缺锁/锁范围错误
  □ 数据库事务隔离级别不当
  □ 缓存与数据库不一致
  □ 单例状态(进程内计数器多实例失效)

防御:
  □ 原子操作(数据库 UPDATE 条件扣减/唯一约束)
  □ 乐观锁/悲观锁
  □ 事务隔离(串行化)
  □ 幂等设计(请求 ID 去重)
  □ 服务端一次性令牌(不可重放)

80.6 内核/区块链竞态(延伸)

内核: 并发访问共享结构(锁缺失 → UAF/双重释放)
  → 第 79 章利用链常包含竞态原语
区块链: 闪电贷(原子借-攻-还,第 46 章)
  → 组合多个交易的"原子性"攻击

80.7 竞态测试检查清单

□ 功能盘点: 兑换/转账/下单/验证码/状态修改
□ 找检查-使用模式(非原子)
□ 并发重放(Turbo Intruder)
□ 多次成功验证
□ 影响评估(重复兑换/超卖/绕过)
□ 根因确认(哪一步非原子)
□ 报告: 复现(并发数/请求)可重复

动手练习

  1. 在一个练习应用(或靶场)复现"重复兑换":正常兑换 + 100 并发重放对比。
  2. 用 Turbo Intruder 对一个验证码功能做并发测试,观察是否绕过一次性。
  3. 分析一个真实的竞态漏洞报告(SRC 公开披露),指出它的"检查-使用"分离点。
  4. 讨论题:为什么"数据库扣减用 UPDATE ... WHERE 条件"能防超卖?(原子性)

深入阅读

  • 仓库:CTF-Sandbox-Orchestrator/competition-race-condition-state-drift/(竞态 CTF 子技能)
  • 仓库:CTF-Sandbox-Orchestrator/competition-queue-worker-drift/(队列/worker 状态漂移)
  • 仓库:skills/api-security/SKILL.md(API 逻辑测试)
  • 仓库:skills/pwn-chain/references/kernel-pwn.md(内核竞态)
  • 实战案例:skills/field-journal/2026-05-26_pentest-newapi-rate-limit-bypass.md(限速绕过)