时间 2025 年 2 月 21 日
涉案 约 $14.6 亿 ⭐ 有记录以来最大
入侵点 ⚠️ 多签钱包服务的开发者机器
归属 普遍归因于有国家背景的攻击组织
类别 C7 密钥与签名流程(供应链)

一、这一篇的位置

⭐ 把 Unit 7 的三起放在一起看:

   [WazirX](https://blog.ifcalm.org/posts/security/blockchain/23-wazirx/)(2024-07)   $2.35 亿   攻破签名者看到的界面
   [Radiant](https://blog.ifcalm.org/posts/security/blockchain/24-radiant-capital/)(2024-10)  $0.50 亿   攻破签名者的设备
   ⭐ Bybit(2025-02)  $14.6 亿   ⚠️ 攻破【所有人共用的那个服务】

⟹ 攻击者沿着同一条思路往【上游】走了两步:
   从"骗一个人",到"骗一群人",
   ⭐ 到"污染他们共同依赖的那个源头"。

二、攻击复盘

Bybit 使用 Safe{Wallet} 管理冷钱包。攻击的路径是:

① ⭐ 攻击者入侵了 Safe{Wallet} 一名开发者的机器
      ⟹ 由此获得了对其前端资源存储的写入能力

② 向前端注入恶意 JavaScript
      ⚠️ 但不是对所有人 ——
      ⭐ 代码里带有【条件判断】:
         只有当访问者是 Bybit 的特定钱包地址时才激活。

      ⟹ 其他所有用户看到的都是正常界面
      ⟹ ⭐ 任何常规的监控、抽查、用户反馈都发现不了

③ Bybit 团队发起一次【例行的】冷钱包转账
      ⟹ 签名者在界面上看到的是一笔正常的转账
      ⟹ ⚠️ 而实际被构造的载荷是一个
           【operation = 1 的 DELEGATECALL】

④ 三位签名者依次用硬件钱包确认
      ⟹ 每一步的密码学都正确
      ⟹ 多签门槛被正常满足

⑤ 交易上链执行
      ⟹ ⭐⭐ DELEGATECALL 在冷钱包【自己的存储上下文】里
           执行了攻击者的代码
      ⟹ 钱包的实现逻辑被整个替换掉

⑥ 攻击者用新的实现逻辑,把约 40 万枚 ETH 转走

⭐⭐ 注意第 ⑤ 步:钱不是被"转走"的,钱包是被"换掉"的。

签名者批准的那笔交易本身没有转走任何钱—— 它只是把这个钱包变成了一个由攻击者控制的钱包。 真正的转账发生在之后,而那时已经不需要任何人签名了。

三、⭐ 每一层防御都在正常工作

这是本篇最值得记住的部分。 逐层检查:

□ 智能合约有漏洞吗?          ⭐ 没有。Safe 合约按设计工作。
□ 密码学被攻破了吗?          ⭐ 没有。签名全部有效。
□ 多签门槛被绕过了吗?        ⭐ 没有。门槛被正常满足。
□ 私钥泄露了吗?              ⭐ 没有。私钥始终在硬件钱包里。
□ 硬件钱包被攻破了吗?        ⭐ 没有。它正确地签了给它的哈希。
□ 签名者被收买了吗?          ⭐ 没有。他们在执行正常职责。
□ Bybit 的服务器被入侵了吗?  ⭐ 没有。

⚠️ 然后 14.6 亿美元没了。

⭐ 唯一失守的环节:
   【签名者用来理解自己在签什么的那个界面】
   ——而那个界面来自一个第三方服务,
     那个服务的一台开发机器被入侵了。

⭐⭐ 这是供应链攻击的完整形态: 攻击者不攻击你,他攻击你信任的东西。 而你对那个东西的信任,从来没有被明确地评估过。

四、为什么这个攻击如此难防

① 定向投毒,无法被抽查发现

⭐ 恶意代码只对特定目标激活。

⟹ 这意味着:
   · Safe 的其他数万名用户看到的都是正常界面
   · 常规的前端完整性检查(如果有)在其他时刻都通过
   · ⚠️ 只有 Bybit 的签名者在那几分钟看到了它

⟹ 传统的"用户会发现异常"这条防线【结构上失效】。

② 信任链没有被列出来过

⭐ 问 Bybit 事发前"你们的资金安全依赖哪些东西",
   大概率的回答是:

      · 冷钱包私钥(硬件钱包里)
      · 多签门槛
      · Safe 合约的正确性
      · 我们自己的运维流程

⚠️ 而实际的清单还包括:
      · Safe{Wallet} 前端的完整性
      · ⭐ Safe{Wallet} 每一名开发者的机器
      · 它的 CI/CD 与资源分发链路
      · 它使用的每一个第三方依赖

⟹ ⭐ 这些从来不在任何人的威胁模型里。

③ 规模与目标的不对称

⚠️ 有国家背景的攻击组织,其资源与耐心
   远超普通的经济性攻击者:

   · 可以潜伏数月甚至更久
   · 可以针对特定个人做长期社会工程([第 22 篇](https://blog.ifcalm.org/posts/security/blockchain/22-ronin-bridge/))
   · ⭐ 可以攻击【供应商的供应商】
   · 不受"攻击成本必须小于收益"的约束

⟹ 传统的经济学威胁模型
   ("攻击成本 > 攻击收益 ⟹ 安全")
   ⭐ 在这类对手面前【不适用】。

五、防御

既然"人会看仔细"和"我们的工具是干净的"都不能依赖,防御只能是结构性的。

① 白名单 + 禁止 delegatecall(最关键的一条)

⭐ 冷钱包应该被配置成:

   □ 只能向【预先设定的白名单地址】转账
   □ ⭐⭐ 完全禁止 operation = 1(DELEGATECALL)
   □ 白名单本身的变更走【独立的、更长的】时间锁

⟹ 在这个配置下,第 ⑤ 步会直接 revert。
   ⭐ 14.6 亿美元的攻击链会断在最后一环。

⚠️ Safe 支持通过守卫模块(Guard)强制这类约束。 这是本篇最可直接执行的一条。

② 时间锁

⭐ 冷钱包的任何操作,签名之后延迟 N 小时才能执行。

⟹ 在这 N 小时里:
   □ 监控可以发现"钱包的实现地址即将被改变"
   □ 团队可以撤销
   □ ⚠️ 而攻击者的窗口从"几分钟"变成"必须瞒过 N 小时"

⭐ 对冷钱包而言,延迟几乎没有业务代价 ——
   冷钱包本来就不需要实时性。

③ 完全独立的校验通道

⭐ 签名前,用一个【与钱包服务毫无关系】的工具校验:

   □ 自己写的脚本,直接读链上的待签交易
   □ 自己按 EIP-712 算哈希
   □ ⭐⭐ 特别检查 operation 字段
   □ 与硬件钱包屏幕逐字符比对

⚠️ 关键词是"毫无关系":
   不能是同一个服务提供的另一个页面,
   不能是同一个 npm 包,
   ⭐ 不能是同一批开发者维护的东西。

④ 把第三方服务列入信任基础

⭐ 画一张图:从"资金"往外,列出所有能影响它的东西。

   资金 ⟸ 冷钱包合约 ⟸ 签名 ⟸ 签名者的判断
                            ⟸ ⭐ 前端界面
                                 ⟸ 前端的托管
                                 ⟸ 前端的构建流程
                                 ⟸ ⭐ 前端开发者的机器
                                 ⟸ 前端的依赖树

⟹ ⚠️ 这张图上的每一个节点,都是你的攻击面。
⟹ 而大多数团队画到第三层就停了。

⑤ 分散,不要把所有资产放在一个可被单次操作影响的地方

□ 冷钱包分成多个,各自独立配置
□ ⭐ 单个钱包的持仓上限
□ 不同钱包用【不同的】管理方案
   ⚠️ 全部用同一个服务 ⟹ 一次供应链攻击全灭

六、⭐ 举一反三

核心命题一:你的信任基础包含你没写过的代码

⭐⭐ “我们的代码是安全的"这句话,只覆盖了攻击面的一小部分。

⭐ 完整的问题是:
   "从我的资金,往回追溯,
    有多少个实体的失误可以导致它丢失?"

⟹ Bybit 的答案里包含了
   ⚠️【一家第三方公司的一名开发者的一台笔记本】。

核心命题二:对手的类型决定威胁模型

⭐ 经济性攻击者:
   · 受"成本 < 收益"约束
   · ⟹ 提高攻击成本就能防住
   · ⟹ 大多数安全设计针对的是这一类

⚠️ 有国家背景 / 有充足资源的攻击者:
   · 不受成本约束
   · 可以潜伏很久
   · ⭐ 可以攻击供应链上游
   · 目标可能不只是钱

⟹ ⭐ 如果你管理的资产规模足够大,
   你的对手就【自动升级】成第二类 ——
   而你的防御必须相应升级。

⚠️ 很多团队的安全设计停留在第一类,
   而资产规模早已进入第二类的射程。

核心命题三:结构性防御 > 程序性防御

⭐ 两类防御的可靠性差距巨大:

   程序性(依赖人正确执行):
      · "签名前要仔细核对"
      · "定期检查权限"
      · "不要点可疑链接"
      ⟹ ⚠️ 失效概率随时间、人数、疲劳程度上升

   ⭐ 结构性(不依赖人):
      · 白名单地址
      · 禁止 delegatecall
      · 时间锁
      · 转账限额
      ⟹ ⭐ 即使所有人都犯错,它依然生效

⟹ 本篇的教训极其明确:
   ⭐⭐ 一条"禁止 delegatecall"的守卫规则,
      能挡住 14.6 亿美元的损失。
      而它是一行配置。

一条给所有人的检查

⭐ 不管你的规模多大,现在就可以做的三件事:

   ① 你的多签能不能执行 delegatecall?
      ⟹ 如果能,且业务不需要 —— ⭐ 现在就禁掉。
   ② 你的冷钱包能转到任意地址吗?
      ⟹ 如果能 —— 加白名单。
   ③ 你的签名者用什么校验交易?
      ⟹ 如果是钱包服务自己的界面 —— ⭐ 加一条独立通道。

七、本案小结

  • 有记录以来最大的单笔加密资产盗窃,约 14.6 亿美元。
  • ⭐⭐ 攻击者入侵的不是 Bybit,而是它使用的多签钱包服务的一台开发者机器,由此向前端注入恶意 JavaScript。
  • 代码带条件判断,只对 Bybit 的特定钱包地址激活——其他数万名用户看到的都是正常界面。“用户会发现异常"这条防线结构上失效。 -⭐ 钱不是被"转走"的,钱包是被"换掉"的:签名者批准的那笔交易本身没转走任何钱,它是一个 operation = 1 的 DELEGATECALL,把钱包的实现逻辑整个替换掉。真正的转账发生在之后,那时已不需要任何人签名。 -⭐ 每一层防御都在正常工作:合约无漏洞、密码学未被攻破、多签门槛正常满足、私钥始终在硬件钱包里、签名者在执行正常职责、Bybit 服务器未被入侵。唯一失守的是"签名者用来理解自己在签什么的那个界面”。 -⭐ 供应链攻击的完整形态:攻击者不攻击你,他攻击你信任的东西——而你对那个东西的信任从来没有被明确评估过。Bybit 的信任基础里包含一家第三方公司的一名开发者的一台笔记本
  • ⚠️ 有国家背景的对手不受"攻击成本 < 收益"约束,可以潜伏数月、攻击供应商的供应商。资产规模足够大时,你的对手会自动升级成这一类,而很多团队的安全设计还停留在经济性攻击者。 -⭐ 最可直接执行的一条:给冷钱包配一条"禁止 delegatecall"的守卫规则——在这个配置下第 ⑤ 步会直接 revert,14.6 亿美元的攻击链断在最后一环,而它只是一行配置。
  • 结构性防御 > 程序性防御:白名单、禁 delegatecall、时间锁、限额——即使所有人都犯错,它们依然生效。而"要仔细核对"“不要点可疑链接"的失效概率随时间和人数上升。
  • 冷钱包本来就不需要实时性,所以时间锁对它几乎没有业务代价。

思考题

  1. 为什么说"钱包是被换掉的,不是钱被转走的”?请说明 operation = 1 在这一步的作用。
  2. 逐层列出本案中"正常工作"的防御。唯一失守的是哪一环?为什么它不在传统审计范围内?
  3. 恶意代码只对特定目标激活。这个设计如何让常规的抽查和用户反馈失效?
  4. 画出 Bybit 从"资金"往外的完整信任链。你能画到第几层?
  5. 一条"禁止 delegatecall"的守卫规则如何挡住整个攻击?请写出它的实现思路。
  6. 冷钱包加时间锁的业务代价是什么?为什么说它"几乎没有代价”?
  7. “独立的校验通道"里的"独立"具体指什么?请列出三条判断标准。
  8. 区分"经济性攻击者"和"有资源的攻击者”。你的项目现在面对的是哪一类?依据是什么?
  9. 对比"程序性防御"和"结构性防御",各举三例。为什么后者更可靠?
  10. 本篇最后给了三条可以立刻做的检查。请对你自己的系统逐条回答,并把"能"的那几条变成工单。