ERC-1271 签名重放漏洞

  • Alchemy
  • 发布于 2024-03-31 13:59
  • 阅读 22

本文讨论了一个由Alchemy发现的ERC1271合约签名重放漏洞,该漏洞影响了多个智能合约账户(SCA),并可能导致与多个应用程序(如Permit2和Cowswap)的交互风险。文章详细解释了ERC-1271的原理、漏洞的技术细节、潜在影响及修复方案,提供了丰富的代码示例和图解,适合区块链开发人员深入理解该漏洞及其预防措施。


发表于 2024年3月29日 4分钟阅读

智能合约账户签名重放漏洞智能合约账户签名重放漏洞

在2023年10月27日,Alchemy 发现了一个影响大量智能合约账户(SCA)的 ERC1271 合同签名重放漏洞,并在与多个应用程序互动时存在风险。受影响的 SCA 包括我们的 LightAccount 和 OKX 的 SmartAccount,我们确定的受影响应用互动包括 Permit2 和 Cowswap。我们迅速将此问题报告给了不同的受影响 SCA 和应用程序,并发现独立安全研究人员 curiousapple 在一个月前也发现了相同的漏洞。我们与 curiousapple、Frangio(ERC1271 作者)、ERC4337 团队,以及其他 SCA 技术专家合作进行修复。在此时,没有资金处于风险中,对应用程序的影响也相当有限。所有涉及的 SCA 都已承认了风险或已发布修复。

技术细节

ERC-1271 合同签名

在以太坊及所有基于以太坊虚拟机(EVM)的链上,有两种不同类型的账户 - 外部拥有账户(EOA)和智能合约。EOA 能通过其关联的 ECDSA 密钥对的私钥签名来验证消息。然而,由于智能合约在创建合约时获得一个预先确定的地址,它无法轻易访问私钥来签署消息。

为解决此问题,2018 年提出了 ERC-1271 合同签名标准。采用此标准,智能合约可以对什么构成有效签名进行实施限制/检查,应用程序可以调用 contract.isValidSignature 来验证某些操作是否获得智能合约的授权。

复制

// ERC1271 接口
interface IERC1271 {
    /// 如果有效,返回 bytes4(0x1626ba7e),否则返回其他值
    function isValidSignature(bytes32, bytes calldata) external returns (bytes4);
}

在智能合约账户(SCA)的背景下,ERC-1271 非常方便,因为它使 SCA 的用户能够以与 EOA 相同的方式使用基于签名的应用程序。这些应用程序包括 OpenSea,以及大多数 DeFi(依赖于代币审批 → 调用体验)。

ERC1271 签名重放漏洞

复制

// ERC1271 参考实现:https://eips.ethereum.org/EIPS/eip-1271
function isValidSignature(
    bytes32 _hash,
    bytes calldata _signature
) external override view returns (bytes4) {
    // 验证签名
    if (recoverSigner(_hash, _signature) == owner) {
      return 0x1626ba7e; // 1271_MAGIC_VALUE
    } else {
      return 0xffffffff;
    }
}

大多数 SCA 通过使用上述参考实现实现 ERC-1271。从工程上看,这是一个轻量级的实现,它使客户端集成变得更容易,因为我们可以重用方法如 signTypedDatasignMessageeth_signTypedData_v*personal_sign,与 EOA 使用方式相同。

但是,如果同一地址拥有多个 SCA,且应用程序未包含交互的源地址,则该签名在该应用程序的两个账户中都是有效的。

由于该漏洞仅在 SCA 和应用程序组合的情况下才可能出现,这一漏洞的严重性取决于该交互可以与哪些应用程序合作。我们首先查看的应用程序是 Permit2,它是 Uniswap 建立的公共基础设施,改善了产业中 ERC20 代币审批流程的安全性与用户体验,因此目前广泛使用。

以下代码块显示了 Permit2 签名所涵盖的结构。特别是,address owner,从中提取代币的地址,并未涵盖在签名中,而是作为参数传递给 Permit2 的调用。

复制

/// Permit2 结构
/// 来源:https://github.com/Uniswap/permit2/blob/cc56ad0f3439c502c246fc5cfcc3db92bb8b7219/src/interfaces/IAllowanceTransfer.sol#L44-L54
struct PermitDetails {
    address token;
    uint160 amount;
    uint48 expiration;
    uint48 nonce;
}
struct PermitSingle {
    PermitDetails details;
    address spender; // 代币转移的接收者
    uint256 sigDeadline;
}

攻击者利用此签名重放漏洞的过程大致如下:

  1. Bob 请求 Alice 支付 X 代币,Alice 拥有 n 个 SCA,并请求通过 Permit2 完成此操作。

  2. 当 Alice 签署第一个许可后,Bob 可以在所有 Alice 的 SCA 上重放此许可,以获得总共 n * X 代币。

