hunterinvariants/aegis-7702
GitHub: hunterinvariants/aegis-7702
Aegis-7702 是一个 Slither 插件与 Foundry 测试套件,专门检测 EIP-7702 智能账户委托场景中常规逐合约静态分析会遗漏的安全漏洞。
Stars: 0 | Forks: 0
# Aegis-7702
[](https://github.com/hunterinvariants/aegis-7702/actions/workflows/ci.yml)
一个 Slither 插件,用于捕获特定于 EIP-7702 智能账户 delegate 的安全漏洞——那些在常规逐合约审查中经常被遗漏的漏洞。
## 为什么会有这个项目
EIP-7702 允许一个常规钱包 (EOA) 借用合约的代码并作为其自身在其自身的存储中运行。这很有用,但它悄然打破了审计人员和工具所依赖的假设:`msg.sender` 究竟是谁、代码运行时存储中有什么内容,以及签名是否可以被重放。Slither 是大多数团队首选的静态分析工具,但其本身并没有 delegation 的概念——它孤立地查看每个合约,从而完全错过了这些隐患。Aegis-7702 作为 Slither 插件添加了这一缺失的层。
## 它能捕获什么
- `eip7702-unprotected-entrypoint` (高) -- 没有调用者检查的 execute/call 入口点;任何人都可以驱动该账户。
- `eip7702-recallable-initializer` (高) -- 没有真正一次性执行守卫的 initializer;可被重新初始化并接管账户。
- `eip7702-missing-nonce` (高) -- 没有 nonce 的签名操作;可随意重放。
- `eip7702-replay-unsafe-sig` (中) -- 未绑定 chainId 的签名;可在另一条链上重放。
- `eip7702-unsafe-eoa-assumption` (中) -- 将 `tx.origin == msg.sender` 用作“是否为 EOA”的检查,而 7702 打破了这一点。
- `eip7702-constructor-state` (中) -- 在 constructor 中设置的安全状态;一旦 EOA 进行 delegate 就会丢失。
- `eip7702-storage-collision` (信息) -- 普通(非命名空间)存储;重新 delegation 可能会破坏它。请使用 ERC-7201。
完整的详细说明——包含漏洞示例及相应的修复方案——位于 `docs/detectors.md` 中。
## 它有效吗?
每个 detector 在发布前必须做两件事:在已知存在漏洞的合约上触发,并在已知安全的合约上保持静默。该仓库包含这两者,且只需一条命令即可进行检查:
```
python tests/run_corpus.py
-> 7/7 detectors pass
```
这些统计数量已提交在 `runs/corpus-proof.json` 中,因此如果任何 detector 变得更嘈杂或更安静(不仅仅是验证被破坏时),`--check runs/corpus-proof.json` 都会失败。
我们还在 The Red Guild 的 `7702-goat` (https://github.com/theredguild/7702-goat) 上运行了整个检测包,这是公开的、故意包含漏洞的 7702 delegate 集合,它标记了其中的每个漏洞类别(从 V0 到 V6)——可以在 `targets/7702-goat.json` 中固定的 commit 处使用 `./run_goat.sh` 进行复现;结果已提交在 `runs/goat.json` 中。
请注意这说明了什么以及没有说明什么:`7702-goat` 是故意包含漏洞的代码,因此它衡量的是召回率。该检测包在生产级 delegate 上的噪音有多大是另一个问题,现在也对此进行了衡量。
## 它的噪音有多大?
该检测包也在固定 commit 处针对三个经过审计且已部署的 EIP-7702 实现进行了运行——MetaMask 的 delegation-framework、Uniswap 的 Calibur 和 ZeroDev 的 Kernel——并且每一项发现都经过了人工审查,并附带了书面理由说明。
```
2 true positives, 7 false positives, 1 disputed -> precision 0.22
```
这是一个很低的数字,并且是按原样发布的,因为一个只针对故意包含漏洞的代码运行过的检测包并不知道自己的噪音有多大。其余的误报分为两类常见的模式:detector 尚未建模的现代命名空间存储模式,以及虽然与 delegate 一起编译但本身并不是 delegation 目标的辅助合约。这两个局限性都记录在 `THREAT_MODEL.md` 中。作为对比,原版 Slither 在同一个 MetaMask commit 上提出了 463 项发现,而该检测包仅提出了 4 项。
完整数据、按目标划分的明细及原始数据:`docs/EVIDENCE.md`。复现全部内容:`docs/REPRODUCE.md`。
## 安装
```
pip install slither-analyzer
pip install -e .
```
为了复现已发布的结果而不仅仅是使用 detector,请改为针对固定的工具链进行安装——请参阅 `docs/REPRODUCE.md`:
```
pip install -c constraints.txt -e .
```
## 使用
```
slither --detect eip7702-unprotected-entrypoint,eip7702-missing-nonce,eip7702-replay-unsafe-sig
```
添加上述列表中的其余参数以运行整个检测包。
## 动态测试组件
静态标记只是初级的防线。真正会造成危害的 7702 漏洞是多笔交易的——它们只有在账户切换 delegate 或签名被重用时才会显现出来——因此这些 detector 由位于 `harnesses/` 目录中的 Foundry 测试组件提供支持,这些组件会在真实的 7702 条件下运行 delegate 并执行漏洞利用。与语料库一样采用相同的双向原则:攻击在存在漏洞的 delegate 上成功执行,并在安全的 delegate 上回退。
```
forge test
-> 8/8 (evm_version = prague)
```
- storage collision -- 一个 delegate 遗留在 slot 0 的值被下一个 delegate 读取为 `owner`,从而导致账户被接管。采用 ERC-7201 命名空间的 delegate 可以抵御此攻击。
- missing nonce -- 一个签名重放并发送了两次;带有 nonce 跟踪的版本会阻止第二次发送。
- recallable initializer -- 第二次 `initialize` 接管了账户;带有守卫的版本会发生回退。
- unprotected entrypoint -- 一个陌生人驱动了被代理的账户并花费了受害者的 token,因为 token 合约将受害者视为 `msg.sender`;带有调用者校验的版本会发生回退。
因此,审查人员可以亲眼看到 detector 标记出的具体漏洞被实际触发——而不是盲目相信这个标记。
高和中级别的发现是值得审查的真实漏洞。信息级别(storage-collision)是一个“建议使用 ERC-7201”的提醒,而不是一个漏洞。
范围、攻击者模型以及此检测包明确声明不做的事情:`THREAT_MODEL.md`。
采用 MIT 许可证。
标签:Slither插件, Solidity, 以太坊, 区块链安全, 智能合约审计, 逆向工具, 错误基检测, 静态代码分析