薛定谔的 NFT、焚烧炉 SPL 代币程序和皇家同花顺攻击!

  • oshield
  • 发布于 2022-06-16 15:30
  • 阅读 24

SolShield 团队披露了 SPL token 程序中的一个严重漏洞,以及 SolSea 程序中的多个 bug。攻击者可以利用这些漏洞的组合,导致价值 1500 万美元的 NFT 和代币丢失,最终代币可能处于半死不活的状态,类似于薛定谔的猫悖论,被称为“薛定谔的 NFT”。

薛定谔的 NFT,一个焚化炉 SPL 代币程序,以及皇家同花顺攻击!

SolShield 团队很高兴发布 SPL 代币程序 中一个严重漏洞的披露报告,以及 SolSea 程序中的许多漏洞,这些漏洞自那时起已成功移除。

在发现时,这些漏洞的独特组合可能导致价值 1500 万美元 的 NFT 和代币损失。代币可能最终处于一种悬而未决的状态,其所有者将永久无法访问,而 NFT 的铸币账户将处于不一致的状态,仍然显示供应量为 1。我们将这种代币称为 薛定谔的 NFT,因为它是一种半烧毁、半活跃的代币,类似于臭名昭著的悖论。

总而言之,这两个程序总共存在 三个 严重问题,这些问题可能被利用,导致在没有适当授权的情况下损失 NFT 和资金。在这里,我们将深入研究每个问题,并详细说明发现过程,以全面造福 Solana 开发者社区。我们感谢 SolSea 采取主动审计其程序,并帮助分享这些发现,以造福其用户和整个 Solana 生态系统。

准备

SPL 代币程序漏洞

关闭账户指令无法正确关闭代币账户!

未能安全关闭程序账户可以说是 Solana 编程中最常见和最糟糕的安全隐患之一。关闭账户的推荐方法(不考虑使用账户鉴别器的 Anchor 框架)是将账户余额(lamport = 0)和账户数据(data = [0; ACCOUNT_SIZE])都归零。

下面的代码片段取自 SPL 代币程序 v3.2 的漏洞版本。我们注意到,在第 27-28 行中,账户余额设置为 0,符合上述第一个条件。但是,代币账户数据根本没有归零!

这是很麻烦的,因为关闭的账户仍然是一个有效的代币账户,具有正确的账户数据结构。因此,事务中的后续指令可以修改其状态。

例如,SPL 代币程序 v3.2 将在集群上成功处理以下事务。在这里,Alice 正在将代币从她的账户发送到 Bob 拥有的一个已经关闭的账户!

Transaction #signer: Aliceix0 - 创建辅助代币账户 T1
ix1 - 为 NFT mint N 初始化 T1,并以 Alice 作为所有者
ix2 - 关闭代币账户 T1 --> [T1 仍然是一个有效的代币账户]
ix3 - 将 T1 的所有权从 Alice 更改为 Bob
ix4 - 将 NFT 从 Alice 关联的代币账户 ATA 转移到 T1

在事务结束时,由于 T1 没有余额,因此它会与其中的 NFT 一起从链中清除。请注意,mint 账户根本没有更改,保持与之前相同的供应量。

因此,看起来我们将良性的代币程序变成了一个焚化炉!我们将在皇家同花顺攻击中再次回到这个概念。

一个简短的序曲

在继续讨论我们在 SolSea 程序中发现的漏洞之前,让我们先了解一下它的内部工作流程。我们对链上交易的初步检查表明,该程序有 3 个基本指令:

##0 instruction Init - 通过创建一个由程序拥有的新账户并在其中存储相关信息(例如初始所有者、价格、mint 地址等)来列出 NFT。NFT 被转移到由 PDA 拥有的新代币账户以进行托管。 #1 instruction Delist - 通过将代币转账回之前创建的托管账户中保存的原始账户来取消列表。 #2 instruction Buy - 在收取市场费用和创建者版税后,将 NFT 换成卖家要求的 SOL 价格。

由于我们无法获得程序源代码,因此我们开发了一个模糊测试工具,通过使用随机生成的数据调用程序的指令来测试潜在的错误。该过程成功揭示了许多安全隐患,这些隐患被用于伪造具有意外账户修改的交易。

在分析这些异常情况时,我们发现该程序容易受到攻击,这些攻击可能导致用户永久丢失其 NFT 或无法取回它们。

接下来,让我们简要回顾一下最关键的错误。

Solsea 漏洞 #1Delist 指令 (#1) 缺少签名者检查

