👮
Contract Cops
  • Mastering Ethereum Book
    • What is ethereum?
    • Tokens
    • Oracles
    • Decenralized Applications(DApps)
    • The Ethereum virtual machine
    • Ethereum basics
    • Ethereum clients
    • Cryptography
    • Wallets
    • Transactions
    • Chapter 7 - Smart Contracts & Solidity
    • Side Notes
      • Tokens
      • Smart Contracts and Solidity
  • Cryptography
    • Ethereum Cryptography - Cheatsheet
    • Assymetric vs symmetric cryptography
    • ECDSA vs RSA
    • Elliptic curves and ECDSA
    • Sha-256 Example
    • Sha-256
    • What are the different steps in SHA-256?
  • Ethereum Blocks
    • Block Headers
  • Learning Solidity
    • Storage vs memory
    • Upgradeable contracts
      • Proxy pattern in smart contracts
  • PoS
    • Proof of stake
  • PoW
    • PoW
  • Tokens
    • ERC-1155
    • ERC20
  • Cryptonomics
    • Automated market makers
    • Collateral Tokens
    • Collateralized Stablecoin
    • Fiat currency
    • Liquidity pool
    • Open Position: Meaning and Risk in Trading
    • Slippage
    • Spot price
  • Common Attack Vectors
    • Checking access control
    • Access control issues on critical functions
    • Account Existence Check for low level calls
    • Account Existence Check
    • Common attacks with contract/EOA addresses
    • Arithmetic under/overflow
    • Assert Attack
    • Assert require revert
    • Assert Violation
    • Bad Interface DOS
    • Bad pragma and compiler
    • Block Timestamp Manipulation
    • Bypassing contract check
    • Code With No Effects
    • Code size check vulnerability
    • Constructors with Care
    • Default Visibilities
    • Delegatecall
    • Delegatecall
    • Denial of Service (DoS)
    • DoS with block gas limit
    • Entropy Illusion
    • External contract referencing
    • Flash Loan Attack
    • Floating Point and Precision
    • Function selector abuse
    • Function selector abuse
    • Smart contract gas griefing
    • Hash collision parameters
    • Hash Collisions With Multiple Variable Length Arguments
    • Imprecise arithmetic
    • Improper Array Deletion
    • Incorrect array deletion
    • Incorrect interface
    • Insufficient Gas Griefing
    • Loop through long arrays
    • Message call with hardcoded gas amount
    • Not enough gas for ether transfer
    • Precision Loss in Calculations
    • Oracle Manipulation
    • Public Burn Function
    • Read-only reentrancy
    • Race Conditions/Front Running
    • Reentrancy Attacks
    • Reentrancy
    • Requirement Violation
    • Right-To-Left-Override control character (U+202E)
    • Shadowing State Variables
    • Short Address / Parameter attack
    • Signature Malleability
    • Signature Replay
    • Transaction Order Dependence
    • Tx.Origin Authentication
    • Unchecked CALL Return Values
    • Unexpected ether
    • Uninitialized Storage Pointers
    • Unsafe Ownership Transfer
  • EIP's
    • EIP155
    • EIP55
  • PoW
    • Ethash
    • Scrypt - RFC 7914
  • Questions for self evaluation
    • Questions 23/04/2023 (Nr: 84)
    • Usability guide for questions
  • Frequently asked questions
    • What is the difference between transaction and message?
    • What is the use of a interface or function without implementation?
  • UsefulResources
Powered by GitBook
On this page
  • Vulnerability
  • Prevention
  1. Common Attack Vectors

Signature Malleability

Surprisingly, signatures can be altered without the possession of the private key and still be valid.

That's what we are going to observe here.

The EVM specification defines several so-called 'precompiled' contracts one of them being

ecrecover

ecrecover() is a very useful Solidity function that allows the smart contract to validate that incoming data is properly signed an expected party.

It just executes the elliptic curve public key recovery.

So what is the vulnerability you may ask?

A malicious user can slightly modify the three values v, r and s to create other valid signatures.

A system that performs signature verification on contract level might be susceptible to attacks if the signature is part of the signed message hash.

Valid signatures could be created by a malicious user to replay previously signed messages.

