Appearance
S1C4: Who Can Sign This?
1. 问题
合约要求调用者提供一个 ECDSA 签名来证明身份。mintFlag 函数检查签名是否由某个 authorized signer 签发。
2. 原因
合约使用 ECDSA 签名恢复(ecrecover)来验证调用者。签名必须由硬编码的 authorized signer 地址签发。需要找到该 signer 的私钥或通过其他方式获取有效签名。
3. 方案
- 从合约 storage 读取 authorized signer 地址
- 使用已知的 Hardhat 默认 mnemonic 推导 signer 私钥(index 12)
- 用该私钥对消息签名
- 提交签名到
mintFlag
javascript
// 使用 ethers.js 签名
const signer = ethers.Wallet.fromMnemonic(hardhatMnemonic, "m/44'/60'/0'/0/12");
const signature = await signer.signMessage(messageHash);
4. 遇到的陷阱
Signer 私钥来源: 不同文档可能指向不同的 derivation path 或 mnemonic。
5. 陷阱的原因
Hardhat 默认 mnemonic 的 account index 12 对应地址 0xFABB0ac9d68B0B445fB7357272Ff202C5651694a,这是 CTF 部署者用作 authorized signer 的地址。
6. 如何解决
验证 signer 地址是否匹配合约中存储的 authorized signer:
bash
cast storage <CHALLENGE> <SIGNER_SLOT>
使用正确的 mnemonic 和 derivation path 生成签名。
7. 技术要点
| 要点 | 说明 |
|---|---|
| ECDSA 签名恢复 | ecrecover 从签名恢复公钥/地址,用于身份验证 |
| Hardhat 默认账号 | Hardhat 使用固定的 mnemonic,所有测试账号的私钥是公开的 |
| EIP-191 | 签名消息的标准化前缀格式 |
| ERC-1271 | 智能合约签名验证的标准接口 |