瞬态存储陷阱:zkLink 78 万美元被盗全解析
核心要点
慢雾解析 zkLink 78 万美元被盗案:攻击者利用 Arbitrator 合约瞬态存储复用漏洞,伪造批次根并绕过校验,最终通过 Merkle 证明提取资产。
据 Woofun AI 消息,2026 年 10 月 29 日,知名跨链协议 遭遇安全事件,约 78.3 万美元资产被盗。安全团队对此次攻击进行了深度复盘,揭示了隐藏在瞬态存储机制下的逻辑缺陷。
zkLink 作为一个多链 zk 汇总(rollup)协议,其核心资产托管在主网上。ZkLink 合约(0x5fd9f73286b7e8683bab45019c94553b93e015cf)不仅承担 L1 消息服务的职能,还直接持有 金库;而配套的 合约(0xad16edcf7deb7e90096a259c81269d811544b6b6)则负责托管 代币金库。提现机制的信用基石在于'批次根'。
在 L2 层,每一笔提现操作都会生成一条 L2→L1 日志,同一批次内的所有日志共同构建出一棵 Merkle 树。当批次在 L2 执行完毕后,其对应的日志根 l2LogsRootHashes[batchNumber] 会被同步至 L1 的 ZkLink 合约中。用户在 L1 发起提现时,需提交提现消息及 Merkle 证明,ZkLink 合约利用存储中的根进行验证,验证通过后方可放款。简而言之,若根真实,消息才可能真实;若根被伪造,任意消息均可被'证明'为已发生。
此外,ZkLink 合约通过 totalBatchesExecuted 变量记录已执行的批次号,验证时会严格检查 _batchNumber 参数。
跨链消息的传递并非由各链直接交互,而是通过网关合约进行转发。在以太坊侧, 合约(0x83bc7394738a7a084081af22eec0051908c0055c)负责接收消息;而在 侧, 合约(0x803460416c2682ac54fccf03ef77b10a12f2809b)承担相应角色。这些网关由 合约(0x1ee09a2caa0813a5183f90f5a6d0e4871f4c6002)统一协调。
Arbitrator 合约的核心职责是认领并转发消息。受信任的 relayer 调用 claimMessage 函数时,Arbitrator 会先使用 relayer 指定的源链消息服务认领一条跨链消息,随后将消息转发至目标链网关。为确保'转发内容'与'实际认领消息'的一致性,Arbitrator 在认领过程中会通过 receiveMessage 函数回调,将消息哈希写入瞬态存储(transient storage),claimMessage 函数随后会比对这一声明。
瞬态存储(EIP-1153)是 Solidity 0.8.24 引入的新特性,其作用域覆盖整笔交易,而非单次函数调用。这意味着在同一交易内,后续发起的调用可以读取先前写入的值,直到交易结束才会清除。本次攻击的入口点是 合约(0x0fdc28e64772a70109d10fd068f859cfa7dea2c6),其 claimPrimaryChainSyncL2TxHashMessage 函数缺乏访问控制,本质上仅是一个将调用者参数原样转交给 Arbitrator.claimMessage 的辅助合约。该合约能成功调用 claimMessage,表明其已在 Arbitrator 合约中登记为 relayer。

评论
暂无评论