条件竞争
介绍
条件竞争(Race Condition)是一种并发编程中的问题,指的是多个线程或进程在无正确同步机制的情况下访问共享资源,导致程序行为不可预测或错误的情况。
触发条件
- 并发,即至少存在两个并发执行流。这里的执行流包括线程,进程,任务等级别的执行流。
- 共享对象,即多个并发流会访问同一对象。常见的共享对象有共享内存,文件系统,信号。一般来说,这些共享对象是用来使得多个程序执行流相互交流。此外,我们称访问共享对象的代码为临界区。在正常写代码时,这部分应该加锁。
- 改变对象,即至少有一个控制流会改变竞争对象的状态。因为如果程序只是对对象进行读操作,那么并不会产生条件竞争。
现实场景
网店购物
假设网店有 1
件商品,两个用户几乎同时下单:
- 用户 A 读取库存(库存 = 1)
- 用户 B 也读取库存(库存 = 1)
- 用户 A 付款成功,系统更新库存
1 → 0
- 由于用户 B 读取库存的时候用户A并没有付款成功,所以读到的库存也是1允许继续执行付款操作,最后付款成功,库存实际变成
-1
(超卖)
银行取钱
假设银行账户余额为 1000
元,两个人同时在不同的 ATM 机上取款 800
元:
- 线程 1(ATM A) 读取账户余额 1000
- 由于线程1此时还没有取款就已经执行了线程 2(ATM B) ,所以线程2也读取到账户余额
1000
- 线程 1 计算 取款后余额:
200
- 线程 2 计算 取款后余额:
200
- 线程 1 写入 新余额 200
- 线程 2 也写入 新余额 200,但实际应该是 -600(透支)
票务系统
如果两个用户同时购买最后一张票:
- 用户 A 读取票数(剩余
1
张) - 用户 B 也读取票数(剩余
1
张) - 用户 A 付款成功,票数变
0
- **用户 B 也付款成功,车票相同产生冲突
CTF中的应用
HgameCTF2025
1 | from flask import Flask, request, render_template, render_template_string, redirect |
render_template
导致产生ssti注入漏洞,虽然waf过滤了{
但是可以利用代码存在的条件竞争漏洞
重点关注 /send
的文件写入操作和 /read
的文件读取操作,在高并发情况下,多个请求可能同时修改 message.txt
/send路由接收到信息后先将内容写入message.txt,之后访问/read才会进行waf检查,
如果message在/read检查时是正常内容,正准备输出内容之前这个空隙又一次执行了/send覆盖了原本正常的message内容,那么就可以成功写入恶意代码,实现bypass
因此我们同时间进行三个请求:
- /send 发送正常内容
- /send 发送恶意代码
- /read 读内容
就可以绕过waf实现代码执行