#37191 [BC-Insight] Unvalidated Field Names in Tuple ABI Parsing Causes Runtime Panic via reflect.StructOf

Submitted on Nov 28th 2024 at 03:23:27 UTC by @CertiK for Attackathon | Ethereum Protocolarrow-up-right

  • Report ID: #37191

  • 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 exists in the accounts/abi package where unvalidated fieldName from user-provided ABI definitions are used to construct struct types using reflect.StructOf. This can cause a panic when the invalid characters are included in the fieldName.

Vulnerability Details

In the type.go file of the accounts/abi package, the code dynamically constructs tuple types based on ABI component definitions as follow:

https://github.com/erigontech/erigon/blob/v2.60.10/accounts/abi/type.go#L158

	case "tuple":
		var (
			fields     []reflect.StructField
			elems      []*Type
			names      []string
			expression string // canonical parameter expression
		)
		expression += "("
		overloadedNames := make(map[string]string)
		for idx, c := range components {
			cType, err := NewType(c.Type, c.InternalType, c.Components)
			if err != nil {
				return Type{}, err
			}
			fieldName, err := overloadedArgName(c.Name, overloadedNames)
			if err != nil {
				return Type{}, err
			}
			overloadedNames[fieldName] = fieldName
			fields = append(fields, reflect.StructField{
				Name: fieldName, // reflect.StructOf will panic for any exported field.
				Type: cType.GetType(),
				Tag:  reflect.StructTag("json:\"" + c.Name + "\""),
			})
			elems = append(elems, &cType)
			names = append(names, c.Name)
			expression += cType.stringKind
			if idx != len(components)-1 {
				expression += ","
			}
		}
		expression += ")"

		typ.TupleType = reflect.StructOf(fields)
		typ.TupleElems = elems
		typ.TupleRawNames = names
		typ.T = TupleTy
		typ.stringKind = expression

The fieldName is taken directly from the ABI component's Name without validation. However, the reflect.StructOf function requires that all field names be valid with the following check. Otherwise, the panic will rise.

https://github.com/golang/go/blob/master/src/reflect/type.go#L2205

It is worth noted a similar issue has been fixed in go-ethereum: https://github.com/ethereum/go-ethereum/pull/24932

Impact Details

Any program that invokes the vulnerable code will panic with an invalid field name.

References

  • https://github.com/golang/go/blob/master/src/reflect/type.go#L2205

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

Proof of Concept

Proof of Concept

We can reuse the test from go-ethereum to verify the issue:

Output:

Was this helpful?