#37530 [BC-Insight] Deposits can be completely DoSed due to incorrect transaction construction

Submitted on Dec 7th 2024 at 13:59:36 UTC by @n4nika for Attackathon | Stacks

  • Report ID: #37530

  • Report Type: Blockchain/DLT

  • Report severity: Insight

  • Target: https://github.com/stacks-network/sbtc/tree/immunefi_attackaton_0.9/signer

  • Impacts:

    • Network not being able to confirm new transactions (total network shutdown)

Description

Note

This issue was found through testing, meaning I show and prove the impact in this issue through a PoC but do not provide a full rootcause analysis. I plan on following up to this issue once that is finished.

Summary

utxo.rs::construct_transactions incorrectly packages deposit transactions always into one big transaction object. This causes the coordinator to always time out if there are more than about 40 deposit requests per bitcoin block. This, in turn, allows an attacker to basically permanently DoS the signers, preventing any deposits.

Finding Description

In transaction_coordinator.rs::construct_and_sign_bitcoin_sbtc_transactions, we call pending_requests.construct_transactions to construct a vector of transaction objects we want to get signatures for and submit to Bitcoin. The PoC below shows that, even when we have a lot of deposits, this returns a vector with one very large transaction object.

Since we then iterate over the transaction_package we got, trying to sign and submit every transaction, we always do one iteration with a very large transaction (depending on how many deposit requests we currently need to fulfill):

In sign_and_broadcast, we then coordinate_signing_rounds. These then time out due to the request being too big.

Impact

This enables an attacker to submit 40 deposit requests in one block and bring the whole system down. Note that 40 deposits in one block can even be reached during completely normal operations!

I want to note that in order for this to be triggered, we need to submit 40 deposits within one block ONCE. This is because when we get the pending_requests in construct_and_sign_bitcoin_sbtc_transactions, we use the default context_window of 10000 blocks!

This now means that once we reach 40 deposits in one block, the system is DoSed for AT LEAST 10000 blocks which is ~69 days at an average block time of 10 minutes. Note that the actual DoS would probably be permanent since we will get more and more deposit requests which just keep on cluttering the database and prolong the downtime of the system indefinitely.

Mitigation

As far as I saw for now, the rootcause lies in how the transaction_package is constructed, meaning that needs to be fixed. As noted in the beginning, I will follow up with an in-depth rootcause analysis.

Proof of Concept

PoC

In order to show this please apply this git diff and execute the test with cargo test --package signer --test integration -- transaction_coordinator::sign_bitcoin_transaction_poc --exact --show-output --ignored --nocapture.

The PoC does the following:

  1. create 40 deposit requests within one btc block

  2. run the signing process

We can see that sign_and_broadcast returns a timeout error and RESULT is None, showing that all the deposits failed to execute. (Sometimes the testsuite itself also fails)

Last updated

Was this helpful?