Attackathon _ Fuel Network 32835 - [Smart Contract - Insight] sway compiler doesnt prevent function
Submitted on Thu Jul 04 2024 12:13:14 GMT-0400 (Atlantic Standard Time) by @cyberthirst for Attackathon | Fuel Network
Report ID: #32835
Report type: Smart Contract
Report severity: Insight
Target: https://github.com/FuelLabs/sway/tree/7b56ec734d4a4fda550313d448f7f20dba818b59
Impacts:
compiler bug - impact is based on the compiled contract
Description
Brief/Intro
The Sway compiler doesn't prevent function selector collisions. If two ABI functions share the first 4B in the hash of their signature, then it's undefined which of them will be called. This can result in unintended actions such as transferring tokens or renouncing ownership.
Vulnerability Details
The compiler with the v0 encoding uses 4B of the signature's hash as the function selector (similarly to the ABI defined by Solidity). When an external call is made, the function that will be executed is defined by this selector. We walk the selectors stored in the preamble and compare them with the input selector. If a match is made, then we jump to the corresponding function.
However, unlike Solidity or Vyper, Sway doesn't check for selector collisions. That means if 2 or more functions share the same selector, then the dispatch mechanism is broken because we dispatch on the first match.
Consider the attached PoC, which demonstrates unintentionally renouncing the ownership. In the test, we call the function way,
but as it can be seen from the assert, the function never gets called, and instead, function fpeu
is called. fpeu
gets called because it has the same selector as way
.
We modified the compiler to print the selector values:
And indeed, we have the same values.
Impact Details
If a collision occurs, then the impact can be critical and depends on the actual logic of the corresponding smart contract. It can result in unintentionally sending funds to the wrong address or renouncing ownership.
If we consider sha256 as a random oracle, truncation to 4B, and the birthday paradox, we can see that we need about (2^32)^0.5=2^16=65536 hashes to get a 50% probability of a collision.
Proof of concept
Proof of Concept
To run the PoC, start forc
from the root of the project: forc test --no-encoding-v1
Forc.toml
src/main.sw
To find the collision we used the following script:
Last updated