BLOCKCHAIN_Reentrancy重入攻击
重入攻击
重入攻击与solidity语言本身的设计缺陷有关,同时也与合约的设计有关......
简单示例
可以先来看一个简单的重入攻击的合约
pragma solidity ^0.7.0; |
Bank
合约中:
mapping (address => uint) private balances;
是创建一个由地址到整数的映射,相当于一个字典,记录账户的余额信息
withdraw()
函数判断需要取出的数值是否小于等于账本中记录的数值,若是则取出
deposit()
函数则为调用该函数的用户存入传入的数值
getBalance()
返回整个账本的余额,方便查看余额
Attack
合约中:
Bank public bank;
接受合约地址,实例化一个Bank合约,以便调用Bank
中函数
attack()
执行攻击步骤
fallback()
关键函数
放到remix上编译,然后部署
先部署银行合约,部署的时候带上一些以太币,这里放10个,标识银行里总共有10个以太

点击getBalance
查看以银行余额,10eth,部署成功

接着再部署Attack
合约,合约里面需要带上1个以太,因为attack()里面需要存入1个以太到银行,构造函数中需要一个待攻击合约的地址,带上上面部署的银行合约地址

点击Attack
,调用合约的Attack()
进行攻击,再观察银行合约,余额已经为0

重入攻击成功
具体解析
在解析之前需要了解以太坊虚拟机EVM中的代码调用关系 ,在一个合约中调用另一个合约的函数时,解释器会去加载另一个合约的代码,类似于将另一个合约的代码整合到自己的合约中,当成自己的函数调用.
合约转账过程中,会调用一个带有数额value
的无名函数,在这个函数中有会调用fallback()
函数
,也就是转账过程分为两部分,转账函数(send()
、call()
、transfer()
)首确定收款合约的收款操作,然后再执行fallback()
函数
在攻击合约中点击attack
后,先调用bank.deposit{value:1 ether}();
往银行中存入1个ether,接着调用bank.withdraw(1 ether);
,从银行中取出1个ether.
在调用bank.withdraw()
时,在银行合约中会有分为两个步骤,一个是收款,一个是调用fallback()
函数,于是银行合约会在取款时调用攻击合约中的fallback()
函数,继续withdraw()
操作,由于上一层的withdraw()
还没有完成,银行记录的账户余额并不会减少,还能符合下一层的withdraw()
,于是就形成递归直到将银行中的钱全部取出.