Attackathon _ Fuel Network 32302 - [Smart Contract - Low] Src ContractConfigurables hash collision
Last updated
Was this helpful?
Last updated
Was this helpful?
Submitted on Mon Jun 17 2024 17:31:27 GMT-0400 (Atlantic Standard Time) by @anatomist for
Report ID: #32302
Report type: Smart Contract
Report severity: Low
Target: https://github.com/FuelLabs/sway-standards/tree/348f7175df4c012b23c86cdb18aab79025ca1f18
Impacts:
Incorrect library function behaviors
src12
Hash
trait implementation for ContractConfigurables
allows collision between different configurations.
ContractConfigurables
is a vector of (offset: u64, data: Vec<u8>)
and represents the interchangeable config for contracts. The hash
method is often used to generate a single identity value that could be used to track or retrieve the configurations or contract from storage. An example of this can be found in the example .
However, there are a few flaws in the hash implementation.
Due to the u64
offset casted as a raw_ptr
in the asm
block, we're doing an arbitrary memory read on offset_ptr.copy_bytes_to(buffer, 4);
. This is clearly incorrect because offset
should be a pointer into the bytecode, and not the current vm memory. Hashing based on the data in vm memory doesn't make sense here.
If we fix the type casting and correctly use address storing offset instead of treating offset as a pointer, the hash still suffers from collision because only the first 4 bytes of the u64
offset is included. Fuel data is stored in big endian, which means the offset should never execeed u32::max
, and the first 4 bytes used in hashing will always be 0.
The encoding of the Vec<u8>
data also allows for more collisions. Assuming both incorrect casting and offset length are fixed, the two configs [(0, [0]), (10, [0, 0, 0, 0, 0, 0, 0, 11, 0])]
and [(0, [0, 0, 0, 0, 0, 0, 0, 0, 10]), (11, [0])]
will still have the same hash.
Without sorting the configuration entries, functionally equivalent configurations with entry orders swapped could have different hashes.
Depending on usage, this may lead to out-of-bound reads, hash collision for different configs, or multiple hashes for functionally identical configs. If ContractConfigurables
is used as the key in factory contracts, it might allow attacks to overwrite entries for other contracts. The exact impact depends on functionality of contracts involved.
https://github.com/FuelLabs/sway-standards/blob/87b39dfcd2a0fcad9d7092b0c9937ae66e3f9299/standards/src/src12.sw#L110
https://github.com/FuelLabs/sway-standards/blob/2206de75bdb5fcabfc90d33dab17878a4d7efe2f/examples/src12-contract-factory/with_configurables/src/with_configurables.sw#L99
This PoC demonstrates that offset is incorrectly treated as a pointer, and could easily have hash collisions or different hashes for the same content.