关于Parity MultiSig钱包账户冻结的分析
近日(2017年11月8号),Parity MultiSig 钱包合约再次发现重大漏洞,官方发出security alert,其中有段描述简单介绍了缘由:
Following the fix for the original multi-sig vulnerability that had been exploited on 19th of July (function visibility), a new version of the Parity Wallet library contract was deployed on 20th of July. Unfortunately, that code contained another vulnerability which was undiscovered at the time - it was possible to turn the Parity Wallet library contract into a regular multi-sig wallet and become an owner of it by calling the initWallet function. It is our current understanding that this vulnerability was triggered accidentally on 6th Nov 2017 02:33:47 PM +UTC and subsequently a user deleted the library-turned-into-wallet, wiping out the library code which in turn rendered all multi-sig contracts unusable and funds frozen since their logic (any state-modifying function) was inside the library.
All dependent multi-sig wallets that were deployed after 20th July functionally now look as follows:
This means that currently no funds can be moved out of the multi-sig wallets.
这是继7月19日被利用的原始multi-sig漏洞修复之后,新版本包含了另一个当时未被发现的漏洞:可以将Parity Wallet library合约变成一个普通的multi-sig钱包,并通过调用该initWallet函数成为其所有者。
这个漏洞是由于意外触发的,这个事件可以追溯到anyone can kill your contract #6995这个issue。
回顾一下7月的漏洞:
Parity MultiSig钱包是一个非常薄的合约,delegatecall它通过一个后备功能委托所有对主库合约的调用:
那么,只需往合约地址转账一个value = 0 ,msg.data.length > 0的交易, 执行到_walletLibrary.delegatecall的分支,该函数能无条件的调用合约内的任何一个函数,黑客调用了一个叫做initWallet的函数:
这个函数再次调用initMultiowned函数:
不幸的是,initWallet没有检查以防止攻击者在合同初始化后调用到initMultiowned, 这个函数使得这个合约的所有者被改为攻击者,相当于从unix中获得了root权限。
那么之后的事情就很清晰了,获得所有权之后传入攻击者地址,转账就好了。
修复
为了保护该initWallet方法,添加了一个modifier(Fix initialisation bug. (#6102)),以确保在执行过程中只能调用一次:
这样,如果攻击者试图通过delegatecall任何一个瘦钱包合同中的机制调用initWallet,它将被这个modifier拒绝。
新的漏洞
注意,新的modifier检查合约的store,以确定它是否已经初始化。这有效地阻止了任何initWallet已经设置的合约尝试调用initMultiowned方法中的m_numOwners。
在这种新的情况下,initWallet攻击者不是在任何钱包合约上进行调用,而是引用了library合约的 initWallet方法。这意味着:
1. library合约和任何常规合约一样,可以调用initWallet并检查modifier;
2. 由于m_numOwners为0,因为library本身从未初始化,所以modifier检查通过;
3. library中的m_owners都将重置为攻击者选择的任何初始化值。
换而言之,这个漏洞是因为共享的library不被视为区块链上拥有独立主权的合约。尽管library合约被用于在单个实例中将共享代码部署到区块链中,但它们仍然是拥有自己的数据存储的完整合约,这使得它们像其他任何合约一样,容易受到攻击。
新的攻击
这次不是针对个人钱包合约,而是攻击共享的library合约,立即影响所有依赖它的钱包合约。
攻击本身很简单:杀死library合约。这导致所有依赖它的钱包合约开始将它们的引用委托给一个没有任何代码的地址,从而变得无法执行任何操作。换句话说,所有钱包合约都立刻冻结了。
怎么杀死library合约?因为这个library包含一个有趣的功能:
而且,由于有人初始化了这个钱包并将它们添加为一个拥有者,他们也可以杀死它。而且由于所有Parity MultiSig钱包都依赖于这个合同,所以现在它们完全不可用了,那就意味着所有钱包合约都被冻结了。
这个漏洞可能的解决方案:检查每个调用的上下文地址是不是library自己的地址,因此只允许通过delegatecalls调用library合约。
那么已冻结的资金怎么处理呢?现在只有把"library 合约"置于初始状态的硬分叉才能解决这个问题。
结论
这次的袭击与7月份的结果相同,都是因为攻击者通过漏洞直接或间接访问到核心方法。这种攻击表明,以太坊生态系统需要一套最佳实践和标准,以确保编码模式得到有效和安全的实施。
这里有个根本的问题值得我们注意:作为library设计的合约应该永远不可能有自己的状态改变,而且也不应该让用户在非正常访问下拥有访问核心问题的权限。
我们的钱包,HSR的区块链并不存在共享的library合约这样的问题,基于比特币的区块链,一旦交易广播到P2P网络,并记录到区块链上将不能被修改。之后我们钱包如果接入以太坊生态系统,需要注意,设计library的合约应该永远不能改变自己的状态。
参考链接
•Parity多重签名钱包被盗事件之技术分析
•Parity Wallet Security Alert — Vulnerability in the Parity Wallet library contract
•Another Parity Wallet hack explained
•Parity Wallet Hack 2: Electric Boogaloo
•关于 Parity 多签钱包账户冻结解释
•The Parity Wallet Hack Reloaded
投稿者:Hwallets技术团队
【声明:欢迎转载,转载请务必注明作者并附上inewb公众号二维码!欢迎投稿,投稿请发送至邮箱:inewbtg@163.com】