SolSea 程序的 delist 指令未正确检查签名者,即该指令唯一需要的签名者是费用支付者。一个敏锐的观察者会注意到,这将允许任何人在没有适当授权的情况下取消任何列表。起初,这似乎是一个良性的缺失断言,因为无论费用支付者是谁,代币最终都会落入由初始化器拥有的账户中。因为该程序正确检查了给定目标代币账户的所有者是否为初始所有者的关键条件。此外,人们总是可以重新列出代币,从而使该问题无关紧要。

也就是说,此漏洞与 SPL 代币程序漏洞相结合,可能会使所有者收回上市代币的权限面临风险 - 更多内容将在本文后面介绍。

Solsea 漏洞 #2经典重新初始化

从 SolSea 网站列出 NFT 会将 4 个指令打包到一个事务中,顺序如下:

ix #0 -- 创建由 SolSea 程序拥有的托管账户
ix #1 -- 创建辅助代币账户 T0
ix #2 -- 使用要列出的 mint 和托管账户 PDA 作为所有者来初始化代币账户 T0
ix #3 -- 调用 SolSea 程序的 Init 指令 (#0) 以存储必要的数据

但当时,没有任何约束来遵守这种结构,因为它仅由前端强制执行,而不是由链上程序强制执行。此外,可以通过正确设置账户密钥来独立调用 SolSea 的 Init 指令 (#0)。发送仅包含单个 Init 指令的事务,我们发现没有检查托管账户是否未初始化,也没有要求其充当签名者。

因此,可以使用初始化的托管账户调用 Init 指令,并传递任意 mint 和代币账户作为参数。简而言之,任何人都可以通过将其重新初始化为新状态来修改任何托管账户。该程序只会覆盖现有数据。因此,真正的初始化器无法取消列表并取回其 NFT。

当然,有一些解决方案可以恢复这些代币,例如向 SolSea 程序添加新指令,从而支持对 SPL 代币程序的 CPI 调用。CPI 调用 Transfer 指令,为授权 PDA 签名。但是,该系统将失去大量的信任。可能授予 SolSea 的极大增加的授权级别又增加了一层中心化。即使将这两个问题放在一边,还有一个相当复杂的问题是找到托管账户的真正初始化器,因为实际的账户数据已丢失。

皇家同花顺

我们称之为皇家同花顺(双关语!)的此集合中最严重的漏洞是将上述两个漏洞放在一起的结果。该攻击利用 SPL 代币程序漏洞SolSea 漏洞 #1 来实际销毁代币。如前所述,我们将生成的代币称为薛定谔的 NFT。

该攻击遵循以下步骤。首先,攻击者创建一个代币账户,将其关闭,然后将目标账户 T 设置为其所有者。由于 SPL 代币程序漏洞,这是可能的。假设 T 之前在 SolSea 上列出了 NFT,则攻击者使用 SolSea 漏洞 #1 调用 Delist 指令,将关闭的账户设置为目标 最后,在事务完全执行后,关闭的代币账户将从状态中清除,并带走 NFT。

下面的伪事务可以更好地可视化该过程:

ix #0 - 攻击者创建一个代币账户,并将其自身初始化为所有者和一个在 SolSea 上列出的 mint。
ix #1 - 攻击者关闭代币账户。
ix #2 - 攻击者将列表初始化器设置为代币账户所有者。
ix #3 - 攻击者调用 SolSea Delist 以将 NFT 从托管转移到由初始化器拥有的已关闭代币账户。-----> 在完全执行后,带有薄荷的代币账户将从状态中清除。

在验证攻击的实用性后,我们迅速联系了 SolSea 的开发团队和 Solana 核心开发人员。两个团队都了解了这些漏洞,并立即开始研究多个修复程序。因此,关闭账户问题已在 SPL 代币程序(v3.3)的当前版本中得到修补,其中账户数据已正确归零。此外,SolSea 程序的所有两个问题现已修复。最重要的是,皇家同花顺不再适用,从而防止用户销毁其代币。

最后,特别感谢 Jordan Prince、Armani Ferrante 和 Justin Starry 帮助我们细致地处理 SPL 代币程序漏洞。我们还要感谢 SolSea 团队认真对待该问题并迅速消除这些漏洞的意愿。特别是,我们感谢 SolSea 的创始人兼 CEO Vitomir Jevremovic 的帮助和努力。

我们自己的首席开发人员 David 也是如此,他最初发现了这些错误并引起了我们的注意。

SolShield —

Solana 的顶级审计和安全服务

网站https://solshield.io

Twitterhttps://twitter.com/SolShield

电子邮件:contact@solshield.io

  • 原文链接: medium.com/@solens_io/sc...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

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