[Ethernaut] 8. Vault

1. 문제

 아래의 금고를 해제하라!

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

contract Vault {
  bool public locked;
  bytes32 private password;

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

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

2. 해법

 인스턴스를 생성할 때 선택한 네트워크의 블록 탐색기(ex. sepolia etherscan)를 열고 인스턴스 주소를 검색합니다.

 Internal Transaction 탭에서 To가 Contract Creation으로 되어 있는 트랜잭션의 부모 해시를 클릭합니다.

 Transaction Details 상단의 State 탭을 클릭합니다. 이 탭에서는 이 트랜잭션으로 인해 블록체인 상에서 어떤 상태 변화가 발생했는지 확인할 수 있습니다. 인스턴스 주소 왼쪽의 화살표를 클릭하여 탭을 펼칩니다.

 인스턴스 스토리지의 두 번째 슬롯의 값에 주목합니다. 이 값이 바로 금고의 비밀번호입니다.

 확인한 비밀번호를 그대로 복사하여 unlock 함수의 매개변수로 넣고 함수를 실행합니다.

 트랜잭션이 컨펌되고 locked 값을 확인하면 false로 변한 것을 확인할 수 있습니다.


3. private은 secret이 아니다

 원본 컨트랙트에서 password의 가시성은 private입니다. 이더리움과 같은 퍼블릭 블록체인은 누구나 블록체인에 저장되어 있는 데이터를 확인할 수 있습니다. 따라서 private은 나만의 작고 소중한 비밀이 될 수 없습니다. private은 그저 다른 컨트랙트에서 해당 값이나 함수에 직접 접근하는 것을 방지해줄 뿐입니다.

 굳이 블록체인 상에 비밀을 저장하고 싶다면, commit-reveal 방식을 사용하여 저장하고자하는 값의 해시값을 만들어 저장하고 나중에 원본값을 공개할 수 있습니다. 그러나 이 방법도 결국은 트랜잭션을 생성할 때 값이 드러나기 때문에 공격자가 동일한 트랜잭션을 더 높은 가스비를 지불하고 생성하여 먼저 마이닝되도록 하는 프론트 러닝(front-running)과 같은 문제에 여전히 취약할 수 있습니다.


4. 결론

퍼블릭 블록체인에서 비밀은 없다.