Let's look at some code to spot where is exactly the problem:

function transfer(
        bytes _signature,
        address _to,
        uint256 _value,
        uint256 _gasPrice,
        uint256 _nonce)
    public
    returns (bool)
{
  bytes32 txid = keccak256(abi.encodePacked(getTransferHash(_to, _value, _gasPrice, _nonce), _signature));
  require(!signatureUsed[txid]);

  address from = recoverTransferPreSigned(_signature, _to, _value, _gasPrice, _nonce);

  require(balances[from] > _value);
  balances[from] -= _value;
  balances[_to] += _value;

  signatureUsed[txid] = true;
}

As you can see, here on this line:

  bytes32 txid = keccak256(abi.encodePacked(getTransferHash(_to, _value, _gasPrice, _nonce), _signature));

the txid is including the _signature in the message hash to check if previously messages have been processed by this contract. That where the vulnerability lies.

But let's now focus on the ECDSA to understand the full picture.

Here’s the curve that is used for Ethereum (& BTC), which is Secp256k1.

Secp256k1 defines a group of points, they are basically the points on the elliptic curve, and for each (x, y) combination x && y are elements of the field Zp, where Zp is a field for p prime.

This curve uses the following formula

p - prime number(a very large number)
n - order of the group(number of points on the EC)

Now, when we are signing a transaction, we are making new random private key which is temporary

This is extremely important to understand, becuase we want to achieve non-determinism in the ECDSA so the reverse engineering of the private key is impossible!

After this, we are using this this temporary private key point to generate a corresponding P on the EC.

P = G,
where G is the generator point
(G = {x = 55066263022277343669578718895168534326250603453777594175500187360389116729240, y = 32670510020758816978083085130507043184471273380659243275938904335757337482424}),
k is your temporary private key (a number in the range [1...n-1])

This P is the public key point that corresponds with our temporary private key k

Remember, P is a point. So from this P, we get the x-coordinate as our r value. In other words:

r = P's x coordinate

We are ready to calculate the signature proof. Let's see what is the formula:

Where:
s - the signature proof,
z - the message hash,
r - P's x coordinate,
e - Our real private key,
k - our temporary private key.
n - prime order of the secp256k1 group

And if I can simplify this for you:

s = ((messageHash + P's x coordinate*your private key) + k^(-1)) (mod n)

And there you go, now we have the r and s values

But now, let's return for a bit to the r value, like I said it was the x coordinate of the temporary public key.

Let's visualize this point on the curve now:

But if you think about it, the point P isn't the only point on the curve that has the same x'coordinate.

If we draw stright line from the x coordinate of point P up to the other side of the EC, we will observe that this straight line will intersect the EC at the exact x coordinate as point P.

So in a nutshell we will have other point P, let's call it P2 that has the same x coordinate, but with other y coordinate.

Let's take a look:

And here comes variable v in to the game.

The ECDSA has to know which point was used when creating the signature proof s value so that the signer address can be recovered.

This is where the value v comes in to play, it simply acts as an indicator for which side of the EC the actual public key that was used is on.

And here comes the vulnerability.

Vulnerability

After we now have the two points P2 and P, we can compute a signature proof value for both of them hence we can make a double spending from a contract.

Prevention

Before I tell you how to prevent this, you know that we found the s value (the signature proof) for the point P. Well now an attacker could do the same thing but for the other point P2.

Essentially find the signature proof ot the point P2.

So this can be done by computing the -s

And since we are working in Zn, we can simply compute n-s and we have our attack s.

And now after this exhausting load of information, how do we prevent this situation from occurring?

The most widely accepted fix is to limit the s value to the lower bound.

There are two s values that can be used to create a valid signature: s and n-s.

Therefore there is one

s > n/2 

and another that is:

s < n/2

We have to limit the signature to use only the s from a single side.

Let's see an example:

This Open Zeppelin ECDSA library prevents this vulnerability from occuring by limiting s value to the lower bound.

Here is a link to the library: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol

PreviousShort Address / Parameter attackNextSignature Replay

Last updated 2 years ago

Alt text
Alt text
Alt text
Alt text
Alt text
Alt text
Alt text