Attackathon _ Fuel Network 32537 - [Smart Contract - Low] Different data types can be used when init
Submitted on Tue Jun 25 2024 18:46:46 GMT-0400 (Atlantic Standard Time) by @Schnilch for Attackathon | Fuel Network
Report ID: #32537
Report type: Smart Contract
Report severity: Low
Target: https://github.com/FuelLabs/sway/tree/7b56ec734d4a4fda550313d448f7f20dba818b59
Impacts:
Compiler bug can lead to unintended behavior in Rust SDK or sway smart contracts.
Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield
Description
Brief/Intro
In Sway, arrays normally can only have one data type. However, due to a bug during array initialization, different numerical data types can be used. This can result in larger numbers appearing in the array than should be possible. When such a number is returned from a function, it may overflow in the Rust SDK and consequently be handled based on an incorrect value.
Vulnerability Details
In Sway, when an array is initialized without specifying the exact type, it is possible that the elements may be a mixture of the data types u16, u32, and u64. This is because during type checking, there is no verification that all values in an array have the same data type. The data type of the elements of the array is simply determined by the data type of the first element in the array, without checking what data types the other elements have (See 1. Reference). The bug is caught for all data types except u16, u32, and u64 because these data types are all converted into a u64 in the ir . This occurs when the IR is verified with the function verify_store, where the data type of each element in the array is checked again (See 2. Reference). The problem when these three different data types occur in one array is that all elements in the array, after initialization, assume the data type of the first element. So, if the first element is, for example, a u16 and all others are u64s, u16 values larger than u16::max() can occur in the array. There isn't an overflow, but the numbers in the array are simply larger than they should be. This leads to further issues, especially when these too large u16 values are returned and used further in the Rust SDK, where they would then overflow.
Impact Details
This bug can have various impacts depending on what the array is used for. Here is one scenario in which this bug can lead to loss of funds:
In a Sway smart contract, during the initialization of an array, the first element is set to a number of type u16, and the second element is assigned a number representing a token amount of type u64. If now the second element is returned from the function using Rust SDK, and based on this value a transaction is executed, it results in an incorrect token amount, potentially causing a user to lose tokens.
References
https://github.com/FuelLabs/sway/blob/7b56ec734d4a4fda550313d448f7f20dba818b59/sway-core/src/semantic_analysis/ast_node/expression/typed_expression.rs#L1833
https://github.com/FuelLabs/sway/blob/7b56ec734d4a4fda550313d448f7f20dba818b59/sway-ir/src/verify.rs#L1024-L1032
Proof of concept
Proof of Concept
Setup
To execute the PoC, a new Sway project must first be created and a test template generated with Rust. The following commands can be used for this:
forc new array-init-bug
cd array-init-bug
cargo generate --init fuellabs/sway templates/sway-test-rs --name array-init-bug --force
In src/main.sw, the following code must now be added:
The code is intended to demonstrate the bug in a Sway smart contract. To test the contract, the following test can be inserted into the file tests/harness.rs:
Run the PoC
To execute the POC, the following commands must now be run:
forc build
cargo test array_init_test -- --nocapture
Last updated