精彩解析:黑客如何做到用几行代码从银行盗取3千万美元

精彩解析:黑客如何做到用几行代码从银行盗取3千万美元

相信不少童鞋看到这个标题喜滋滋点进来,怕是今天要发家致富了。但是呢咳咳,来来来,跟着小编大声念一遍社会主义核心价值观:

                                         

违法的事情咱们不能干,但是呢,作为一名极客,了解了解黑客某些方面的技术还是很有必要的嘛~~~


前几天,一名黑客黑进了以太坊(Ethereum),制造了数字货币史上第二大盗窃案。


大概在太平洋时间中午12点,一个不知名的黑客在Ethereum网络上利用Parity多重签名的一个关键漏洞,仅仅几分钟就从三个巨额钱包里面盗取了价值超过3千万美元的Ether币。如果再给他几个小时,这个黑客就可以盗取价值超过1.8亿美元的Ether。


但有人阻止了他们。


听到警报声之后,来自Ethereum社区的白帽子黑客迅速组织起来。他们分析了这次袭击,意识到没有办法扭转盗窃行为,但是还有很多钱包正暴露在漏洞面前。时间是至关重要的,现在就只剩下一个选项:在攻击者之前黑进剩余的钱包。


通过利用同样的漏洞,白帽子全部劫持了所有剩下的风险较高的钱包,并排除了帐户,从而有效地防止了攻击者盗取剩下的1.5亿美元。


看起来很不可思议是不是,但是,你没有看错。


为了防止黑客抢劫银行,白帽子写了程序抢先黑进剩余的钱包。那么你最关注的是 ,钱被放到哪儿了呢?白帽子黑客总不可能自己留下吧。。。。放心,一旦这笔钱被安全地盗走,他们便开始将资金退还给各自的账户。


这是一件大事,它对密码货币的世界有重大的影响。


重要的是要明白,这个漏洞并不是Ethereum方面或Parity本身的一个漏洞。相反,这是默认智能合同代码中的一个漏洞,Parity客户端给用户部署多重签名钱包。


这一切都很复杂,所以为了让大家清楚这个细节,这篇文章分为三个部分:


  • 究竟发生了什么事? 对Ethereum,智能合同和多重签名的钱包的解释。
  • 他们是怎么做到的? 攻击的技术说明(专门针对程序员)。
  • 现在怎么办?攻击对智能合同未来和安全的影响。



如果你已经对Ethereum和加密世界相当熟悉了,可以跳到第二部分。



究竟发生了什么?



这个故事有三个组成部分:Ethereum,智能合同和数字钱包。


Ethereum是2013年发明的数字货币 - 比特币发行后的4年。随着比特币400亿美元的增长,它已经成为世界第二大数字货币市值--20亿美元。


像所有加密货币一样,Ethereum是Bitcoin协议的后代,并改进了Bitcoin的设计。但不要被愚弄:虽然它是像比特币这样的数字货币,但是Ethereum更强大。


虽然Bitcoin使用其块链来实现货币交易的分类帐,但是Ethereum使用其块链来记录巨大的分布式计算机中的状态转换。Ethereum相应的数字货币,以太网本质上是为这台大型电脑供电的副作用。


换句话说,Ethereum真的是一个跨越整个世界的电脑。任何在他们的电脑上运行Ethereum软件的人都在参与这个世界电脑,Ethereum虚拟机(EVM)的运作。因为EVM被设计为图灵完整(忽略gas cost),所以几乎可以在计算机程序中表达任何东西。


Gas是一种特别的单位用于Ethereum(以太币)里,它用来衡量一个行为或者一系列行为有多少“工作量”。


我要强调的是,这是一个非常疯狂的东西。加密世界对于Ethereum的潜力感到高兴,在过去6个月里,它的价值已经高涨。



