#37300 [BC-Insight] Incorrect Encoding of Negative *big.Int Values in MakeTopics

Submitted on Dec 2nd 2024 at 00:47:26 UTC by @CertiK for Attackathon | Ethereum Protocol

  • Report ID: #37300

  • Report Type: Blockchain/DLT

  • Report severity: Insight

  • Target: https://github.com/ledgerwatch/erigon

  • Impacts:

    • (Specifications) A bug in specifications with no direct impact on client implementations

Description

Brief/Intro

A vulnerability has been identified in the MakeTopics function within the accounts/abi/topics.go file of the codebase. The issue stems from the incorrect encoding of negative *big.Int values when generating topics for contract events.

Vulnerability Details

Affected Codebase: https://github.com/erigontech/erigon/tree/v2.61.0-beta1

In the MakeTopics function, the handling of *big.Int types is as follows:

https://github.com/erigontech/erigon/blob/v2.61.0-beta1/accounts/abi/topics.go#L45

			case *big.Int:
				blob := rule.Bytes()
				copy(topic[length.Hash-len(blob):], blob)

The rule.Bytes() method returns the absolute value of the *big.Int as a big-endian byte slice, disregarding the sign of the number. This means that negative integers are incorrectly encoded. For example, big.NewInt(-1).Bytes() returns [1], leading to the topic being encoded as 0x000...0001 instead of the correct two's complement representation 0xFFFF...FFFF.

https://github.com/golang/go/blob/master/src/math/big/int.go#L520

// Bytes returns the absolute value of x as a big-endian byte slice.
//
// To use a fixed length slice, or a preallocated one, use [Int.FillBytes].
func (x *Int) Bytes() []byte {
   // This function is used in cryptographic operations. It must not leak
   // anything but the Int's sign and bit size through side-channels. Any
   // changes must be reviewed by a security expert.
   buf := make([]byte, len(x.abs)*_S)
   return buf[x.abs.bytes(buf):]
}

Impact Details

The failure to correctly encode negative *big.Int values affects any functionality that relies on event topics generated by the MakeTopics function.

References

  • https://github.com/erigontech/erigon/blob/v2.61.0-beta1

  • https://github.com/ethereum/go-ethereum/pull/28764/

Proof of Concept

Proof of Concept

For simplicity, we can add the following test in TestMakeTopics https://github.com/erigontech/erigon/blob/v2.61.0-beta1/accounts/abi/topics_test.go#L30

       {
           "support negative *big.Int types in topics",
           args{[][]interface{}{
               {big.NewInt(-1)},
           }},
           [][]libcommon.Hash{
               {libcommon.HexToHash("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")},
           },
           false,
       },

The test will raise the error:

--- FAIL: TestMakeTopics (0.00s)
   --- FAIL: TestMakeTopics/support_negative_*big.Int_types_in_topics (0.00s)
       /Users/xxx/erigon/accounts/abi/topics_test.go:144: makeTopics() = [[0x0000000000000000000000000000000000000000000000000000000000000001]], want [[0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff]]
FAIL
FAIL    github.com/erigontech/erigon/accounts/abi   0.508s
FAIL

Was this helpful?