在之前的内容中,学习到了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 合约的拥有者变成了攻击者。
修复倡议

  1. 在应用 delegatecall 时应留神被调用合约的地址不能是可控的;
  2. 在较为简单的合约环境下须要留神变量的申明程序以及存储地位。因为应用 delegatecall 进行内部调时会依据被调用合约的数据结构来用批改本合约相应 slot 中存储的数据,在数据结构发生变化时这可能会造成非预期的变量笼罩。

如果想理解更多的智能合约和区块链常识,欢送到区块链交换社区CHAINPIP社区,一起交流学习~ 社区地址:https://www.chainpip.com/