智能合同只是运行在EVM上的计算机程序。在许多方面,他们就像正常的合同,除了他们不需要律师或法官来解释条款。相反,它们被编译成EVM的字节码和解释。通过这些程序,你可以(除其他事项外)以编程方式仅根据合同代码的规则转移数字货币。


当然,有些事情是正常的合同可以做而智能合同不能做到的 - 智能合同不能轻易地与不在区块链上的东西进行交互。但是,智能合同也可以做正常合同无法做到的事情,例如通过不可破解的加密技术完全执行一套规则。


这导致我们需要了解Ethereum中钱包的概念。在数字货币世界中,钱包是你存储资产的方式。你可以使用一个秘密密码(也称为你的私钥来访问你的钱包。


不同类型的钱包赋予不同的安全属性,如退出限制。最受欢迎的类型之一是多重签名钱包。


在多重签名的钱包中,有几个私钥可以解锁钱包,但只有一个钥匙不能解锁钱包。例如,如果你的多重签名钱包有3个键,则可以指定必须提供3个键中至少2个才能成功解锁。


这意味着,如果你父亲和你的母亲都是这个钱包上的签名人,即使犯罪分子盗走了私人钥匙,他们仍然无法获得你的资金。这是更强大的安全保障,所以多重签名是钱包安全的标准。


这正是黑客攻击的钱包类型。


那么出了什么问题?他们破解了私钥吗?他们是使用量子计算机还是某种尖端因子分解算法?


不,所有的加密都是健全的。漏洞其实简单的有些可笑了:他们在代码中发现了一个程序员引入的错误,让他们重新初始化钱包,就像恢复出厂设置一样。一旦他们这样做,他们就可以自由地将自己当作新的主人,然后取钱。


这是怎么发生的?


以下是对发生的事情的技术说明。如果你不是开发人员,请随时跳到下一部分,因为这部门比较偏技术了。


Ethereum有一个相当独特的编程模式。在Ethereum上,你可以通过发布合同(您可以将其视为对象)编写代码,并通过调用这些对象的方法来更改其状态来执行事务。


为了在Ethereum上运行代码,你需要首先部署合同(部署本身就是一个事务),这将花费少量的Ether。然后,你需要调用合同中的方法与之进行交互,这将花费更多的Ether。你可以想像,这样可以激励程序员优化代码,以尽量减少事务处理并最大程度降低计算成本。


降低成本的一个方法是使用库。通过将你的合同调用到之前部署的共享库,你不必重新部署任何共享代码。在Ethereum里,保持DRY(Dont repeat yourself)原则将直接节省你的钱。


Parity的默认多重钱包完全是这样的。它引用了一个包含钱包初始化逻辑的共享外部库。该共享库由库的合同的公钥引用。


// FIELDS
address constant _walletLibrary = 0xa657491c1e7f16adb39b9b60e87bbb8d93988bc3;


这个库将在几个地方被调用,通过一个叫做DELEGATECALL的指令,它执行以下操作:对于任何调用DELEGATECALL的方法,它将调用与你合同中授权的相同的方法,但使用的是当前合同的上下文。它本质上就像一个super调用,除了没有继承部分。(JavaScript中的等价是OtherClass.functionName.apply(this, args)。)


以下是他们的多重签名钱包中的一个例子:isOwner方法使用当前合同的状态并授权给共享的钱包库的isOwner方法:


function isOwner(address _addr) constant returns (bool) {  
  return _walletLibrary.delegatecall(msg.data);
}


多重钱包本身包含所有正确的权限检查,并且一定要严格执行与钱包状态相关的所有敏感操作的授权。


但他们犯了一个严重的错误。


Solidity允许你定义“回退方法”。这是在没有与给定方法名称匹配的方法时调用的方法。你定义一个匿名函数:

function() {  
  // do stuff here for all unknown methods
}


Parity团队决定让任何将Ether发送给合同的未知方法默认存入发送的Ether。


function() payable {  
  // payable is just a keyword that means this method can receive/pay Ether
  if (msg.value > 0) {
    // just being sent some cash?
    Deposit(msg.sender, msg.value);  
  }
  throw;
}


但他们又进了一步,这里是他们的严重错误。下面是被攻击的实际代码。


function() payable {  
  // just being sent some cash?
  if (msg.value > 0)
    Deposit(msg.sender, msg.value);
  else if (msg.data.length > 0)
    _walletLibrary.delegatecall(msg.data);
}


这段代码的意思是:

  1. 如果方法名称未在此合同中定义...
  2. 在交易中没有发送Ether..
  3. 消息有效载荷中有一些数据


那么如果它定义在_walletLibrary合同的上下文中,那么它将调用同一个的方法。


使用这种方式,攻击者调用了一种方法initWallet(),它没有在multisig合同上定义,但是在共享的钱包库中定义了:


function initWallet(address[] _owners, uint _required, uint _daylimit) {  
  initDaylimit(_daylimit);
  initMultiowned(_owners, _required);
}


这个方法调用了initMultiowned方法...


function initMultiowned(address[] _owners, uint _required) {  
  m_numOwners = _owners.length + 1;
  m_owners[1] = uint(msg.sender);
  m_ownerIndex[uint(msg.sender)] = 1;
  for (uint i = 0; i < _owners.length; ++i)
  {
    m_owners[2 + i] = uint(_owners[i]);
    m_ownerIndex[uint(_owners[i])] = 2 + i;
  }
  m_required = _required;
}


你看懂了这里发生了生么吗?攻击者基本上通过库的授权方式重新初始化合同,覆盖原始合同的所有者。他们和他们加进去的任何一数组的业主将成为新的所有者。


鉴于他们现在可以控制整个钱包,他们可以简单地提取剩余的余额。这正是他们做了什么。


那么什么造成了此次损失呢?你可以说有两个。首先,initWallet和initMultiowned钱包库未标记为internal(这就像一个private方法,这将阻止该授权调用),这些方法没有检查钱包是不是已经初始化。如果检查了的话黑客就不可能成功了。


第二个漏洞是原始的delegateCall。你可以将其视为等同于eval使用用户提供的字符串运行的raw 语句。为了简明扼要,本合同使用元编程来代理对基础库的潜在方法调用。这里更安全的方法是将用户允许调用的特定方法列入白名单。


麻烦的是,这在gas cost更昂贵(因为它必须评估更多的条件)。但是当涉及到安全性时,我们可能必须克服这个问题,才能制定出大量资金的智能合同。


所以这就是本次攻击。


这是一个聪明的攻击,但一旦你指出其中的原理,这就看起来没那么厉害了。然后,攻击者跳过了这个漏洞,他们可以找到三个最大的钱包 - 但从交易时长来看,他们完全是手动完成的。


白帽子小组正在使用脚本进行规模化处理,这就是为什么他们能够跑赢攻击者。


免责声明:本文由入驻邦投条平台的作者撰写,除邦投条官方账号外,文章观点仅代表作者本人,不代表邦投条立场,文章版权归原作者所有,请联系原作者申请授权。文章内容仅供参考,不构成投资建议。若有投资者据此操作,风险自担。如您发现内容存在版权问题,请提交相关链接至邮箱:banquan@rongebang.com,我们将及时予以处理。阅读更多有价值的内容,欢迎下载 邦投条APP

分享到:

参与评论

回复: X

请回复有价值的信息,无意义的评论将很快被删除,账号将被禁止发言。

登录 后参与评论
提交评论

相关投条号

四川钢结构网是四川钢结构行业的互联网平台;
大庆市格瑞设备清洗有限公司官方头条号
甘肃旅游网由创始人李福创立的甘肃旅游服务平台
中国建筑劳务云商由李福创立的劳务行业平台
梦客科技提供最前沿的便携式电动滑板车最新资讯及欧美行情。