Web3/The Ethernaut

[The Ethernaut] Level 1. Fallback

프레딕 2025. 1. 6. 21:48
728x90

드디어 Web3를 시작하게 됐다.

과연 흥미를 붙여 계속 할 수 있을진 모르겠지만.... The Ethernaut을 천천히 풀어보며 공부해보려 한다....

일단 우여곡절끝에 지갑 생성 후 Level 1 Fallback을 풀었다.

 

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

contract Fallback {
    mapping(address => uint256) public contributions;
    address public owner;

    constructor() {
        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 (uint256) {
        return contributions[msg.sender];
    }

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

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

 

문제에서 요구하는건 두가지이다.

1. owner 강탈

2. 잔고 0으로 만들기

 

일단 1번을 시도하기 위해선 

owner = msg.sender를 트리거 하면 된다.

해당 엔드포인트는 contribute()와 receive에서 보인다.

일단 contribute는 0.001 ether보다 작으면 msg.value를 contributions에 추가하는데 이게 contributions[owner]보다 크면 된다.

그러나 constructor()에서 초기 contributions값을 1000ether로 설정해 놓았기에 사실상 불가능한 포인트이다..

receive를 살펴보면은 msg.value > 0이고 contributions[msg.sender] > 0 이기만 하면 owner=msg.sender을 트리거 가능하기에 요기가 좀 더 좋아 보인다.

 

일단 the ethernaut에서는 console창을 통해 해당 ABI들을 트리거 가능하다.

ABI가 정확히 뭐냐면 나도 정확히는 모르겄지만 대충 코드 안에 저 함수들이나 그런걸 파싱에서 사용가능하게 해주는? 그런 것 같다. (자세힌 모름...)

여튼 예를 들어 contribute를 트리거 하기 위해선

await contract.contribute({'value':_ethers.utils.parseEther("0.0005")})

요런식으로 값을 넘길 수 있다. (0.0005 ether 넘기기)

receive()에선

msg.value > 0 이고 contributions[msg.sender] > 0 이여야 통과되는데 뭐 msg.value는 0보다 크게 넘긴다 치고 contributions가 0이상이 되려면 contribute()에서 조금만 보내주면 된다.

일단 receive는 payable이 붙어 있어 순수 이더 전송을 처리하는 함수기에 sendTransaction을 사용해 넘길 수 있다.

여기서 contribute에도 payable이 붙어 있기에 같이 작동 될 것이다.

await contract.sendTransaction({'value':_ethers.utils.parseEther("0.0001")})

0.0001은 0보다 커지기에 value가 넘어가고 owner = msg.sender를 트리거 할 수 있게 된다.

 

그 후 withdraw를 호출하면 잔고가 0이 되고 성공하게 된다.

await contract.withdraw()

 

참고로 아래 명령어를 통해 owner의 잔액도 확인 가능하다.

await getBalance(instance)

 

 

음 아직 제대로 다 이해는 못되는데 구글링 해가면서 해봐야지...

728x90
반응형