level 18. magic number
이번 문제는 10개 이해 opcode(evm code)를 사용해 숫자 42를 반환하는 컨트랙트를 배포해야 합니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract MagicNum {
address public solver;
constructor() {}
function setSolver(address _solver) public {
solver = _solver;
}
/*
____________/\\\_______/\\\\\\\\\_____
__________/\\\\\_____/\\\///////\\\___
________/\\\/\\\____\///______\//\\\__
______/\\\/\/\\\______________/\\\/___
____/\\\/__\/\\\___________/\\\//_____
__/\\\\\\\\\\\\\\\\_____/\\\//________
_\///////////\\\//____/\\\/___________
___________\/\\\_____/\\\\\\\\\\\\\\\_
___________\///_____\///////////////__
*/
}
10 이하의 opcode로 구성된 컨트랙트를 배포하고 setSolver를 통해 등록해 문제를 해결하면 됩니다.
이 문제를 해결하기 위해서는 opcode와 컨트랙트 구조에 대한 이해가 필요합니다.
따라서 취약점 분석보다는 필요한 개념에 대해 설명하겠습니다.
Init code는 말 그대로 초기화, 즉 배포 코드 입니다. 컨트랙트가 배포 될때 실행되는 바이트 코드입니다.
다만 컨트랙트가 배포되고 난 이후에는 CA(contract)에 저장이 되지 않습니다. 저희가 컨트랙트를 호출할 때 실행되는 코드는 런타임 코드로 Init code는 컨트랙트의 실행과는 상관이 없습니다.
배포 코드의 목적은 런타임 코드를 EVM에 리턴 시켜주는 것 입니다.
Contract deploy tx는 아래와 같습니다.
{
"to": null,
"value": msg.value,
"data": "<init_code><runtime_code><constructor_args (option)>"
}
생성자 인자와 함께 init code가 실행되고 초기화(생성자 함수 내부 로직)가 진행되며 EVM에 runtime code를 반환해 줍니다.
배포 코드 역시 opcode로 직접 구성할 수 있겠지만 굳이 안그래도 됩니다. constructor 함수 안에 10개 이하의 opcode로 이뤄진 runtime code를 넣고 return만 시켜주면 됩니다.
이제 CA에 저장되며 호출되어 컨트랙트 내부 로직을 수행하는 runtime code를 직접 opcode로 구성해보겠습니다. etherscan Contract address를 치고 들어가서 볼 수 있는 컨트랙트 바이트 코드가 바로 이 runtime code 입니다.
evm codes
위 사이트에 들어가면 opcode들을 확인할 수 있고 PlayGround에서 실습도 가능합니다.
EVM은 스택 기반입니다. 따라서 어떤 데이터를 메모리나 스토리지에 올리거나 return 시켜줄 경우에는 우선 필요한 값들을 스택에 넣어두어야 합니다.
완성한 공격 코드는 아래와 같습니다.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IMagicNumber {
function setSolver(address _solver) external;
}
contract Attack {
constructor(address _target) {
IMagicNumber tartget = IMagicNumber(_target);
tartget.setSolver(address(this));
assembly {
mstore(0,0x602a5f5260205ff3)
return (0x18, 0x08)
}
}
}
inline assembly를 사용해 직접 메모리로 올리고 return 시켜주었습니다.

배포된 컨트랙트의 코드 영역에는 위와 같이 저희가 EVM에 리턴한 런타임 코드만 존재합니다.