从真实失败中抽取可复用模型
真实案例→定位根因→最小模型→攻击测试→修复回归
闪电贷、恶意 Token、回调等常常只是触发器或放大器。你要继续追问:系统本来承诺的哪个不变量被破坏了?
访问控制:谁拥有改变系统的能力
- 初始化函数是否可重复或被抢先调用。
- 管理员、operator、guardian 与 upgrader 是否分权。
- 内部函数或间接路径能否绕过权限。
- 多签和时间锁是否实际约束了链上执行。
不只检查 modifier
权限错误可能出现在初始化、代理升级、治理执行、签名恢复和一条间接内部调用路径中。
重入:外部调用意味着交出控制权
不只检查 ETH 转账。ERC-777、ERC-721 接收、闪电贷、DEX callback 和恶意 Token 都可能把控制权交还给攻击者。
先交出控制权
sendAssets();
balance[user] = 0;先完成状态变化
balance[user] = 0;
sendAssets();Checks-Effects-Interactions 和重入锁只能解决部分问题。还要检查跨函数共享状态与只读重入。
精度与舍入:一 wei 的偏差也能复利
mul / div优先先乘后除,减少过早截断。
rounding明确每个计算应向协议还是用户方向舍入。
decimals不要假设所有 Token 都是 18 位小数。
edge检查首存、零份额、极小输入和巨额输入。
代理与升级:逻辑可以换,状态不能错位
- implementation 是否被初始化锁定。
- 升级权限是否受到多签和时间锁约束。
- 新实现是否保持 storage layout 兼容。
- 审计 commit 是否真的是当前实现。
组合风险
即使代理与实现分别正确,升级流程、管理员权限和初始化顺序组合后仍可能产生严重漏洞。
一个有效 Finding 必须形成证据链
具体代码位置可达调用路径明确前置条件可复现 PoC可量化影响合理修复
只有“可能存在风险”而没有路径和影响,通常只是观察项,不是已经证明的漏洞。
课末自测
为什么“这里有一个外部 call”本身不能证明存在重入漏洞?
信心