以太坊代理中的恶意后门

以太坊代理中的恶意后门,这篇文章详细说明如何利用智能合约可升级性的代理模式。

我们最近审核了ZeppelinOS的初始版本,发现了代理模式中的一个漏洞,该漏洞用于实现几乎所有可升级的智能合约。

此漏洞允许攻击者隐藏可能很难发现的恶意代码,而无需深入了解Solidity和Proxy Pattern的工作原理。这已在ZeppelinOS上修复。

Solidity函数调用internals

用Solidity写的简单智能合约

如果你是以太坊的开发人员,那么你最有可能在Solidity方面编写和考虑你的智能合约,但这并不是网络如何与他们合作。

从网络的角度来看,智能合约是一个与其相关联的单个代码块的帐户。如果任何其他帐户向合约发送消息,其代码将在EVM上执行。

那么如果合约只有一段连续的代码,如何调用不同的函数呢?

以太坊定义了其组件之间通信的标准方式,即应用程序二进制接口或简称ABI。你可以将其视为低级API,不仅指定系统中可用的功能,还指定我们通常认为合理的工作量。其中一些是如何调用函数,如何传递参数以及它们如何返回值。

以太坊ABI规定你的交易的数据参数必须以函数选择器开始,该函数选择器标识你尝试调用的方法。使用选择器,合约的代码会跳转到实现你尝试调用的函数的部分。

函数选择器只是函数签名的sha3哈希的前四个字节。例如,get的选择器计算为sha3(“get()”)[0:4],它给出了0x6d4ce63c。类似地,set的一个是sha3的结果sha3(“set(uint256)”)[0:4]

函数选择器只有一个例外,那就是每个智能合约中存在的回退函数,它没有选择器。当没有提供data参数时,或者当给定的选择器与任何合约的方法都不匹配时,它具有被调用的特殊行为。

重新访问代理模式

关于代理模式,它的不同变化和它们的权衡,已经写了很多。无论你选择哪种代理模式,其核心功能都是相同的:它将收到的所有消息转发给当前的合约实现。

我们来看看它是如何工作的。

别担心,你不需要了解那个可怕的装配块是如何工作的。它将当前消息转发给实现,向它发送完全相同的data参数。

将转发逻辑放在回退功能中允许我们将任何呼叫转发到代理Proxy,据说。事实证明,这并不总是发生。

代理Proxy还需要自己的元功能,因为它需要可升级。因此,如果存在并且不执行回退功能,则不会转发implementation()proxyOwner()等函数。

代理选择器冲突

作为一个聪明的以太坊开发者,你可能已经意识到,代理商合约中的选择器与实现合约中的选择器匹配的任何函数都将被直接调用,完全跳过实现代码。

因为函数选择器使用固定数量的字节,所以总是存在冲突的可能性。这不是日常开发的问题,因为Solidity编译器将检测合约中的选择器冲突,但是当选择器用于交叉合约交互时,这变得可利用。可以滥用冲突来创建一个看似很好的合约,实际上隐藏了一个后门。

使用一些防锈代码,我们发现clash550254402()proxyOwner()具有相同的选择器。在新的Macbook Pro中用不到15分钟的时间才能找到它。有动力的黑客可以优化流程并投入更多资源来寻找离散的功能名称。

可利用性

代理模式是在以太坊生态系统中使用的当前方法,以使智能合约可升级,选择器冲突攻击允许使用它的任何项目,或者获得访问升级机制的攻击者,部署隐藏恶意功能的代码。

例如,大多数可升级性实现都有一些状态迁移的概念,这些功能可以升级合约的存储。这些对于伪装选择器冲突特别有用,因为自动生成的字符串(如提交号)可以是这些函数的可接受名称,使选择器冲突攻击易于伪装。

在我们对ZeppelinOS进行的安全审计的背景下,我们发现这可以被任何人利用,而不仅仅是代理所有者,因为他们打算让网络的任何用户部署实现供其他用户使用。作为另一个例子,似乎根本不应该移动资金的函数调用实际上根本不会被调用,窃取某人的钱。

提出的解决方案

