共计 957 个字符,预计需要花费 3 分钟才能阅读完成。
在之前的内容中,学习到了 storage 中是应用插槽存储数据的。而 delegatecall 函数有个乏味的特点:当应用 delegatecall 函数进行内部调用波及到 storage 变量的批改时是依据插槽地位来批改的而不是变量名。
举个例子:
合约 A
合约 B
当合约 B 调用 testDelegatecall()函数时,合约 B 的地址 c 的值会变为合约 A 的地址,而地址 a 则是不变。因为合约 A 的函数 test()扭转的是插槽 slot1 的值,同样的在合约 B 中运行时,扭转的也是插槽 slot1 的值,即地址 c 的值。
指标合约
破绽剖析
咱们能够看到有两个合约,Lib 合约中只有一个 pwn 函数用来批改合约的 owner,在 HackMe 合约中存在 fallback 函数,fallback 函数的内容是应用 delegatecall 去调用 Lib 合约中的函数。咱们须要利用 HackMe.fallback() 触发 delegatecall 函数去调用 Lib.pwn() 将 HackMe 合约中的 owner 改成本人。
攻打合约
当初咱们来看看整个攻打的逻辑:
1. 攻击者调用 attack()发动攻打,attack 函数首先去调用 HackMe.pwn();
2.HackMe 合约中并没有 pwn 函数,此时触发 HackMe.fallback();
3.HackMe.fallback() 应用 deldegatecall 调用 Lib 合约中的函数,函数名取的是 msg.data 也就是 “pwn()”,而 Lib 合约中恰好有名为 pwn 的函数,于是便在 HackMe 合约中运行了 pwn 函数;
4.pwn 函数批改了插槽 slot0 地位(即 HackMe 合约的拥有者)的值为 msg.sender(即攻击者),最终导致了 HackMe 合约的拥有者变成了攻击者。
修复倡议
- 在应用 delegatecall 时应留神被调用合约的地址不能是可控的;
- 在较为简单的合约环境下须要留神变量的申明程序以及存储地位。因为应用 delegatecall 进行内部调时会依据被调用合约的数据结构来用批改本合约相应 slot 中存储的数据,在数据结构发生变化时这可能会造成非预期的变量笼罩。
如果想理解更多的智能合约和区块链常识,欢送到区块链交换社区 CHAINPIP 社区,一起交流学习~ 社区地址:https://www.chainpip.com/