用于检测变形智能合约的工具

  • a16z
  • 更新于 2024-10-31 11:41
  • 阅读 358

变形智能合约指的是在合约地址上的代码会被修改。 本文介绍一个工具用于检测变形智能合约

作者:Michael Blau

以太坊安全的一个关键假设是智能合约代码是不可变的,因此一旦部署到区块链上就无法更改。然而,实际上,一些智能合约 可以 更改——即使在它们已经部署之后。通过一些巧妙的技巧,你可以创建变形智能合约,使其“ 变形 ”成其他东西——通过了解是什么使它们成为可能,你可以检测到它们。

变形(Metamorphic)智能合约是可变的,这意味着开发者可以更改其中的代码。这些智能合约对 web3 用户构成了严重风险,因为用户信任的代码应该以绝对一致性运行,尤其是当不法分子可以利用这种变形能力时。想象一下,攻击者使用这种技术来“拉地毯”那些在他们没有意识到是变形的智能合约中质押代币的人。基于此类前提的攻击可能会使骗子能够猎取人们,并普遍破坏对去中心化系统全部承诺的信任。

为了分析智能合约是否包含变形属性,我构建了一个简单的变形合约检测器 (灵感来自并基于 Jason Carver0age其他人的原始工作)。任何人都可以使用该工具检查给定合约是否显示出可能表明变形潜力的标记。该方法并不万无一失:仅仅因为智能合约显示出一个标志,并不意味着它一定是变形的;而且即使没有显示,也不意味着它是安全的。检查器仅提供一个初步评估,表明合约_可能_是变形的,基于可能的指标。

Web3 用户应该熟悉变形合约带来的威胁,以便他们能够注意并避免可能的攻击。钱包和区块链索引器可以通过在用户与可能包含变形属性的智能合约交互之前发出警告来提供帮助。此工具旨在帮助人们了解这一潜在威胁……并防御它。

检测变形智能合约

我构建的变形合约检测器分析了六个可能表明智能合约是否变形的属性。

  1. 是否使用已知的变形代码部署了合约? 如果已知的变形字节码——以太坊智能合约通常用 Solidity 编写,编译后转化为的低级虚拟机可读代码——出现在给定智能合约的部署交易中,那就是一个主要的红旗。在接下来的部分中,我们将讨论由 0age 开发的一个变形字节码示例。一个重要的警告:变形字节码可能有无数种变体,这使得检测所有种类变得困难。然而,通过扫描众所周知的实例,检测器消除了那些仅仅复制粘贴现有示例的攻击者的低垂果实。
  2. 智能合约代码是否可以自毁? 要替换合约中的代码——创建变形合约的关键步骤——开发者首先需要删除现有代码。唯一的方法是使用 SELFDESTRUCT 操作码 ,这是一种命令,正如其名所示——它会擦除给定合约地址的所有代码和存储。合约中存在自毁代码并不能证明它是变形的;然而,它提供了一个线索,表明合约_可能_是变形的,无论如何,知道你依赖的合约是否可以自毁是值得的。
  3. 智能合约是否从其他地方调用代码? 如果相关智能合约不能直接自毁,它仍然可以通过使用 DELEGATECALL 操作码来擦除自己。此操作码允许智能合约动态加载和执行存在于另一个智能合约中的代码。即使智能合约不包含 SELFDESTRUCT 操作码,它也可以使用 DELEGATECALL 从其他地方加载自毁代码。虽然 DELEGATECALL 功能并不直接表明智能合约是否变形,但它是一个可能的线索——以及值得注意的潜在安全问题。请注意,此指示器可能会引发许多误报。
  4. 另一个合约是否部署了此合约? 变形合约_只能_由其他智能合约部署。这是因为变形合约是由另一个操作码启用的,该操作码只能由其他智能合约使用,称为 CREATE2。(我们将在后面的部分中讨论 CREATE2——它如何工作以及为什么重要。)此特征是可能变形的最不显眼的指标之一;它是一个必要但不充分的前提条件。扫描此特征可能会引发许多误报——但它是有价值的信息,因为它可以引起怀疑,并提供进一步审查合约的理由,尤其是如果智能合约包含下一个描述的操作码。
  5. 部署者合约是否包含 CREATE2 操作码? 如上所述,通过 CREATE2 部署是变形的一个基本前提。如果部署者合约包含 CREATE2 操作码,这可能表明它使用 CREATE2 部署了相关合约。如果部署者确实使用 CREATE2 部署了该合约,虽然这并不意味着合约一定是变形的,但这意味着它_可能_是变形的,可能明智的做法是谨慎行事并进一步调查。再次注意误报:CREATE2 有很多合法用途 ,包括加强 “Layer 2”扩展解决方案并使创建智能合约钱包更容易,从而改善 web3 用户引导和密钥恢复选项。
  6. 代码是否更改? 这是最明显的标志,但只有在变形合约已经变形后才会出现。如果智能合约的代码哈希——一个独特的加密标识符——与合约最初部署时不同,那么很可能代码已被删除、替换或更改。如果哈希不再匹配,那么代码的某些部分已更改,合约可能是变形的。此标志是变形的最可靠指示器,但它无法预测或预防变形,因为它只检查已经发生的情况。

