首页 > 区块链 > 区块链安全 - DAO攻击事件解析
币区块  

区块链安全 - DAO攻击事件解析

摘要:dao区块链0x00 前言最近之后可能还会发一些其他的安全分析文章。0x00 基础知识1.跨合约调用智能合约之间的调用本质上是外部调用,可以使用message call或者创建智能合约对象的形式进行调用。(1)使用message call比如合约1调用合约2的某个方法:bytes4 methodId

区块链安全 - DAO攻击事件解析

0x00 前言

最近

之后可能还会发一些其他的安全分析文章。

0x00 基础知识

1.跨合约调用

智能合约之间的调用本质上是外部调用,可以使用message call或者创建智能合约对象的形式进行调用。

(1)使用message call

比如合约1调用合约2的某个方法:

bytes4 methodId = bytes4(keccak256("increaseAge(string,uint256)")); return addr.call(methodId,"jack", 1); 

(2)还原智能合约对象 如果已知合约的地址,可以通过如下方式获取到合约对象:

Contract1 c = Contract1(AddressOfContract1) ; c.foo() ; //跨合约调用 

2.智能合约发送ETH

我们可以在智能合约中用代码向某个地址(这个地址可以是人,也可以是智能合约)发送以太币,比较常见的两个方式是:

(1)调用send函数

比如:msg.sender.send(100)

(2)使用message call

msg.sender.call.value(100)()

这两个方式不同的是发送的gas数量,gas就是执行opcode需要花费的一种币,称作为gas也特别形象。当调用send方法时,只会发送一部分gas,准确地来讲,是2300gas,一旦gas耗尽就可能抛出异常。

而使用message call的时候,则是发送全部的gas,执行完之后剩余的gas会退还给发起调用的合约。

3.fallback函数

智能合约中可以有唯一的一个未命名函数,称为fallback函数。该函数不能有实参,不能返回任何值。如果其他函数都不能匹配给定的函数标识符,则执行fallback函数。

当合约接收到以太币但是不调用任何函数的时候,就会执行fallback函数。如果一个合约接收了以太币但是内部没有fallback函数,那么就会抛出异常,然后将以太币退还给发送方。

下面就是一个fallback函数的代码示例:

contract Sample{  function () payable{  // your code here  } } 

一般单纯使用message call或者send函数发送以太币给合约的时候,没有指明调用合约的某个方法,这种情况下就会调用合约的fallback函数。

0x01 攻击事件还原

我们先用简单的模拟代码来了解下整个攻击过程。

首先是存在漏洞的智能合约代码,Bank:

区块链安全 - DAO攻击事件解析

用户可以通过addToBalance方法存入一定量的以太币到这个智能合约,通过withdrawBalance方法可以提现以太坊,通过getUserBalance可以获取到账户余额。

注意到这里是通过message call的方式来发送以太币,所以在调用sender的fallback函数的时候我们就会有充足的gas来进行循环调用。如果是send的方式,gas只有2300,稍微一操作就会耗尽gas抛出异常,是不够用来进行嵌套调用的。以下是不同操作所需要的gas数量:

区块链安全 - DAO攻击事件解析

出问题的是withdrawBalance方法,特别是在修改保存在区块链的balances的代码是放在了发送以太币之后。 攻击代码如下:

区块链安全 - DAO攻击事件解析

这里的deposit函数是往Bank合约中发送10wei。withdraw是通过调用Bank合约的withdrawBalance函数把以太币提取出来。注意看这里的fallback函数,这里循环调用了两次Bank合约的withdrawBalance方法。

攻击的过程如下:

(1)假设Bank合约中有100wei,攻击者Attack合约中有10wei

(2)Attack合约先调用deposit方法向Bank合约发送10wei

(3)之后Attack合约调用withdraw方法,从而调用了Bank的withdrawBalance方法。

(4)Bank的withdrawBalance方法发送给了Attack合约10wei

(5)Attack收到10wei之后,又会触发调用fallback函数

(6)这时,fallback函数又调用了两次Bank合约的withdrawBalance,从而转走了20wei

(7)之后Bank合约才修改Attack合约的balance,将其置为0

通过上面的步骤,攻击者实际上从Bank合约转走了30wei,Bank则损失了20wei,如果攻击者多嵌套调用几次withdrawBalance,完全可以将Bank合约中的以太币全部转走。

0x02 复现过程

给Bank合约100wei,给Attack合约10wei。

(1)部署Bank,分配100wei

区块链安全 - DAO攻击事件解析

(2)部署Attack

区块链安全 - DAO攻击事件解析

分配给Attack 10wei。

(3)调用Attack合约的deposit方法

(4)调用Attack合约的withdraw方法

(5)查看Attack合约的余额,变成了30wei,即窃取了20wei

0x03 DAO攻击事件代码分析

在DAO源码中,有withdrawRewardFor函数:

function withdrawRewardFor(address _account) noEther internal returns (bool _success) {  if ((balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply < paidOut[_account])  throw;  uint reward =  (balanceOf(_account) * rewardAccount.accumulatedInput()) / totalSupply - paidOut[_account];  if (!rewardAccount.payOut(_account, reward)) //vulnerable  throw;  paidOut[_account] += reward;  return true; } 

这里调用了payOut函数进行付款。

function payOut(address _recipient, uint _amount) returns (bool) {  if (msg.sender != owner || msg.value > 0 || (payOwnerOnly && _recipient != owner))  throw;  if (_recipient.call.value(_amount)()) { //vulnerable  PayOut(_recipient, _amount);  return true;  } else {  return false; } 

而payOut中直接使用的是message call的方式发送以太币,从而导致了嵌套漏洞。

0x04 总结

在编写智能合约进行以太币发送的时候,要使用send或者transfer,不要使用message call的方式,而send其实还是有些小问题,以后有时间再分析。DAO事件直接导致了以太坊硬分叉,分为ETH和ETC。可见,区块链领域的安全不容忽视,因为其修复难度和所造成的影响都很高,毕竟是和钱打交道,兄dei,给个评论+

*

免责声明
世链财经作为开放的信息发布平台,所有资讯仅代表作者个人观点,与世链财经无关。如文章、图片、音频或视频出现侵权、违规及其他不当言论,请提供相关材料,发送到:2785592653@qq.com。
风险提示:本站所提供的资讯不代表任何投资暗示。投资有风险,入市须谨慎。
世链粉丝群:提供最新热点新闻,空投糖果、红包等福利,微信:juu3644。