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

Was this helpful?