除了为变形合约检测器构建一个简单的命令行工具外,我还构建了一些示例智能合约,展示了一个骗局变形合约质押场景,我将在下一节中描述。所有代码都可以在这个 GitHub 仓库中找到。

恶意行为者如何利用变形合约窃取资金

以下是某人可能使用变形智能合约进行诈骗的方式。

首先是设置阶段。攻击者使用两种工具在区块链上的特定地址部署一个智能合约:变形字节码和 CREATE2 操作码。(我们稍后会详细介绍这两个概念。)变形字节码然后如其名所示,“变形”。在这里,它变成了一个质押合约 ,用户可以在其中质押 ERC-20 代币。(再次强调,我们稍后会讨论这种变形技巧的细节。保证!)

接下来是诱饵和转换。毫无戒心的用户在这个合约中质押他们的代币,被可能获得收益或其他好处所吸引。然后,攻击者使用 SELFDESTRUCT 操作码删除所有质押代码和“状态”——区块链存储或内存——在这个智能合约地址。(需要注意的是,代币——作为一个独立的 ERC-20 合约的一部分——仍然存在,不受自毁合约的影响。)

最后是拉地毯。攻击者重新使用设置阶段使用的相同变形字节码“重新部署”一个新合约。这个新合约部署到刚刚被自毁合约腾出的相同地址。然而,这次字节码“变形”(再次强调,我们稍后会解释如何实现)成一个恶意合约,可以窃取在合约地址质押的所有代币。诈骗完成。

变形智能合约带来的风险现在显而易见。但你可能仍然想知道,这种变形技巧究竟是如何工作的?要理解这一点,你必须深入探究字节码层面。

CREATE2 如何开启变形的可能性

CREATE2是一个操作码升级, 于 2019 年 2 月引入以太坊 ,提供了一种新的部署智能合约的方式。

CREATE2 给开发者提供了比以前更多的控制权来部署他们的智能合约。原始的 CREATE 操作码使得开发者难以控制待部署智能合约的目标地址。使用 CREATE2,人们可以在实际部署到区块链之前控制并知道特定智能合约的地址。这种预先知识——加上一些巧妙的技巧——使得人们能够创建变形智能合约。

CREATE2 如何预测未来?操作码的计算是确定性的:只要输入不变,CREATE2 确定的地址就不会改变。(即使是最小的变化也会导致部署到其他地方。)

更具体地说,CREATE2 是一个将几个元素组合并哈希在一起的函数。首先,它包含部署者(或发送者)的地址:作为父合约的发起智能合约。接下来,它添加一个由发送者提供的任意数(或“盐”),这允许开发者将相同的代码部署到不同的地址(通过更改盐)并防止覆盖现有的相同合约。最后,它使用一些智能合约初始化(“init”)字节码的 keccak256 哈希,这是变成新智能合约的种子。这个哈希组合确定了一个以太坊地址,然后将给定的字节码部署到该地址。只要字节码完全相同,CREATE2 将始终将给定的字节码部署到区块链上的相同地址。

以下是 CREATE2 公式的样子。(注意:你会在下面的例子中注意到另一个元素“0xFF”。这是 CREATE2 用来防止与前面的 CREATE 操作码冲突的常量。)

现在我们有了一种将代码部署到确定性地址的方法,如何在同一地址_更改_代码呢?起初,这似乎是不可能的。如果你想使用 CREATE2 部署新代码,字节码必须改变,因此,CREATE2 将部署到不同的地址。但如果开发者以某种方式构造字节码,使其在 CREATE2 部署智能合约时可以“变形”成不同的代码呢?

变形合约实际上是如何工作的

将智能合约变成变形合约的配方总共需要三个智能合约,每个合约扮演独特的角色。

其中一个必要组件是变形合约工厂,操作的核心。这个“工厂”负责部署变形合约以及另一个称为实现合约的智能合约,因为它的代码最终会在变形合约中实现。这三个合约之间的微妙配合导致了变形,如下图所示。让我们详细讨论每个步骤,1-7,以阐明其中的操作。

步骤 1:开发者启动一切

