티스토리 뷰

Solidity/Hacking

[Ethernaut] 12. Privacy

piatoss 2024. 1. 24. 12:00

1. 문제

 이 컨트랙트의 작성자는 스토리지의 민감한 부분에 대해 충분히 주의를 기울이고 컨트랙트를 작성했습니다.
 이 컨트랙트의 잠금을 해제하시오.

 도움이 될 만한 것들:
 * 스토리지 작동 원리 이해
 * 함수의 파라미터가 어떻게 파싱되는지 이해
 * 타입 캐스팅이 어떻게 동작하는지 이해
// 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
  */
}

2. 해법

 컨트랙트의 잠금을 해제하기 위해서는 스토리지에 저장된 32bytes 타입의 길이가 3인 배열 data의 마지막 원소값이 필요합니다. 우선 블록 탐색기를 열어서 컨트랙트가 배포될 때 스토리지에 어떤 변화가 있었는지 확인합니다.

 

 여기서 스토리지 슬롯의 다섯 번째 인덱스에 들어있는 값을 사용하겠습니다. bytes32 타입의 값을 더 작은 타입으로 캐스팅하면 값이 뒷부분에서부터 잘려나갑니다. 따라서 bytes16으로 캐스팅한 결과는 0x를 제외하고 앞부분의 16 바이트를 가지게 됩니다. 이 값을 unlock 함수의 인수로 집어넣고 함수를 호출합니다.

 

 트랙잭션이 컨펌되고나서 locked 값을 확인하면 false로 변경된 것을 확인할 수 있습니다.

 

 인스턴스를 제출하고 마무리합니다.


3. 스토리지

스토리지에 저장되는 값들은 슬롯에 순서대로 저장이 되며, 스토리지의 각 슬롯에는 최대 32바이트 크기의 데이터가 저장될 수 있습니다. 그렇다면 우선적으로 다음과 같은 스토리지 레이아웃을 생각해볼 수 있습니다.

 

 그런데 이렇게 배치를 하게 되면 31바이트(엄밀히 따지면 255비트) + 31바이트 + 31바이트 + 30바이트해서 총 123바이트가 낭비됨으로 인해 불필요한 비용이 발생하게 됩니다. (일반적인 값 타입의 경우 빈 자리는 00으로 채워짐)

 

 그래서 Solidity에서는 다음과 같이 연속하는 스토리지 변수들의 크기의 합이 32바이트를 초과하지 않는 선에서 하나의 슬롯에 함께 담습니다. 이 경우에는 낭비되는 메모리가 31바이트 + 28바이트로 크게 줄은 것을 확인할 수 있습니다. 스토리지 레이아웃이 이러하므로, data[2]는 스토리지의 다섯 번째 슬롯에서 읽어올 수 있습니다.


4. 결론

  1. private은 secret이 아니다.
  2. 스토리지가 어떻게 동작하는지 알아보았다.
  3. 바이트열 타입의 값은 작은 타입으로 캐스팅할 때 뒷부분에서 잘려나간다.
 

Layout of State Variables in Storage — Solidity 0.8.10 documentation

» Layout of State Variables in Storage Edit on GitHub Layout of State Variables in Storage State variables of contracts are stored in storage in a compact way such that multiple values sometimes use the same storage slot. Except for dynamically-sized arra

docs.soliditylang.org

 

'Solidity > Hacking' 카테고리의 다른 글

[Ethernaut] 14. Gatekeeper Two  (0) 2024.01.27
[Ethernaut] 13. Gatekeeper One  (1) 2024.01.25
[Ethernaut] 11. Elevator  (1) 2024.01.23
[Ethernaut] 10. Re-entrancy  (0) 2024.01.22
[Ethernaut] 9. King  (0) 2024.01.20
최근에 올라온 글
최근에 달린 댓글
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Total
Today
Yesterday
글 보관함