变形智能合约指的是在合约地址上的代码会被修改。 本文介绍一个工具用于检测变形智能合约
作者:Michael Blau
以太坊安全的一个关键假设是智能合约代码是不可变的,因此一旦部署到区块链上就无法更改。然而,实际上,一些智能合约 可以 更改——即使在它们已经部署之后。通过一些巧妙的技巧,你可以创建变形智能合约,使其“ 变形 ”成其他东西——通过了解是什么使它们成为可能,你可以检测到它们。
变形(Metamorphic)智能合约是可变的,这意味着开发者可以更改其中的代码。这些智能合约对 web3 用户构成了严重风险,因为用户信任的代码应该以绝对一致性运行,尤其是当不法分子可以利用这种变形能力时。想象一下,攻击者使用这种技术来“拉地毯”那些在他们没有意识到是变形的智能合约中质押代币的人。基于此类前提的攻击可能会使骗子能够猎取人们,并普遍破坏对去中心化系统全部承诺的信任。
为了分析智能合约是否包含变形属性,我构建了一个简单的变形合约检测器 (灵感来自并基于 Jason Carver、0age和其他人的原始工作)。任何人都可以使用该工具检查给定合约是否显示出可能表明变形潜力的标记。该方法并不万无一失:仅仅因为智能合约显示出一个标志,并不意味着它一定是变形的;而且即使没有显示,也不意味着它是安全的。检查器仅提供一个初步评估,表明合约_可能_是变形的,基于可能的指标。
Web3 用户应该熟悉变形合约带来的威胁,以便他们能够注意并避免可能的攻击。钱包和区块链索引器可以通过在用户与可能包含变形属性的智能合约交互之前发出警告来提供帮助。此工具旨在帮助人们了解这一潜在威胁……并防御它。
我构建的变形合约检测器分析了六个可能表明智能合约是否变形的属性。
除了为变形合约检测器构建一个简单的命令行工具外,我还构建了一些示例智能合约,展示了一个骗局变形合约质押场景,我将在下一节中描述。所有代码都可以在这个 GitHub 仓库中找到。
以下是某人可能使用变形智能合约进行诈骗的方式。
首先是设置阶段。攻击者使用两种工具在区块链上的特定地址部署一个智能合约:变形字节码和 CREATE2 操作码。(我们稍后会详细介绍这两个概念。)变形字节码然后如其名所示,“变形”。在这里,它变成了一个质押合约 ,用户可以在其中质押 ERC-20 代币。(再次强调,我们稍后会讨论这种变形技巧的细节。保证!)
接下来是诱饵和转换。毫无戒心的用户在这个合约中质押他们的代币,被可能获得收益或其他好处所吸引。然后,攻击者使用 SELFDESTRUCT 操作码删除所有质押代码和“状态”——区块链存储或内存——在这个智能合约地址。(需要注意的是,代币——作为一个独立的 ERC-20 合约的一部分——仍然存在,不受自毁合约的影响。)
最后是拉地毯。攻击者重新使用设置阶段使用的相同变形字节码“重新部署”一个新合约。这个新合约部署到刚刚被自毁合约腾出的相同地址。然而,这次字节码“变形”(再次强调,我们稍后会解释如何实现)成一个恶意合约,可以窃取在合约地址质押的所有代币。诈骗完成。
变形智能合约带来的风险现在显而易见。但你可能仍然想知道,这种变形技巧究竟是如何工作的?要理解这一点,你必须深入探究字节码层面。
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 与我联系。
编辑:Robert Hackett @rhhackett
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!