ABI Hash Collisions¶
ABI Hash Collisions refer to a vulnerability type of the Application Binary Interface (ABI) encoding format, which smart contracts use to encode and decode calldata sent to functions. However, it can also be used by smart contract developers to encode and decode custom parameters. Two versions exist: abi.encode
and abi.encodePacked
. While more secure, the former results in a significantly larger result data size, thus raising the gas cost, especially when storing it. As a result, the latter (abi.encodePacked
) sees wider usage, albeit with increased risk due to the higher likelihood of hash collisions when dynamic variables are packed together. The hash is often used as a storage key or within a signed payload, with potential security ramifications.
This vulnerability arises when a hash calculation is used with packed ABI-encoded data that includes multiple variable-length arguments. Despite the hash remaining the same, shifting data across arguments can alter the payload semantics. This can trigger hash collisions in the Eternal Storage pattern, alter the meaning of signatures, and result in collisions when used as a mapping key.
A naive implementation of a royalty registry demonstrates the latter case:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
In this system, users are categorized into regular and premium ones. Royalties are disbursed by teams. Thus multiple regular and premium users are grouped together. An administrator adds the groups to the allowedPayouts
mapping, indicating their eligibility for reward claims. The claimRewards
function can then be triggered by anyone to initiate a payout where the contract transfers the ETH to team members according to their entitled amount.
Given that the team member data structures are ABI-encoded and hashed for their access key, a hash collision can be triggered by an attacker due to variable-length parameters being encoded side-by-side. The nature of this attack lies in the equivalence of the following hashes:
1 2 3 |
|
Thus, when calling claimRewards
, regular users can add themselves to the privileged users' array and receive a larger payout than warranted, siphoning funds from the system.