본문 바로가기
Write Up/Ethernaut - 블록체인 워게임

Ethernaut - 12단계 (Privacy)

by p6rkdoye0n 2023. 11. 18.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Privacy {

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

  constructor(bytes32[3] memory _data) {
    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.

 

locked를 false로 만들면 풀리는 문제이다. locked는 unlock 함수를 통해서 false로 바꿀 수 있다. byte16 타입의 데이터를 인자로 받고 data[2]와 비교를 하고 맞게 된다면 false로 바꿔주게 된다.

 

Ethernaut 풀었던 문제 중에서 private으로 데이터 타입을 설정해도 web3 API로 변수의 값을 읽을 수 있는 것을 해본적이 있다. 그렇다면 byte32 data[2]는 몇번째 인덱스의 위치하였는지 알아야 할 필요가 있다.

 

단순히 변수의 7번째라서 6이라고 치고 막상 검색해보면 안 나오는 것을 알 수 있다.

 

 

//index 0 (bool은 최대 32바이트 차지)
bool public locked = true;
//index 1 (uint256은 최대 32바이트 차지)
uint256 public ID = block.timestamp;
//index 2 (uint8은 최대 1바이트 차지)
uint8 private flattening = 10;
//index 2 (uint8은 최대 1바이트 차지)
uint8 private denomination = 255;
//index 2 (uint8은 최대 2바이트 차지)
uint16 private awkwardness = uint16(block.timestamp);
//index 3 (bytes32는 최대 32바이트 차지 => data[0]:3, data[1]:4, data[2]:5)
bytes32[3] private data;

 

하나의 인덱스에는 최대 32바이트를 저장할 수 있으므로 위와 같은 계산 방식으로 data[2]는 인덱스 5번째 위치에 존재하는 것을 알 수 있다.

 

 

data[2]의 값을 구했다.

 

function unlock(bytes16 _key) public {
    require(_key == bytes16(data[2]));
    locked = false;
  }

 

해당 함수는 bytes32 타입인 data[2]의 값을 bytes16으로 형변환을 시켜주고 인자로 들어오는 key의 값과 비교를 해준다. 그렇다면 해당 값을 bytes16으로 형변환 시켜주고 해당 함수의 인자로 넣어준 뒤에 호출해주면 문제가 풀릴거 같다.

 

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

contract Find_key {
    bytes32 public key = 0x93615177f13477ffb05e3f834e066be1adab311848b161000a0e751b9cc4e82a;     

    function find_key() public view returns (bytes16) {
        return bytes16(key);
    }
}

 

구한 값을 위의 코드로 형변환 시켜주고 해당 값을 인자로 함수를 호출한다.

 

 

그럼 locked의 값이 false로 바뀌게 되면서 문제를 풀 수 있었다.

 

 

🚩