ecrecover
is a precompiled built-in cryptographic function which recovers an address associated with the public key from an elliptic curve signature or returns zero on error. The parameters corresponding to the signature are r
, s
& v
.
As noted above, ecrecover
will return zero on error. It's possible to do this deterministically by setting v
as any positive number other than 27 or 28.
ecrecover
is often used to verify that the signer is an authorized account. The problem with this is that uninitialized or renounced authorization logic often sets the owner/admin address as address(0)
, the same value which may be deterministically returned by ecrecover
. This means that an unsecure contract may allow an attacker to spoof an authorized-only method into executing as though the authorized account is the signer.
// UNSECURE
function setOwner(bytes32 newOwner, uint8 v, bytes32 r, bytes32 s) external {
address signer = ecrecover(newOwner, v, r, s);
require(signer == owner);
owner = address(newOwner);
}
The above method is intended to only set a new owner
if a valid signature from the existing owner
is provided. However, as we know, if we set v
to any value other than 27 or 28, the signer
will be the null address and if the current owner is uninitialized or renounced, the require
statement will succeed allowing an attacker to set themselves as owner
.
We can mitigate this issue by reverting if the recovered signer
address is null, e.g.:
function setOwner(bytes32 newOwner, uint8 v, bytes32 r, bytes32 s) external {
address signer = ecrecover(newOwnerHash, v, r, s);
require(signer == owner && signer != address(0));
owner = address(newOwner);
}