Attackathon _ Fuel Network 32965 - [Blockchain_DLT - Critical] Messages to L included even on revert
Last updated
Was this helpful?
Last updated
Was this helpful?
Submitted on Mon Jul 08 2024 15:33:31 GMT-0400 (Atlantic Standard Time) by @NinetyNineCrits for
Report ID: #32965
Report type: Blockchain/DLT
Report severity: Critical
Target: https://github.com/FuelLabs/fuel-core/tree/v0.31.0
Impacts:
Direct loss of funds
Messages to the L1 bridge are included in the block even in case of reverts. This allows theft of all tokens from the bridge.
The function executor/src/executor.rs::update_execution_data
adds all message_ids from the MessageOut receipts of the current tx to the execution data even if the tx itself has reverted:
This means its possible to send out messages to the L1 but revert the tx, which un-does the burn of the bridged tokens. This fake-withdraw can be repeated over and over again and messages can still be relayed on L1, allowing theft of all tokens from the bridge
Theft of all tokens from the bridge on L1
Not applicable
Link to the gist: https://gist.github.com/99crits/3ee583a149bc41ca62e76ccfbf7c0e89
This poc is based on the tests/bridge_erc20.ts
file in the fuel-bridge repository. It demonstrates the following flow:
Attacker and victim both deposit the same amount of the same token
Attacker withdraws 2 times, first time he reverts his tx at the end and the second time follows the regular flow. He can relay twice and will have double the amount of tokens he originally deposited.
Victim withdraws, L2 side will be successful and his tokens will be burned. The relay on L1 will fail, due to underflow (no tokens left)
This test requires a minor modification to the message_proof
endpoint on the client. Currently this endpoint does an early return if the tx has not succeeded:
However any attacker can run his own client and modify the endpoint like this:
All the necessary data for the proof is already on-chain, this modification just allows an easy retrieval of the necessary message-proof.
So the setup steps are the following:
Clone fuel-core
from commit c5b425e2b3e05899e83bed0090865a7f4ec30c78 (latest one as of 2024-07-08)
Add the line Some(TransactionStatus::Failed { block_height, .. }) => block_height,
as additional matching branch to query/message.rs
as shown above
Run docker build -t 99crits-fuel-core . -f deployment/Dockerfile
(command from the README with custom tag)
Now in the fuel-bridge
repository: In docker/fuel-core/Dockerfile
change the FROM
directive to FROM 99crits-fuel-core:latest
Change to fuel-bridge/docker
directory and run make clean
and then make up
Then, go to the fuel-bridge/packages/integration-tests/
directory and run pnpm install
Finally, paste the gist from above as bridge_erc20_multi_withdrawal_using_reverts.ts
into integration-tests/tests
and then run pnpm mocha -b -r ts-node/register 'tests/bridge_erc20_multi_withdrawal_using_reverts.ts'