在我们发现此漏洞之前,来自Zeppelin的Francisco Giordano已经在开发Transparent Proxies。这是一种改进的技术,旨在让实现合约使用与Proxy相同的函数名,而不会出现选择器冲突。这消除了攻击。

这些新代理通过转发任何呼叫来工作,只要它们不是来自代理所有者。冲突仍然存在,但如果呼叫者是Proxy所有者以外的任何人,则转发呼叫。这使得代理所有者成为唯一可能陷入冲突的帐户,因此用户不会受到隐瞒。

唯一的缺点是其他用户将无法使用其ABI读取代理Proxy自己的状态(即所有者和实现)。他们需要使用web3.eth.getStorageAt()代替。这是一个相当小的代价,可以确保可升级合约完全符合其实现源代码所显示的内容。

练习

对于那些想要深入挖掘如何利用这个漏洞的人,我们整理了一个小练习。你的任务是试图在合约中窃取ropsten-ETH,并弄清楚发生了什么。请记住,这是一个代理合约,所以你也应该看看它的实现。

你可以用这些合约做任何你想做的事情,只是不要完全清空它的平衡,这样其他人也可以玩。

笔记

1.消息是帐户之间的通信方式。发送交易时,你正在向另一个帐户发送消息。当发件人是合约时,它们通常被称为内部交易。 2.消息实际上不像传统代理那样转发。发生的事情是我们执行实现的代码就好像它是代理通过委托调用delegatecall一样。

======================================================================

分享一些以太坊、EOS、比特币等区块链相关的交互式在线编程实战教程:

  • java以太坊开发教程,主要是针对java和android程序员进行区块链以太坊开发的web3j详解。
  • php以太坊,主要是介绍使用php进行智能合约开发交互,进行账号创建、交易、转账、代币开发以及过滤器和交易等内容。
  • python以太坊,主要是针对python工程师使用web3.py进行区块链以太坊开发的详解。
  • 以太坊入门教程,主要介绍智能合约与dapp应用开发,适合入门。
  • 以太坊开发进阶教程,主要是介绍使用node.js、mongodb、区块链、ipfs实现去中心化电商DApp实战,适合进阶。
  • ERC721以太坊通证实战,课程以一个数字艺术品创作与分享DApp的实战开发为主线,深入讲解以太坊非同质化通证的概念、标准与开发方案。内容包含ERC-721标准的自主实现,讲解OpenZeppelin合约代码库二次开发,实战项目采用Truffle,IPFS,实现了通证以及去中心化的通证交易所。
  • C#以太坊,主要讲解如何使用C#开发基于.Net的以太坊应用,包括账户管理、状态与交易、智能合约开发与交互、过滤器和交易等。
  • EOS教程,本课程帮助你快速入门EOS区块链去中心化应用的开发,内容涵盖EOS工具链、账户与钱包、发行代币、智能合约开发与部署、使用代码与智能合约交互等核心知识点,最后综合运用各知识点完成一个便签DApp的开发。
  • 深入浅出玩转EOS钱包开发,本课程以手机EOS钱包的完整开发过程为主线,深入学习EOS区块链应用开发,课程内容即涵盖账户、计算资源、智能合约、动作与交易等EOS区块链的核心概念,同时也讲解如何使用eosjs和eosjs-ecc开发包访问EOS区块链,以及如何在React前端应用中集成对EOS区块链的支持。课程内容深入浅出,非常适合前端工程师深入学习EOS区块链应用开发。
  • java比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Java代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Java工程师不可多得的比特币开发学习课程。
  • php比特币开发教程,本课程面向初学者,内容即涵盖比特币的核心概念,例如区块链存储、去中心化共识机制、密钥与脚本、交易与UTXO等,同时也详细讲解如何在Php代码中集成比特币支持功能,例如创建地址、管理钱包、构造裸交易等,是Php工程师不可多得的比特币开发学习课程。
  • tendermint区块链开发详解,本课程适合希望使用tendermint进行区块链开发的工程师,课程内容即包括tendermint应用开发模型中的核心概念,例如ABCI接口、默克尔树、多版本状态库等,也包括代币发行等丰富的实操代码,是go语言工程师快速入门区块链开发的最佳选择。

汇智网原创翻译,转载请标明出处。这里是以太坊代理中的恶意后门