Submitted on Sat Jul 13 2024 17:57:02 GMT-0400 (Atlantic Standard Time) by @nikitastupin for Attackathon | Fuel Network
Report ID: #33186
Report type: Smart Contract
Report severity: Medium
Target: https://github.com/FuelLabs/sway-libs/tree/0f47d33d6e5da25f782fc117d4be15b7b12d291b
Impacts:
- Temporary freezing of funds for at least 1 hour
- Temporary freezing of funds up to 1 hour
- Permanent freezing of funds
https://github.com/FuelLabs/sway-libs/blob/0f47d33d6e5da25f782fc117d4be15b7b12d291b/libs/src/bytecode/utils.sw#L97-L133
The function _compute_bytecode_root
enters an infinite loop when the bytecode is empty. This issue occurs in functions like verify_predicate_address()
, verify_predicate_address_with_configurables()
, and verify_contract_bytecode()
within sway_libs::bytecode::*
.
The following minimal sample Sway code triggers the issue:
fn test(address: ContractId) {
// empty bytecode
let mut bytecode = Vec::<u8>::new();
// infinite loop
verify_contract_bytecode(
address,
bytecode
);
}
The infinite loop occurs because the logic to break it, as shown in lines 127-129 of the code here, is not reached when the bytecode is empty:
// If we only have one node left then that is the root
if size == 1 {
break;
}
If an attacker controls the bytecode or address of the Contract, this issue prevents the transaction from being executed and users' funds could get stuck.
Let's consider the following scenario: there is a contract responsible for managing the queue of asset withdrawals for users. This contract utilizes a vulnerable bytecode primitive from sway_libs to invoke the compute_bytecode_root()
function. The issue arises when the attacker has the ability to select the ContractId
from which the bytecode is obtained and then supplied to the aforementioned compute_bytecode_root()
function. Consequently, this vulnerability allows the attacker to obstruct the queue, resulting in a potential blockage of funds belonging to other users in the queue.
Install forc and cargo:
curl https://install.fuel.network | sh
source "$HOME/.bashrc"
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
Download the proof of concept:
mkdir poc
cd poc
mkdir src tests
curl -O https://gist.githubusercontent.com/nikitastupin/8189e45b671dad58004192bd48e2e262/raw/ed4c10a5213cefdd27eec4548a7348604373f8c9/Cargo.toml
curl -O https://gist.githubusercontent.com/nikitastupin/8189e45b671dad58004192bd48e2e262/raw/ed4c10a5213cefdd27eec4548a7348604373f8c9/Forc.toml
curl -o tests/harness.rs https://gist.githubusercontent.com/nikitastupin/8189e45b671dad58004192bd48e2e262/raw/ed4c10a5213cefdd27eec4548a7348604373f8c9/harness.rs
curl -o src/main.sw https://gist.githubusercontent.com/nikitastupin/8189e45b671dad58004192bd48e2e262/raw/ed4c10a5213cefdd27eec4548a7348604373f8c9/main.sw
Run the proof of concept:
forc build && cargo test -- --nocapture
It will stuck in an infinite loop.