时间 2024 年 10 月 16 日
涉案 约 $5000 万
模式 ⚠️ 与三个月前的 WazirX 高度相似
类别 C7 密钥与签名流程

一、背景:一次"没什么特别"的例行操作

Radiant 是一个跨链借贷协议,其关键权限由多签控制。攻击发生时,团队正在执行一次常规的多签操作。

⚠️ 攻击者早已在多个签名者的设备上植入了恶意软件。

⟹ 他们不需要发起任何交易,
   ⭐ 只需要【等待】团队自己发起一次多签操作,
      然后在签名的那一刻把载荷换掉。

这是一种"寄生"式的攻击:攻击者不制造异常事件,他利用一个本来就会发生的正常事件

二、⭐ 复盘里最重要的那句话

Radiant 的事后复盘提到了一个细节:

签名过程中出现了交易失败、需要重新签名的情况—— 而这在团队看来是"多签钱包的常见现象"。

这句话值得反复读。

攻击的实际过程需要:
   · 恶意载荷被签名
   · ⚠️ 而正常载荷的交易会失败
   ⟹ 于是签名者会看到"这笔交易失败了,请重签"

⭐ 这是一个【极其明确】的异常信号。

⚠️ 但它没有触发任何警觉,
   因为团队【已经习惯了】偶尔的签名失败。

异常的常态化(normalization of deviance):

一个系统里反复出现的小毛病,如果每次都"没出事", 就会逐渐从"异常"被重新分类为"正常"。 而当它某一次真的是攻击信号时,没有人会注意到。

三、为什么这个模式会重复出现

① 攻击者在复用一套已被验证的工具

