새소식

인기 검색어

Write Up/Ethernaut

[Ethernaut] Alien Codex

  • -
반응형

// SPDX-License-Identifier: MIT pragma solidity ^0.5.0; import '../helpers/Ownable-05.sol'; contract AlienCodex is Ownable { bool public contact; bytes32[] public codex; modifier contacted() { assert(contact); _; } function make_contact() public { contact = true; } function record(bytes32 _content) contacted public { codex.push(_content); } function retract() contacted public { codex.length--; } function revise(uint i, bytes32 _content) contacted public { codex[i] = _content; } }

우리의 mission은 owner를 탈취하는 것이다.

흐음.. 그런데 여기에 owner를 가질 수 있는 함수가 없다.

helpers/Ownable-0.5.sol

Ownable-0.5.sol을 보면 _transferOwnership() 함수를 이용하여 _owner를 탈취할 수 있을 것 같다.

그런데 이 함수들은 전부 owner일 때만 가능하다.

 

이 문제는 Storage 저장 방식에 관한 문제이다. 코를 잘 보면 Secure coding이 부족한 부분이 있다. 바로 retract() 함수이다.

보통 Secure coding을 위해 +=, -= 을 .add, .sub로 설정하고, push, pop을 사용하면 안전한 함수이다. 그런데 retract() 함수는 codex.length--로 underflow가 일어난다.

 

Storage에 저장되는 조건이 4가지 있다.

  • Storage slot의 첫 번째 항목은 하위 순서로 정렬되어 저장된다.
  • 값 유형은 저장하는 데 필요한 만큼의 바이트만 사용한다.
  • 값 유형이 Storage slot의 나머지 부분에 맞지 않으면 다음 Storage slot에 저장된다.
  • 구조체 및 배열은 항상 새 slot에 시작하고 채워진다.

그리고 동적배열 같은 경우는 크기가 정해지지 않아서 다른 변수들 사이에 저장될 수가 없다. 그래서 외부 저장 장소에 동적 배열을 저장한다. 외부 저장 장소이지만 2 ** 256 범위 안에 있으며 계산은 keccak256으로 한다.

즉 새로운 slot p에 저장된다하면 keccak256(p)의 위치에 저장이 된다.

 

문제에서 같이 한 번 보자. 해당 컨트랙트의 함수를 호출하려면 contact가 true가 되어야 한다.

그러면 make_contact()함수를 호출한 다음 나머지 함수 호출이 가능하다.

이제 해당 Contract의 Storage를 보자

slot0은 contact랑 owner가 같이 있다. 그리고 다음 slot부터 codex이 들어가는데 그림으로 Storage를 살펴보자

Storage를 보면 2 ** 256개의 저장공간이 있고 저장공간 하나당 32byte가 들어간다. codex은 동적배열이니까 keccak256(1)을 한 위치에 codex[0]이 들어간다. 실제로 한 번 확인해 볼까??

확실히 keccak(1)에 내가 입력한 값이 들어가 있다.

input의 시작은 keccak256(1)부터 시작이다. 그리고 owner index에 접근하기 위해 ((2**256)-1) - keccak256(1)을 해주고 +1을 하면 0번 index에 접근할 수 있다. 또 Contract의 모든 변수에 액세스 하기 위해여 codex의 길이를 -1 시켜 underflow를 일으킨다.

index가 ((2**256)-1) - keccak256(1)이고 player32는 player의 address를 32byte로 늘린 거다. revise()를 하면 owner를 탈취할 수 있다.

반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.