cgra's

2021-11-12

TRB Defect Exhibition - Two DoS Classics

Filed under: TRB — cgra @ 13:13:02

The denial-of-service classics for TRB presented here are:

  • the unbounded mempool and
  • the blockchain checkpoints aging over time, which make it possible to spam a node with bogus blocks, using more and more powerful, but affordable second-hand mining hardware.

I consider them classics, because I can't imagine they weren't widely known already long ago. Why I bothered to mention these anyway, is because I'm in the process of enumerating a bunch of other TRB DoS issues too, with similar effects.

On the other hand, I haven't fully tested either of these theories in practice, so it's always possible I am imagining things... Please correct, if seeing false claims.

Unconfirmed transactions, aka mempool

TRB mempool keeps unconfirmed transactions in two sets: A relay set contains all the transactions it has received from other nodes (or from the node operator) within the last 15 minutes. These transactions are relayed to all the other peers. Variables mapRelay and vRelayExpiration implement the relay set (declarations, writes, 'getdata' response filtering) .

The other set is the mining set. It originally made sense for the TRB operator to mine blocks himself, so these transactions are the longer-kept transactions, besides the relay set, that the node does not bother relaying anymore, but will keep for putting into new blocks. Variables mapTransactions and mapNextTx implement the mining set (declaration, 11 other mapTransactions occurrences in main.cpp).

The specific feature that mapNextTx exists for, is permanently disabled. Therefore, mapNextTx is an easily removable, unnecessary piece. (declaration, ptxOld always NULL (another, depending construct for easy removal), write occurrence 1, write occurrence 2).

While the relay set shrinks over time, transactions are also dropped from both sets when they show up in newly accepted, best-chain blocks.

TRB mempool will grow as long as valid transactions keep coming in, and don't get accepted into new blocks fast enough, or, node runs out of memory.

Finally, the anyone-can-spend transactions (SegWit, Taproot(?)) might make a particularly easy tool for generating bogus transactions to fill TRB mempool with.

Spam blocks

mapBlockIndex keeps an in-RAM index of downloaded, valid blocks, losing chains included (declaration, index accepted blocks, ~50 total occurrences).

The memory cost of the index is possibly well over 108 bytes1 per entry (entry type).

TRB implements hard-coded checkpoints for freezing the older end of the main chain, so that no branch originating from the frozen side cannot be valid anymore, and automatically rejected.

Because the last TRB checkpoint is so old (last checkpoint, validation by checkpoint), today’s second-hand mining hardware is turning into a low-cost tool for generating spam blocks, starting from right after the last checkpoint, because the mining difficulty back then was much lower.

The attacker could choose anything between empty and full bogus blocks, depending on the proportion he wanted the victim’s RAM and disk to be filled in.

Generating spam blocks, an example

The following method assumes an applicable, 14Th miner. An Antminer S9 could be such a miner, but I don’t know for sure.

First, get the miner and figure out how to use it, if not already familiar.

Start building on block height 169342. The next block, your first spam block, will be the last block of the same difficulty adjustment period the last checkpoint was in. The timestamp of your spam block 169343 should be at least 8 weeks later than the first block in the same difficulty adjustment period, block at height 167328.

The point of this is to immediately gain the maximum drop in difficulty in our new-born spam branch. The starting difficulty bits are 0x1a0c309c, and after the above difficulty manipulation, would be 0x1a30c270. The second spam block, height 169344, will have 1/4 difficulty of spam block 169343.

The block 169343 should finish within 20 to 32 min of mining. Create 2016 lower-difficulty blocks continuing the new spam chain.

Mining the lower-difficulty blocks should finish in ~7.34 days. The timestamp of spam block 171359, should again, be at least 8 weeks later than timestamp of block 169344, the first of the same difficulty adjustment period.

Repeat this difficulty reduction step as many times as necessary.

After the difficulty is brought down to a comfortable level, you can simply start mining competing blocks, all of the same height and time, and the stream of spam blocks will just keep flowing, and will never reach the current timestamp of the victim node, which otherwise could end the spam game.

  1. bnChainWork’s variable-length, big-integer contents were not taken into account, only the constant-length bits found inside the OpenSSL bignum_st typedef. []

1 Comment »

  1. My proposed solution to the spamola (and would speed up sync substantially as well) was "cement" -- an optional list of known-good block hashes fed in at bootup.

    Comment by Stanislav Datskovskiy — 2021-11-12 @ 16:16:18

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by a less-enormous pile of '???'