编码人员设计了一些智能合约代码——实现合约字节码——最终会出现在变形合约中。开发者将这段代码发送到变形合约工厂,这是一个主要目的是部署其他智能合约的智能合约。这个动作启动了整个变形合约创建过程。接下来的所有步骤都是这一初始步骤的结果。实际上,步骤 1 到 6 在区块链上几乎是一个原子交易,意味着几乎同时发生。这些步骤可以一遍又一遍地重复,无限次地替换变形合约中的代码,使其不断变形。

步骤 2:工厂部署实现合约

工厂部署的第一个合约是实现合约,包含实现代码。(我们知道,这很有创意。)将实现合约视为一个装载码头或中转站,持有一些代码,然后将其发送到最终目的地,在这种情况下,就是变形合约内部。

步骤 3:工厂存储实现合约地址

在区块链上部署后,实现合约必然存在于某个区块链地址。工厂将这个合约地址存储在自己的内存中(稍后在步骤 5 中使用)。

步骤 4:工厂部署变形合约

工厂使用 CREATE2 和变形字节码部署变形合约。你可以在这里 查看变形字节码是如何工作的。 但可以肯定地说,当变形字节码执行时,它会将代码从其他链上位置(在本例中是从实施合约)复制到变形合约中。正如我们在上一节中讨论的那样,由于 CREATE2 是确定性的(只要使用相同的发送者、盐和字节码),那么无论重复这些步骤多少次,变形合约地址都保持不变。下面是变形字节码的示例,来自 0xage 的 metamorphic repo。这只是变形字节码的一个例子——可能存在无数种变体,极大地增加了变形合约的检测难度。

步骤 5:变形字节码向工厂查询实现合约地址

变形字节码向工厂请求实现合约地址(如步骤 3 中存储的)。只要请求地址的变形字节码保持不变,实现合约的地址是否更改并不重要。实际上,如果开发者后来部署了一个新的实现合约——例如一个旨在窃取代币的恶意合约——它必然会在不同的区块链地址上部署,如步骤 2 所述。这对变形合约的创建没有影响。

步骤 6: 实现合约代码被复制到变形合约中

使用在步骤 5 中获取的区块链地址,变形字节码定位实现合约中的代码,并将该代码复制到变形合约的本地存储中。这就是变形合约如何变形的:通过从实现合约中复制代码。

步骤 7:重复操作

开发者可以一遍又一遍地重复步骤 1 到 6,并通过新的实现合约将变形合约中的代码替换为他们喜欢的任何代码。所需的只是使用 SELFDESTRUCT 操作码——或者更狡猾地,使用最终导致 SELFDESTRUCT 的 DELEGATECALL 操作码——来移除变形合约中现有的代码。通过用新的实现合约字节码重复这个循环,变形合约将如同魔法般变形!

使用这种创建变形合约的技术,聪明的开发者可以不断地在 web3 用户的脚下变换基础。再次考虑诈骗场景。开发者可能首先部署一个包含代币质押代码的实现合约,通过图中所示的迂回路径并在上述步骤中详细说明,最终进入变形合约。诈骗者可以随后自毁此代码,并通过部署一个包含代币窃取代码的新实现合约来替换它。

无论在实现合约中部署什么,最终都会进入变形合约。这就是这个技巧的本质。

***

变形智能合约打破了隐含的 web3 社会契约,即所见即所得。类似于三杯藏球游戏使用三个移动的杯子来隐藏一个球,三个合约在创建变形合约时的相互作用使得很难跟踪合约的真实功能。三杯藏球游戏是一个特别恰当的比较,因为信心骗子通常会使用手法和误导来确保他们获胜。在 web3 版本中,变形合约编写者可以类似地让“球”——即实现代码——消失(即:自毁),并可以用他们喜欢的任何东西替换它。

变形合约的存在意味着 web3 用户可能会进入可以随意更改的合约——这就是为什么理解和防御这一威胁如此重要的原因。我的变形合约检测器只是识别变形合约所用手法的第一步。未来有几种方法可以改进检测器。例如,通过递归检查创建变形合约的工厂(或部署者合约),可以查看工厂本身是否是变形的。此功能将是检测器升级版 2 的一个有用补充。

值得再次重申:这个检测工具并不是万无一失的。它捕捉到的标志并不都是变形潜力的明显迹象,但它们确实提供了线索。识别这些标志只是更彻底调查的开始。这就是为什么我们扩展了检测器以搜索可能容易产生误报的标志,例如 CREATE2 或 DELEGATECALL 操作码的存在。如果你有改进工具的建议或想要在此初步工作基础上进行构建或添加,请通过 mblau@a16z.com 与我联系。

使用检测工具分析智能合约的变形特征,并访问 GitHub 仓库了解更多

编辑:Robert Hackett @rhhackett

我是 AI 翻译官,为大家转译优秀英文文章,如有翻译不通的地方,在这里修改,还请包涵~

点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

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