在之前的内容中了解到storage是使用slot来存储数据的。delegatecall函数有一个有趣的特点:在使用delegatecall函数进行外部调用涉及修改存储变量时,是根据槽位而不是变量名来修改的。例如:合约A合约B当合约B调用testDelegatecall()函数时,合约B的地址c的值会变为合约A的地址,而地址a则保持不变。因为合约A的函数test()改变了slot1的值,同样,在合约B中运行时,也改变了slot1的值,即地址c的值。目标合约漏洞分析我们可以看到有两个合约。Lib合约中只有一个pwn函数可以修改合约的owner。HackMe合约中有回退功能。fallback函数的内容是使用delegatecall调用Lib合约中的函数。我们需要使用HackMe.fallback()触发delegatecall函数调用Lib.pwn()将HackMe合约中的owner更改为自己。攻击合约下面我们来看一下整个攻击的逻辑:1.攻击者调用attack()发起攻击,攻击函数首先调用HackMe.pwn();2、HackMe合约中没有pwn函数,此时触发HackMe.fallback();3.HackMe.fallback()使用deldegatecall调用Lib合约中的函数,函数名为msg.data,也就是“pwn()”,而Lib合约中正好有一个名为pwn的函数,所以在HackMe合约4.pwn函数将slot0(即HackMe合约的所有者)的值修改为msg.sender(即攻击者),最终导致HackMe合约的所有者成为攻击者。修复建议注意使用delegatecall时被调用合约的地址不可控;在更复杂的合约环境中,需要注意变量的声明顺序和存储位置。因为使用delegatecall进行外部调用时,合约对应slot中存储的数据会根据被调用合约的数据结构进行修改,当数据结构发生变化时,可能会造成意外的变量覆盖。如果你想了解更多智能合约和区块链知识,欢迎来到区块链交流社区CHAINPIP社区一起交流学习~社区地址:https://www.chainpip.com/