⭐ WazirX(2024-07)⟹ Radiant(2024-10)⟹ [Bybit(2025-02)](https://blog.ifcalm.org/posts/security/blockchain/25-bybit/)

三起事故的核心是同一件事:
   【让签名者签署他没有看到的内容】

⚠️ 而且金额在【递增】:2.35 亿 ⟹ 5000 万 ⟹ 14.6 亿

⟹ 这说明攻击方在【迭代和复用】,
   ⭐ 而防守方在各自为战 ——
      Radiant 出事时,WazirX 的复盘已经公开三个月了。

一条实践:把同行的事故复盘当作自己的待办清单。每一份公开复盘发布后,问一句:"我们有没有同样的问题?"——这件事的成本极低,而 Radiant 本可以因此避免。

② 攻击面在"日常运维"里,而不在"上线时"

⚠️ 安全投入几乎全部集中在【上线前】:
   审计、测试、赏金。

⭐ 而这类攻击发生在【上线后的第 500 次例行操作】时。

⟹ 没有人为"第 500 次例行操作"做威胁建模。

③ 恶意软件驻留期长

攻击者在设备上潜伏了相当长的时间:
   · 观察团队的操作习惯
   · 等待一次足够有价值的多签操作
   · ⭐ 在最合适的时机才动手

⚠️ 这意味着"我们最近没发现异常"完全不构成证据 ——
   ⭐ 一个好的攻击者的定义就是"你发现不了他"。

四、防御

① 把"小毛病"当作信号来管理

⭐ 建立一条纪律:任何【计划外】的事件都必须被记录和解释。

   □ 交易失败了 ⟹ 为什么?失败原因是什么?
   □ 界面显示和预期不一致 ⟹ 停下来,查清楚
   □ ⚠️ 需要重新签名 ⟹ ⭐ 视为【安全事件】,
        而不是"再点一次"
   □ 某台设备行为异常 ⟹ 立刻从签名流程中隔离

⟹ ⭐ 关键是把默认反应从"再试一次"改成"先搞清楚"。

一个具体做法:维护一份"异常台账"。每一次计划外事件都记一行:时间、现象、解释、是否已确认根因。当同一个现象出现第三次而根因栏还是空的,那就是一个必须被处理的风险。

② 签名操作用专用的、隔离的设备

⭐ 一台"签名专用机"应该:
   □ 不用于收发邮件、浏览网页、装任何其他软件
   □ ⭐ 系统从只读介质启动,每次使用后重置
   □ 与办公网络物理隔离
   □ ⚠️ 校验 calldata 的那台设备,
        必须和发起交易的那台【不是同一台】

⟹ 恶意软件的立足点被消除之后,
   [第 23 篇](https://blog.ifcalm.org/posts/security/blockchain/23-wazirx/)的整个攻击链就断了。

③ 多人独立校验,且结果要交叉比对

⭐ 不要让所有签名者用同一个流程:

   签名者 A:用工具 X 解析 calldata
   签名者 B:⭐ 用工具 Y 独立解析
   ⟹ 两人报出的【解析结果】必须一致

⚠️ 如果所有人都用同一个前端,那么
   "多人校验"只是把同一个错误看了多遍。

④ 假设终端已被攻破,然后设计

⭐ 把"我们的设备可能已经被入侵"当作【前提】而不是【风险】:

   □ 大额转账只能转到白名单地址
      ⟹ 即使签了恶意交易,钱也去不了攻击者的地址
   □ ⭐ 时间锁 ⟹ 恶意交易签出后还有 N 小时可以撤销
   □ 独立的监控(跑在另一套基础设施上)
      ⟹ 检测到异常自动触发暂停
   □ ⚠️ 定期轮换密钥与设备

⭐⭐ 这是第 23 篇那条结论的强化版不要依赖"人会看仔细",也不要依赖"我们的设备是干净的"。 设计要能在这两条都不成立时仍然保护资金。

五、⭐ 举一反三

核心命题一:异常的常态化

⭐⭐ 安全事故最可靠的前兆,是一个被大家习惯了的小毛病。

⚠️ 在你的系统里找找这些"大家都知道、没人当回事"的现象:

   · "这个告警经常误报,忽略就行"
      ⟹ ⭐ 那么真的告警来的时候呢?
   · "这个测试偶尔会挂,重跑一下"
      ⟹ 它可能在告诉你一个真实的竞态
   · "那个余额对不上一点点,正常"
      ⟹ ⭐ 一点点是多少?为什么?
   · "这个接口有时候超时,重试就好"
   · "签名有时候失败,重签"          ⟹ 本篇
   · "部署脚本第一次总是失败"

⭐ 判据:任何你能说出"这个一直这样"的现象,
   而你【说不出根因】—— 那就是一个未被理解的风险。

核心命题二:把同行的复盘当作自己的待办

⭐ 一条低成本、高回报的流程:

   每当一份公开的事故复盘发布:
      ① 读完
      ② ⭐ 逐条问:"我们有没有同样的问题?"
      ③ 把"有"的那几条变成工单
      ④ ⚠️ 把"没有"的那几条写下理由 ——
         因为半年后情况可能变了

⟹ Radiant 出事时,WazirX 的复盘已经公开三个月。

这个档案本身就是为这个用途准备的——上线前检查清单把 29 起事故压缩成了一份可以逐条打勾的表。

核心命题三:为"第 500 次操作"做威胁建模

⭐ 安全评估通常覆盖"系统上线"这个时刻,
   ⚠️ 而攻击往往发生在"日常运维"中。

⟹ 需要单独建模的运维场景:
   □ 例行的参数调整
   □ ⭐ 例行的多签操作(本篇、[第 23 篇](https://blog.ifcalm.org/posts/security/blockchain/23-wazirx/)、[第 25 篇](https://blog.ifcalm.org/posts/security/blockchain/25-bybit/))
   □ 合约升级
   □ 新增/下架资产
   □ 密钥轮换(⚠️ 轮换过程本身是一个窗口)
   □ 人员入职/离职
   □ ⭐ 应急响应演练本身(它需要高权限)

六、本案小结

  • 攻击手法与三个月前的 WazirX 几乎一样:多个签名者的设备被植入恶意软件,前端显示正常而签出的是攻击载荷。
  • “寄生"式攻击:攻击者不制造异常事件,他等待并利用一个本来就会发生的正常事件——一次例行的多签操作。
  • 复盘里最重要的一句:签名失败需要重签,在团队看来是"多签钱包的常见现象”。 这是一个极其明确的异常信号,但它没有触发任何警觉,因为团队已经习惯了偶尔的签名失败。 -⭐ 异常的常态化:一个反复出现的小毛病,如果每次都"没出事",就会从"异常"被重新分类为"正常"——而当它某一次真的是攻击信号时,没有人会注意到。
  • ⚠️ WazirX(7 月)→ Radiant(10 月)→ Bybit(次年 2 月),金额递增:攻击方在迭代复用一套已验证的工具,而防守方在各自为战——Radiant 出事时 WazirX 的复盘已公开三个月。
  • 把默认反应从"再试一次"改成"先搞清楚":维护一份异常台账,同一现象出现第三次而根因栏还是空的,就是一个必须处理的风险
  • 签名专用机:不收邮件、不上网、只读介质启动、与办公网物理隔离,且校验 calldata 的设备不能是发起交易的那台
  • ⚠️ 多人校验必须用不同的工具——所有人用同一个前端时,“多人校验"只是把同一个错误看了多遍。 -⭐ 假设终端已被攻破,然后设计:白名单地址、时间锁、独立基础设施上的监控。不要依赖"人会看仔细”,也不要依赖"我们的设备是干净的"。
  • 安全评估覆盖的是"上线",而攻击发生在"第 500 次例行操作"——运维场景需要单独建模。

思考题

  1. 为什么说这是"寄生式攻击"?它和主动发起交易的攻击相比,在检测上有什么不同?
  2. “签名失败需要重签"为什么是一个明确的异常信号?请解释攻击过程中它为什么会出现。
  3. 在你的系统里找出三个"这个一直这样、但说不出根因"的现象。逐个尝试解释。
  4. 设计一份"异常台账"的字段。什么条件下一条记录应该升级为安全事件?
  5. 一台"签名专用机"的完整配置要求是什么?请写出一份可执行的清单。
  6. 为什么"校验 calldata 的设备必须和发起交易的不是同一台”?如果是同一台会怎样?
  7. “多人校验必须用不同的工具”——请设计一个具体方案,说明两个人分别用什么。
  8. 在"我们的设备已经被入侵"这个前提下重新评估你的多签流程。哪些防御还站得住?
  9. 设计一个"读同行复盘 → 转成工单"的流程。谁负责?多久一次?产出是什么?
  10. 列出五个需要单独做威胁建模的运维场景,为其中一个写出完整的威胁模型。