Smart contract security – delegatecall (2)


This time, we will talk about a more complex contract vulnerability case when using the delegatecall function.

target contract
Smart contract security - delegatecall (2)
Vulnerability Analysis The target of this attack is still to obtain the owner permission in the HackMe contract. We can see that in the two contracts, except for the constructor in the HackMe contract, which can modify the owner of the contract, there is no function to modify the owner, but it can be modified. The value of slot0 in the HackMe contract, and the slot slot0 in the HackMe contract represents the address of Lib, then we first modify the address of Lib to our address, and when calling the HackMe contract again, it will run the logic in our contract, then if we want to change Isn’t the value of the slot at any position controlled by us?

attack contract
The following is our attack contract this time:
Smart contract security - delegatecall (2)
Next, let’s take a look at the entire logic of the attack:

  1. The Attack.attack() function first converts its address to uint256 type (this step is to be compatible with the data type in the target contract) and calls the HackMe.doSomething() function for the first time;
  2. The HackMe.doSomething() function uses the delegatecall function to call the Lib.doSomething() function with the address of the incoming Attack contract;
  3. It can be seen that the Lib.doSomething() function changes the parameter stored in slot0 in the contract to the value passed in, so that when the HackMe contract uses delegatecall to call the Lib.doSomething() function, it will also change the value of the variable stored in slot0 Value, that is, change the lib parameter (the address of the Lib contract is stored here) to the address of the Attack contract we passed in. At this point, the address of the Lib contract previously stored in the HackMe.lib parameter is changed to the address of the Attack contract we passed in;
    4. The Attack.attack() function calls the HackMe.doSomething() function again. Since we have changed the HackMe.lib variable to the address of the Attack contract in the previous step, the HackMe.doSomething() function will no longer call the previous The Lib contract uses a delegatecall to call the Attack.doSomething() function instead. At this time, we will observe the writing of the Attack contract again, and find that the storage location of its variables is intentionally consistent with the HackMe contract, and it is not difficult to find that the content of the Attack.doSomething() function is also written by the attacker as owner = msg.sender. This operation modifies The variable stored in the contract is slot1. Therefore, the HackMe contract uses the delegatecall to call the Attack.doSomething() function, which will change the variable owner whose storage location is slot1 in the contract to msg.sender, which is the address of the attacker, and the attacker has completed his attack.

repair suggestion
When we use delegatecall in the development of the contract, we must always pay attention to the address of the contract being called. It must always run within the logic of our design, and it cannot be allowed to exceed the scope of application of our design. Once there is a situation that exceeds our expected design, Then the contract may be used by criminals.
If you want to learn more about smart contracts and blockchain knowledge, welcome to the blockchain exchange community CHAINPIP community to exchange and learn together~ Community address: