Don't think! Just do it!

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

Smart contract/Ethernaut 문제풀이

Ethernaut 문제풀이 #12 - Privacy

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

벌써 12번 문제입니다. 총 23개 문제니까 절반을 넘겼네요.

다른 길은 없습니다. ㅋㅋ 자 갑시다.

 

이 컨트랙트의 제작자는 저장소를 보호하는데 꽤나 신중했다고 하네요. 이 컨트랙트를 unlock하면 이길 수 있다고 합니다.

힌트로는 어떻게 storage가 작동하는지, 어떻게 parameter parsing 이 작동하는지 또 어떻게 casting이 작동하는지 이해하는 것이라 합니다.

팁을 하나 더 주네요. 난이도 8/10 짜리 문제라서 서비스가 좋군요.

메타마스크는 단지 상품이라는 것을 명심하고 메타마스크에 문제가 있느면 다른 툴을 사용하라고 합니다. 고급 난이도의 게임플레이는 Remix나 web3 provider를 사용한다고 합니다.....이미 그러고 있잖아... ㅅㅍ..

 

코드를 봅시다~!!!

contract Privacy {

  bool public locked = true;//locked = true 잠겨 있음.
  uint256 public ID = block.timestamp;//현재 블록의 타임스템프
  uint8 private flattening = 10;//byte 변수 0x0a
  uint8 private denomination = 255;//byte 변수 0xff
  uint16 private awkwardness = uint16(now);// 2 byte 변수 (현재 블록 타임스탬프)
  bytes32[3] private data;//

  constructor(bytes32[3] memory _data) public { //생성자
    data = _data;
  }
  
  function unlock(bytes16 _key) public { //unlock 함수
    require(_key == bytes16(data[2]));//이 조건을 만족하자!!
    locked = false;//locked가 풀림.
  }

  /*
    A bunch of super advanced solidity algorithms...

      ,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`
      .,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,
      *.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^         ,---/V\
      `*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.    ~|__(o.o)
      ^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'^`*.,*'  UU  UU
  */
}

 

 

_key 만 알아내면 unlock함수를 통해서 locked를 false로 변경할 수 있을 것 같습니다. 그런데 키가 약간 희안하네요. bytes16(data[2])가 키인데 data[2]를 bytes16으로 형변환한 값이네요. data bytes32[] 이므로 bytes16 강제 형변환하면 상위 비트가 잘려나갑니다. 즉 키는 data[2]의 하위 16 byte가 될 것 같습니다.

 

레벨8에서도 같은 것을 이용해서 문제를 푼 적이 있습니다.

2022.02.28 - [Smart contract/Ethernaut 문제풀이] - Ethernaut 문제풀이 #8 - Vault

이더리움 네트워크에서는 아무리 private으로 설정했다 하더라도 주소만 알고 있다면 컨트랙트 내부의 모든 변수를 읽어올 수 있습니다. web3에서는 web3.eth.getStorageAt() 을 이용해서 특정 주소 저장소의 값을 읽어옵니다.

 

자 그럼 콘솔에서 getStorageAt을 이용해 컨트랙트의 주소 0번 부터 차례대로 읽어봅시다.

 

await web3.eth.getStorageAt(contract.address,0)

 

아래는 실행 결과를 표로 만든 거에요.

 

여기서 주의할 점은 이더리움에서 string과 bytes는 big-endian을 사용하고 나머지는 little-endian을 사용합니다. 따라서 큰 비트에서 작은 비트로 강제 형변환 하면 하위 비트만 남으므로 string과 bytes는 왼쪽비트가 남고 uint, bool 등 나머지는 형식은 오른쪽 비트가 남습니다.

 

data[2]는 contract address로부터 5번째 주소인

0x96c12237b779e4177732465f377cd57780c1fc1169f44879336851aa6a07e668 입니다.

data는 bytes32 이므로 이를 bytes16으로 강제 형 변환을 하면 왼쪽 하위 비트가 남습니다.

0x96c12237b779e4177732465f377cd577이 됩니다.

 

자 이 숫자를 unlock함수에 넣고 실행해봅시다.

 

await contract.unlock("0x96c12237b779e4177732465f377cd577");

 

거래가 완료되면 locked가 false가 된 것을 확인합니다.

 

 

레벨은 완료했는데 힌트에서처럼 메타마스크 말고 다른 걸 사용하거나 하지 않았네요. 뭔가 찜찜합니다.

 

제출하고 문제풀이를 봅시다.

 

 

별거 없네요 이렇게 푸는게 맞답니다. 하지만 아시다시피 이더리움 스토리지는 매우 비쌉니다. 가격을 조금이라도 아끼려면 어떻게 스토리지가 구성되고 동작하는지 확실하게 파악하시는 게 좋지요. 

 

레벨의 문제풀이에 나온 것처럼 아래 사이트를 살펴보시고 실제 컨트랙트를 작성하시기 전에 충분한 시간을 들여 테스트넷에서 연습해보는 것이 중요할 것 같습니다.

https://medium.com/aigang-network/how-to-read-ethereum-contract-storage-44252c8af925

 

How to read Ethereum contract storage

Everybody is talking that data in contracts are public, but not everybody knows how to read it.

medium.com

 

자 이번 교훈

 

이더리움 스토리지! 정확히 알고 쓰자!

 

그럼 레벨 13에서 만나요.

 

안녕 ~!

 

반응형