Musyg/reward-accounting-drift-audit
GitHub: Musyg/reward-accounting-drift-audit
一个演示 MasterChef 风格质押池奖励累加器漂移漏洞的智能合约安全审查项目,提供可复现的 Foundry PoC 和已修复分支。
Stars: 0 | Forks: 0
# 奖励会计漂移,安全审查演示

这是一个智能合约安全审查的独立演示:一个刻意
包含漏洞的 MasterChef 风格质押池,其 `deposit` 会快照一个过时的奖励
累加器,由此导致的奖励被盗(通过通过的
[Foundry](https://book.getfoundry.sh) 概念验证来证明),以及一个在
相同场景下已消除该漏洞的 `fixed` 分支。
## 为什么创建此仓库
任何人都可以在简介中写上“我审计智能合约”。这个仓库展示的是实际工作:一个目标、一个具体的发现、一个可执行的证明,以及一个经过验证的修复。如果无法重现,就不算完成。
## 仓库布局
此审查位于两个分支中:
| 分支 | 内容 | 绿色的 `forge test` 代表什么 |
|--------|----------|---------------------------------|
| `master` | 包含漏洞的质押池以及利用该漏洞的 PoC | 后加入的存款者可以收获他们在加入之前产生的奖励 |
| `fixed` | 修复后的质押池以及相同的场景 | 后加入的存款者无法获得加入之前的奖励 |
- `src/RewardPool.sol`,接受审查的合约
- `test/RewardPool.poc.t.sol`,概念验证
- `Reward_Accounting_Drift_Review.pdf`,完整的书面报告
## 发现
| ID | 严重程度 | 摘要 |
|----|----------|---------|
| H-01 | 高 | 存款时累加器过时。`deposit` 更新了用户的质押份额和 `rewardDebt`,但在此之前没有先调用 `updatePool`,因此它快照了一个过期的 `accRewardPerShare`。在累加器刷新之前加入的存款者会获得在他们未持有份额时累积的奖励,从而将奖励从真正赚取它们的质押者那里抽走。 |
在 `master` 分支上的 PoC 数据:Alice 作为唯一的质押者持续了 100 秒,因此该时间窗口内的所有 100 个奖励代币都归她所有。攻击者在最后时刻存款并立即收获:攻击者拿走了 50 个代币,而 Alice 只收到 50 个。在 `fixed` 分支上,攻击者收到 0 个,而 Alice 保留了全部 100 个。
## 重现步骤
需要 [Foundry](https://book.getfoundry.sh/getting-started/installation)。
```
git clone https://github.com/Musyg/reward-accounting-drift-audit.git
cd reward-accounting-drift-audit
forge install
# master: 奖励窃取成功
forge test -vv
# fixed: 同一攻击被中和
git checkout fixed
forge test -vv
```
## 修复方案
在 `deposit` 的开头,即触碰质押份额和 `rewardDebt` 之前,调用 `updatePool()`。首先结清累加器意味着新存款者的 `rewardDebt` 是根据最新的 `accRewardPerShare` 进行快照的,因此他们只会从加入的那个区块开始计算奖励。这是每个 MasterChef 派生质押池所依赖的恒定规则:在对质押份额进行任何更改之前,先刷新累加器。
## 严重程度的评级标准
高:无特权参与者直接从诚实的质押者那里窃取已累积的奖励。唯一的先决条件是在奖励待累积期间进行存款,而这正是活跃质押池的正常状态。
标签:Foundry, 区块链, 智能合约