[Web3] Fallback

2025. 5. 25. 21:38·Hacking/Write Up
728x90
반응형

문제 : https://ethernaut.openzeppelin.com/level/0x3c34A342b2aF5e885FcaA3800dB5B205fEfa3ffB

 

https://ethernaut.openzeppelin.com/level/0x3c34A342b2aF5e885FcaA3800dB5B205fEfa3ffB

 

ethernaut.openzeppelin.com

Code Analysis

// 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;
    }
}

해당 함수를 하나하나 분석해보겠다.

Constructor()

  • 배포자에게 owner 권한을 부여
  • msg.sender의 기여도를 1000 ether로 설정

Contribute() 

  • 0.001 ether 미만만 전송 가능
  • 자신의 기여도가 기존 owner 보다 커지면 owner을 탈취할 수 있음
  • 하지만, 배포자가 1000 ether 기여도로 시작하기에 일반적인 contribute로는 절대 넘을 수 없다.

getContribution()

  • 본인의 기여도 조회 가능

withdraw()

  • owner만 컨트랙트 내의 이더를 모두 출금 가능

receive()

  • 해당 컨트랙트의 fallback 함수 (함수명을 명시하지 않고 ETH 전송 시 실행)
  • 기여도가 0보다 크고, msg.value>0인 경우, owner를 msg.sender로 무조건 변경
  • 해당 함수에서 취약점이 발생한다. 

 

Exploit Scenario

  1. contribute 함수를 호출하여 이더를 보낸다. 
  2. contributtions[msg.sender] > 0 상태가 됨
  3. msg.value > 0인 ether을 보내면 receive() 작동
  4. owner = msg.sender가 됨
  5. withdraw()로 전체 이더를 출금함

Exploit

처음 contribute함수를 실행하여, 0.0009만큼의 이더를 보낸다. 

이에 따라 msg.sender의 기여도가 >0이 된다. 

msg.value > 0인 ether을 보내주며 receive()가 작동된다. 

이후 owner가 msg.sneder라는 것을 확인할 수 있다.

player과, contract.owner()을 실행해보면 확인할 수 있음

 

이후 withdraw로 전체 이더를 출금하면 된다.

728x90
반응형
저작자표시 비영리 변경금지 (새창열림)

'Hacking > Write Up' 카테고리의 다른 글

[1-Day] CVE-2017-0199  (1) 2025.05.29
[Web3] Fallout  (0) 2025.05.25
[Web3] Hello Ethernaut  (0) 2025.05.25
[Pwnable] hook  (0) 2025.05.16
[Pwnable] oneshot  (0) 2025.05.16
'Hacking/Write Up' 카테고리의 다른 글
  • [1-Day] CVE-2017-0199
  • [Web3] Fallout
  • [Web3] Hello Ethernaut
  • [Pwnable] hook
min_zu
min_zu
  • min_zu
    민주제도
    min_zu
  • 전체
    오늘
    어제
    • ._. (176)
      • AI (2)
        • DeepLearning (2)
        • CS231n (0)
      • Web (2)
        • ReactJS (0)
      • CS (83)
        • OS (7)
        • Data Structure (23)
        • Computer Architecture (8)
        • Computer Network (20)
        • Algorithm (25)
      • Linux (3)
        • KaliLinux (0)
        • Docker (1)
      • Hacking (83)
        • Write Up (25)
        • Pwnable (13)
        • Reversing (2)
        • Cryptography (12)
        • Web Hacking (4)
        • Window (6)
        • Network (7)
        • Web3 (13)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    DataStructure
    Mac
    Sort
    OS
    DeepLearning
    Graph
    Tree
    ComputerArchitecture
    Web
    Search
    AI
    Linux
    WinAFL
    UTM
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
min_zu
[Web3] Fallback
상단으로

티스토리툴바