The hint of this level lies in its name, Delegation. According to Wiki
A Delegation is the assignment of authority to another person (normally from a manager to a subordinate) to carry out specific activities.
Yes i still get my information from Wikipedia. Now let’s understand the code of this level. This level contains two contracts, Delegate and Delegation.
In the Delegate contract, the constructor takes an address and makes it the owner of the contract. There is another public function pwn() in which whomever initialize the contract becomes the owner of it.
contract Delegate {
address public owner;
constructor(address _owner) {
owner = _owner;
}
function pwn() public {
owner = msg.sender;
}
}
In the Delegation contract, it first calls in the Delegate contract then its constructor proceeds to take in the address of Delegate contract and store it in delegate and also makes the contract initializer the owner of the contract. Also exists a fallback() function which triggers when there is no other function in the contract executes properly. In the fallback() function it calls the pwn() function of Delegate contract by stating the Delegate contract address and then calling delegatecall() function to execute the pwn() function and set it to a bool result condition which checks whether the address is the current address of the contract.
contract Delegation {
address public owner;
Delegate delegate;
constructor(address _delegateAddress) {
delegate = Delegate(_delegateAddress);
owner = msg.sender;
}
fallback() external {
(bool result,) = address(delegate).delegatecall(msg.data);
if (result) {
this;
}
}
}
What a delegatecall() is that it lets you call a function on another contract while keeping the original data context. Think of it like calling a function from a library that we do in other programming languages. So we are allowing the Delegate contract to run its pwn() function inside our Delegation contract conforming to the title of this level.
When you Get New Instance only the Delegation contract works not the Delegate contract since it acts like a library to the Delegation contract. Now we cannot be the owner of the Delegation contract since we initialize it goes with the address of the Level and not our address. You can confirm this by the following command.
You see the conflict now? Since we only have access to Delegation contract and it is calling a function from Delegate contract and not of its own we cannot push in our own address to become the contract owner. So we need to hit the pwn() function somehow.
In order to do so, we run the following command
await sendTransaction({
from: player,
to: contract.address,
data: "0xdd365b8b"
})
In this command, you can understand that the sender is the player which is us and the receiver is the level, but what is this strange data value that we are sending in the transaction. EVM calls the functions by looking at the first 4 bytes of the function signature. In our case, the signature is keccak256 which is basically sha3. So if we want to obtain the signature of pwn() function we would run the following command to know Hexadecimal value of pwn() which is of 4 bytes equaling to dd365b8b
.
So we push it into the data and can now manipulate the pwn() function to become the owner of Delegation contract by the command stated above.
Now you have become the owner of the contract and can confirm this with the following commands.
Now just Submit Instance and WIN WIN WIN WIN!
Top comments (0)