unlock 함수에 key 넣어서 locked상태 false로 만들기.
문제의 핵심은 스토리지에 어떻게 변수들이 저장되는지를 알아야 한다.
이더리움에서 스토리지를 적게 사용하는 것이 가스비에 큰 영향을 미치는데 그것을 알아봐야 한다.
문제에서 변수는 이런 식으로 있고 우리는 data[2]를 가져와서 unlock함수에 넣어야 한다.
지금 보면 locked, ID는 public이라서 getter함수가 자동으로 있다.
그렇기에 contract.ID 이런 식으로 call 하면 값을 알 수 있지만, private은 그게 안된다.
하지만 web3.js, ethers.js에 있는 getStorageAt매서드를 이용하면 그것을 알 수 있는데 storage는 32 bytes의 크기를 가지기 때문에 뒤에서부터 data [2]가 어디 있는지 찾으면 되는데
bool값인 locked가 0번째 스토리지.
ID는 uint256이라서 1번쨰 스토리지.
flattening, denomination,awkwardnesss는 짜잘이라서 세 개가 하나의 스토리지에 들어간다. 2번째 스토리지.
그다음 bytes32인 data가 스토리지 하나씩 차지하는데 data[2]는 3번째에 위치해서 5번째 스토리지에 위치한다.
그래서 getStorageAt을 사용하면 bytes32값이 나오는데 unlock함수는 bytes16으로 넣어줘야 해서
function convert(bytes32 _input) external pure returns(bytes16){
return bytes16(_input);
}
살짝 바꾸는 함수에 넣어서 나온 값을 unlock함수에 넣으면 된다.
다른 블로그의 추가 설명.
https://dev.to/nvn/ethernaut-hacks-level-12-privacy-2afl
level 12.Privacy 코드
// 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
*/
}
'CTF > Ethernaut' 카테고리의 다른 글
[Ethernaut] 14.Gatekeeper Two (0) | 2024.02.10 |
---|---|
[Ethernaut] 13.Gatekeeper One (!!hard!!) (0) | 2024.02.09 |
[Ethernaut] 11.Elevator (0) | 2024.02.08 |
[Ethernaut] 10.Re-entrancy (0) | 2024.02.05 |
[Ethernaut] 9.King (0) | 2024.02.05 |