Description
For this challenge, we have to deal only with a single Smart Contract called Switch. The goal of the challenge is to gain ownership of the contract, overriding the value of the owner state variable.
Code
/**
*Submitted for verification at Etherscan.io on 2022-08-13
*/
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.0;
/**
* @title Claim ownership of the contract below to complete this level
* @dev Implement one time hackable smart contract (Switch)
*/
contract Switch {
address public owner;
modifier onlyOwner() {
require(msg.sender == owner, "caller is not the owner");
_;
}
constructor() {
owner = msg.sender;
}
// Changes the ownership of the contract. Can only be called by the owner
function changeOwnership(address _owner) public onlyOwner {
owner = _owner;
}
// Allows the owner to delegate the change of ownership to a different address by providing the owner's signature
function changeOwnership(
uint8 v,
bytes32 r,
bytes32 s
) public {
require(ecrecover(generateHash(owner), v, r, s) != address(0), "signer is not the owner");
owner = msg.sender;
}
// Generates a hash compatible with EIP-191 signatures
function generateHash(address _addr) private pure returns (bytes32) {
bytes32 addressHash = keccak256(abi.encodePacked(_addr));
return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", addressHash));
}
}
Solution
我们可以看到在changeOwnership中只验证了VRS的有效性,但是没有认证ecrecover出来的地址是否是owner就直接切换了,所以我们随便传入一个签名都可以做到。
uint256 privateKey = 123456;
bytes32 hashedMessage = bytes32(0);
// sign the hashed message
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, hashedMessage);