https://github.com/erigontech/erigon ), though it does not seem to be exploitable at this moment du...
Submitted on Nov 25th 2024 at 19:13:18 UTC by @CertiK for Attackathon | Ethereum Protocol
Report ID: #37113
Report Type: Blockchain/DLT
Report severity: Low
Target: https://github.com/ledgerwatch/erigon
Impacts:
(Specifications) A bug in specifications with no direct impact on client implementations
Description
Brief/Intro
The utility function getData()
mishandles an overflow case, which would lead to an out-of-range panic.
Vulnerability Details
The utility function getData()
is utilized to take a subslice of a byte slice specified with the start position and size.
The implementation of getData()
proceeds as follows:
Get the length of the input
data
;Reset the start position
start
as the length of the input ifstart
is larger than length;Add the
start
with size to getend
;Reset the
end
as the length of the input ifend
is larger than length.
Besides the same result, function getDataAndAdjustedBounds()
also returns the start
and end - start
.
https://github.com/erigontech/erigon/blob/v2.60.10/core/vm/common.go#L55
The issue lies in the step 3 that the addition of two uint64 integers, end := start + size
could lead to overflow. The overflow would result in out-of-range panic when taking the subslice data[start:end]
. In particular, the size
is extremely large, and start
is less than the length of the input.
The two utility functions are called in multiple places with non-constant start
and size
, including the ModExp precompile contract and opcode CODECOPY and EXTCODECOPY.
The ModExp precompile contract serves as a precompile contract to compute the modular exponentiation in big integers (i.e., base ** exponent mod module), outlined in the https://eips.ethereum.org/EIPS/eip-198, https://eips.ethereum.org/EIPS/eip-2565.
The entry point of all precompile contracts is the function RunPrecompiledContract()
that invokes function RequiredGas()
to compute the required gas to run the precompile contract and Run()
to perform the actual execution.
https://github.com/erigontech/erigon/blob/v2.60.10/core/vm/contracts.go#L212
In the Run()
of ModExp precompile contract, the function getData()
is used to get the values of the base, exponent and module based on the specified byte length of base, exponent and module.
The input of the ModExp precompile contract Run()
is a byte slice :
baseLen
is the first 32 bytes of the input (position 0 ~ 32 );expLen
is the second 32 bytes of the input (position 32 ~ 64) ;modLen
is the third 32 bytes of the input (position 64 ~ 96);base
is the value stored in the position starting at 96 and with sizebaseLen
;exponent
is the value stored in the position starting at96+baseLen
and with sizeexpLen
;module
is the value stored in the position starting at96+baseLen+expLen
and with sizemodLen
;
https://github.com/erigontech/erigon/blob/v2.60.10/core/vm/contracts.go#L428
In the above invocations, the out-of-range panic insidegetData()
could be triggered if baseLen+expLen
is overflowed, particularly, baseLen
is small but expLen
is extremely large.
However, the gas cost of this execution is max of uint64, which makes the attack impossible. Similarly, the situation is applied in the opcodes CODECOPY and EXTCODECOPY with massive gas cost due to large memory expansion.
Impact Details
Given the current gas constraints, the issue does not appear to be exploitable at this time. However, as utility functions, improper usage or potential future adaptations could lead to unexpected results.
References
https://github.com/erigontech/erigon
https://eips.ethereum.org/EIPS/eip-198
https://eips.ethereum.org/EIPS/eip-2565
Proof of Concept
Proof of Concept
The PoC section provides a unit test with a crafted input to trigger the out-of-range panic inside the function getData()
.
Set the input of
RunPrecompiledContract()
as follows. The parse of input shows that baseLen is 1 and expLen is max uint64:
Specify the gas as max uint64, the test script is as follows:
Run the unit test to check it triggers the out-of-range panic:
Was this helpful?