[Ethernaut CTF] Privacy

0xDave·2022년 10월 4일
0

Ethereum

목록 보기
33/112

소스코드


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

contract Privacy {

  bool public locked = true;
  uint256 public ID = block.timestamp;
  uint8 private flattening = 10;
  uint8 private denomination = 255;
  uint16 private awkwardness = uint16(now);
  bytes32[3] private data;

  constructor(bytes32[3] memory _data) public {
    data = _data;
  }
  
  function unlock(bytes16 _key) public {
    require(_key == bytes16(data[2]));
    locked = false;
  }

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

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

해결과제


The creator of this contract was careful enough to protect the sensitive areas of its storage.

Unlock this contract to beat the level.

Things that might help:

    Understanding how storage works
    Understanding how parameter parsing works
    Understanding how casting works

Tips:

Remember that metamask is just a commodity. Use another tool if it is presenting problems. 
Advanced gameplay could involve using remix, or your own web3 provider.

해결과정


data 값을 알아내면 된다. getStorageAt으로 여러 값들을 뽑았지만 Storage에 대한 근본적인 이해가 필요하다.

Storage는 2^256개의 슬롯으로 구성돼있고, 각 슬롯 당 32바이트가 할당된다. 컨트랙트에 선언된 순서대로 슬롯을 채운다고 보면 된다. 이 때 공간을 절약하기 위해 크기에 따라 같은 슬롯에 저장되기도 한다. 자세한 내용은 아래 코드를 통해 살펴보자. 해당 코드는 solidity-by-example의 Accessing Private Data에서 가져왔다.

  1. uint로 변수를 선언하면 디폴트로 uint256을 갖는다. uint256은 32바이트이므로 전체가 slot 0에 저장된다.
  2. address 타입은 20바이트, boolean은 1바이트, uint16은 2바이트로 공간이 남기 때문에 묶어서 slot 1에 저장된다.(다음에 나올 password가 32바이트라서 이전까지만 묶어서 저장된다.)
  3. 32바이트로 선언된 password는 slot 2에 저장된다.
  4. constant는 storage에 저장되지 않는다.
  5. 각각 32바이트로 선언됐기 때문에 array의 각 데이터가 하나씩 slot3, 4, 5에 저장된다.

이제 본 코드를 살펴보자.

  bool public locked = true; //slot 0
  uint256 public ID = block.timestamp; //slot 1
  uint8 private flattening = 10; //slot 2
  uint8 private denomination = 255; //slot 2
  uint16 private awkwardness = uint16(now); //slot2
  bytes32[3] private data; //slot 3, 4, 5

우리가 원하는 data[2]는 slot 5에 있을 것이다. 그런데 한 가지 주의할 게 있다. data는 32바이트로 저장되어 있지만 unlock에 입력하는 값은 16바이트 형태로 되어있다. 이를 바탕으로 컨트랙트를 작성해보자.

디플로이 후 slot 5에 해당하는 값으로 unlock 실행하면 끝!

profile
Just BUIDL :)

0개의 댓글