Bob 对拥有 2 个 SCA 的 Alice 的攻击示意图Bob 对拥有 2 个 SCA 的 Alice 的攻击示意图

在此过程中,我们制作了一个概念证明以证实此漏洞。请在这里找到:replay-sig-poc

影响

作为我们调查的一部分,我们发现:

  1. 多个 SCA 存在风险。

  2. 除了我们的 LightAccount,其他 SCA 包括 Zerodev 的 KernelBiconomySoul Wallet、eth-infinitism 的 EIP4337Fallback 用于 Gnosis Safes、AmbireAccount、OKX 的 SmartAccount、Argent 的 BaseWalletFuse Wallet

  3. 多个应用程序存在风险:

  4. Permit2 - 基于签名的转账是可重放的。然而,大多数 Permit2 的使用是通向 Universal Router,利用这一点需要 Universal Router 中的一个独立关键漏洞。

  5. Cowswap - 使用 ERC-1271 路径的交易是可重放的。签名涵盖了 address recipient,因此这里的风险至多是过期价格和/或某些 MEV 损失。

  6. Gnosis Safe 在此攻击向量中并不脆弱。

在此时,我们通过 Telegram 群组向 SCA 和应用程序披露了此事,并发现 curiousapple 在一个月前也发现了同样的问题,并与 Frangio 和其他 SCA 技术专家合作进行修复。总的来说,目前受影响的 SCA 和应用程序的完整组合列表如下所示:

影响:账户和应用程序影响:账户和应用程序

注意:对于 Argent,由于它们是一个移动应用并且每台设备生成签名者,因此不可能有两个 SCA 由同一 EOA 拥有,因此签名重放攻击对 Argent 无效。然而,未完整叉 Argent 合同的项目可能仍然处于风险中,并应采用 Argent 的钱包架构或发布修复。

修复

提出了两个 SCA 修复方案。SCA 建设者应注意,他们应实施这两个解决方案之一以防止上述重放攻击:

复制

// 解决方案 1:
// 用 SCA EIP712 域包装传入摘要
function isValidSignature(bytes32 digest, bytes calldata sig) external view returns (bytes4) {
    bytes32 domainSeparator =
        keccak256(
            abi.encode(
                _DOMAIN_SEPARATOR_TYPEHASH,
                _NAME_HASH,
                _VERSION_HASH,
                block.chainid,
                address(SCA)
            )
        );
    bytes32 wrappedDigest = keccak256(abi.encode("\x19\x01", domainSeparator, digest));
    return ECDSA.recover(wrappedDigest, sig);
}
// 解决方案 2:
// 仅用 SCA 的地址包装传入摘要
function isValidSignature(bytes32 digest, bytes calldata sig) external view returns (bytes4) {
    bytes32 wrappedDigest = keccak256(abi.encode(digest, address(SCA)));
    return ECDSA.recover(wrappedDigest, sig);
}

这两个解决方案均可防止 ERC-1271 签名重放攻击。后者的解决方案更轻量,但意味着钱包客户端必须为用户显示一个不透明的哈希供其签名。前者的修复在确保签名对用户不不透明的道路上更容易,也因此我们为 LightAccount 选择了前者的修复。大多数其他 SCA 也选择了相同的修复。

致谢

特别感谢 OKX 支付给 Howy 的漏洞奖励,以解决此问题!

祝贺 curiousapple 从 Ambire、Instadapp、Biconomy 和 Cowswap 获得漏洞奖励!

此外,特此感谢:

  1. Dror Tirosh 为大多数 SCA 采用的 EIP-712 结构方法修复进行头脑风暴
  2. Frangio 为分享 ERC-1271 的更多背景以及通过 EIP 委员会更新 ERC-1271 的参考实现做出的巨大努力
  3. Ivo (Ambire) 为深入探讨两种提议解决方案之间的技术实现差异
  4. Vectorized 为嵌套 EIP-712 解决方案的客户端实现提出并资助 0.5 ETH 奖金
  5. Juno (ChainLight) 迎接挑战,交付 嵌套 EIP712 解决方案的客户端实现 并获得 Vectorized 的奖金
  6. David Eiber 在头脑风暴相关漏洞、索引受影响的 SCA 和协议以及创建 PoC 方面的帮助
  7. Yoav Weiss 在整个过程中包括连接我们与安全研究人员及其他受影响的 SCA 和应用程序时的帮助
  • 原文链接: alchemy.com/blog/erc-127...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Alchemy
Alchemy
江湖只有他的大名,没有他的介绍。