Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flat Watermelon Terrier - Cross-chain replay attack vulnerability #39

Open
sherlock-admin2 opened this issue Nov 23, 2024 · 0 comments
Open

Comments

@sherlock-admin2
Copy link

Flat Watermelon Terrier

High

Cross-chain replay attack vulnerability

Summary

Signatures needed to execute a transaction can be reused on another chain if several conditions are satisfied

Root Cause

https://github.com/sherlock-audit/2024-11-hats-protocol/blob/main/hats-zodiac/src/HatsSignerGate.sol#L644-L684

The HatsSignerGate.sol::_countValidSignatures to check signatures validity uses ecrecover function that is subject to cross-chain replay attack.

  function _countValidSignatures(bytes32 dataHash, bytes memory signatures, uint256 sigCount)
    internal
    view
    returns (uint256 validSigCount)
  {
    // There cannot be an owner with address 0.
    address currentOwner;
    uint8 v;
    bytes32 r;
    bytes32 s;
    uint256 i;

    for (i; i < sigCount; ++i) {
      (v, r, s) = signatureSplit(signatures, i);
      if (v == 0) {
        // If v is 0 then it is a contract signature
        // When handling contract signatures the address of the contract is encoded into r
        currentOwner = address(uint160(uint256(r)));
      } else if (v == 1) {
        // If v is 1 then it is an approved hash
        // When handling approved hashes the address of the approver is encoded into r
        currentOwner = address(uint160(uint256(r)));
      } else if (v > 30) {
        // If v > 30 then default va (27,28) has been adjusted for eth_sign flow
        // To support eth_sign and similar we adjust v and hash the messageHash with the Ethereum message prefix before
        // applying ecrecover
        currentOwner = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", dataHash)), v - 4, r, s);
      } else {
        // Default is the ecrecover flow with the provided data hash
        // Use ecrecover with the messageHash for EOA signatures
@>        currentOwner = ecrecover(dataHash, v, r, s);
      }

      if (isValidSigner(currentOwner)) {
        // shouldn't overflow given reasonable sigCount
        unchecked {
          ++validSigCount;
        }
      }
    }
  }

Internal pre-conditions

Safe.sol, HatsSignerGate.sol deployed on two blockchains so that:
Safe.nonce() chain A > Safe.nonce() chain B and the signatures have been already used in a transaction in chain A

External pre-conditions

An attacker that takes signatures through the block explorer and use them in another chain (aforementioned chain B) when the Safe.nonce() value will be equal to the one used in chain A

Attack Path

The attacker could get from a block explorer the signatures used on one chain and replay them on another chain that has a lower nonce value when it will be equal to the nonce used in the OG transaction (first chain).

Impact

Permissions to execute a transaction coming from the Safe contract can be bypassed replaying signatures already used in another transaction on a different chain when the Safe.nonce() values are the same.

PoC

No response

Mitigation

Use ECDSA library functions

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant