Ho fatto una nuova versione del documento, molto piu' efficace della precedente, per diversi motivi:
1) funziona
2) e' il compendio di settimane di studio e discussioni qui nel thread
3) ci sono diversi riferimenti a casi precedenti e ben documentati
4) Introduce tutta una serie di concetti che se anche non usati (BlockStuffing, MEV)
dovrebbero mettere molti dubbi sullo stato della rete ad un lettore minimamente tecnico (come e' successo qui nel thread)
5) e' meno tecnico-spinto (no assembler evm o amenita' simili) quindi piu' comprensibile a tutti.
6) Metto anche due esempi di smart contract fuzionanti (provati con la evm geth)
7) Indico una sommaria metodologia di esecuzione.
questa potrebbe essere la versione da mettere su reddit.
Se ci date una letta e mi indicate svarioni, mi fate un cortesia.
---------------------------------------------------------------
Una strategia di attacco alla rete ethereum basata sulla tecnica BlockStuffing e lo smart contract DeathStarDi gbianchi bitcointalk.org
questo studio nasce da alcune osservazioni:
1) nella rete ethereum non esiste nessun concetto di "smart contract vietato", la rete e' permissionless
ossia qualsiasi utente puo' immettere in rete qualsiasi tipo di codice, basta che il codice sia formalmente corretto
e che paghi il caricamento e l'esecuzione del codice.
2) L'unico meccanismo per "governare" l'esecuzione del codice e' il fatto che l'esecuzione di qualsiasi
smart contract costa gas, proporzionale al numero di istruzioni eseguite ed al tipo di istruzioni.
Ma non necessariamente uno Smart Contract deve eseguire operazioni utili, puo' semplicemente eseguire un loop
che "brucia" gas senza nessuna logica elaborativa.
3) Una volta immesso, il codice e' immutabile, quindi non vi e' modo di "togliere di mezzo" lo smart contract dalla rete,
a meno di un hard fork tipo DAO. Ma mentre Dao sfruttava un bug, qui viene utilizzata l'architettura di base di ethereum,
rendendo veramente difficile la progettazione di un hard fork abbastanza efficace.
4) Ogni blocco ha una dimensione massima definita non dalle dimensioni in Byte, ma dal massimo GAS spendibile nel blocco.
Dopo l'hard-fork London, la dimensione "normale" del blocco e' variabile attorno ad una media di 15.000.000 di gas,
e puo' aumentare fino a 30.000.000 di gas in base alla domanda della rete, con un processo chiamato tâtonnement.
Sinteticamente la massima dimensione di un blocco e' data da BlockGasLimit.
5) in passato sono gia' stati eseguiti degli attacchi con la tecnica di BlockStuffing e non sono state trovate soluzioni
strutturali efficaci. [3]
3.3.3 DoS with Block Stuffing (V31
). This vulnerability was first observed from the Fomo3D contract [23].
The vulnerability entails only the attacker's transactions being included in the newly mined blocks
while others are abandoned by miners for a period of time. This can happen when the attacker offers a higher
gasPrice to incentivize the miners to select the attacker's transactions. This vulnerability is caused by the greedy
mining incentive mechanism. At the moment of writing, there is no solution to prevent this vulnerability.
6) Possono inoltre essere utilizzate tecnologie avanzate di MEV [4][5] per ottimizzare al massimo la possibilita' che il nostro
smart contract sia incluso nel blocco successivo, scandagliando la mempool e verificando quali sono le fee con gwei/gas piu' alto
per eseguire la transazione con la massima probabilita' di essere inclusa.
In base a queste osservazioni, si puo' progettare uno smart contract "DeathStar" la cui esecuzione costi esattamente il numero di
gas necessari a riempire un blocco, e che quindi "bruci" ethereum solo per competere con gli altri smart contract nel riempimento di un blocco.
Sinteticamente,
la transazione sta comprando l'intero spazio di un blocco ethereum, e quindi non ne resta a disposizione
per l'esecuzione di altri smart contract.
Motivazioni per un attacco BlockStuffing:Un gruppo di attaccanti potrebbe essere incentivato per svariati motivi a bruciare ethereum per mettere in difficolta' la rete, ad esempio:
- ad esempio essere i sostenitori di un'altra moneta competitor, non soggetta a queto tipo di problema (ad esempio Bitcoin)
- oppure organizzare uno short su ethereum prima dell'attacco, congestionare la rete ethereum e ricoprirsi a prezzi piu' bassi,
recuperndo i soldi dell'attacco e guadagnandoci
- rallentare e/o indirizzare a proprio vantaggio uno o piu' degli svariati smart contract che girano su ethereum, ad esempio
posticipare l'esecuzione di altri smart contract per avvantaggiarsi di certe condizioni
(estrazioni a premi, aste online, ICO, transazioni finanziarie su DEX, Defi, ecc... come e' gia' stato fatto [2])
In generale qualsiasi persona o gruppo con sufficenti mezzi e con un qualsiasi tipo di interesse alla decadenza della rete ethereum
e/o degli smart contract che vi girano, potrebbe usare questa linea di attacco.
Per fare una stima del costo necessario, considerare che viene minato un blocco ethereum ogni circa 15 secondi.
Stimando la dimensione del blocco media di 15.000.000 di gas, e un costo gas di 100 gwei, sono circa 1.5 ethereum per blocco.
Aggiungendo una fee del 10% per essere i piu' competitivi, potremmo stimare un costo per blocco di circa 1.65 ethereum.
A questo costo del gas, al cambio attuale di circa 4000$ per un eth un attacco della durata di 60 minuti verrebbe a costare circa 400 ethereum
ossia circa 1.600.000$
una cifra molto ridotta in rapporto al valore della rete di centinaia di miliardi di dollari.
Ovviamente questa stima varia in base al costo attuale del gas in gwei, e al tasso di conversione eth/usd, entrambi estremamente variabili.
Descrizione tecnica di DeathStarUtilizzando il linguaggio solidity, viene codificato uno smart contract che esegue un loop che brucia tutto il gas
passato dalla transazione chiamante con il parametro GasLimit.
Eventualmente si possono creare varie versioni leggermente diverse di DeathStar, per renderne piu' difficile
l'individuazione da un eventuale HardFork o da un software di filtro aggiunto dai miner o dai nodi,
ma tutte funzionanti in base alla stessa logica come negli esempi che riporto:
Esempi Codice di DeathStar:
// questa versione poco prima di finire il gas si ferma,
// lasciando un piccolo margine di gas per eseguire le istruzioni di return senza errore
pragma solidity ^0.6.0;
contract DeathStar_a
{
function DeathLoop_a() public payable returns (bool)
{
uint left = 0;
while(true)
{
left = gasleft();
// poco prima di finire il gas si ferma,
// lasciare un piccolo margine di gas per eseguire le istruzioni di return senza errore
if (left < 1000)
{
break;
}
}
return(true);
}
}
// questa versione cicla fino ad arrivare all'errore out of gas.
pragma solidity ^0.6.0;
contract DeathStar_b
{
function DeathLoop_b() public payable returns (bool)
{
while(true)
{
}
return(true);
}
}
Descrizione sintetica della dinamica dell'attacco BlockStuffing:1) lanciare un proprio nodo geth: geth --syncmode "light" --mainnet
si sincronizza in un attimo perche' fa il download della blockchain precedente.
servira' per essere autonomi e non passare da api proprietarie che potrebbero bannarci durante l'attacco.
2) pre-caricare in rete un certo numero di smart-contract deathStar
ognuno ad un address diverso e con codice leggermente diverso,
per rendere difficile sia il riconoscimento da parte delle mining pool che un possibile hard fork,
(DeathStar_a, DeathStar_b ecc..)
3) Reperire un numero adeguato di eth in base alla durata dell'attacco e al costa attuale del gas in gwei e pre caricarli su un certo numero di indirizzi origine.
(15.000.000 dimensione media blocco * (costo gas in gwei + fee di incentivo per essere sicuramente inclusi))/1.000.000.000
= costo in ethereum per 15 secondi di attacco)
4) crere uno script (python, perl, c, go.... un linguaggio a piacere) che usa chiamate RPC su geth
e fa piu' o meno le cose qui descritte sommariamente:
# se DeathLoop_a smette di funzionare,
# passare a DeathLoop_b e cosi' via.
CalledDeathStar=Deathloop_a
while( nuovo blocco minato)
{
legge la baseFeePerGas e il BlockGasLimit attuali.
calcola GasBurned=BlockGasLimit-X (X serve per lasciare un piccolo spazio anche alle altre transazioni, da decidere se X > 0)
calcola le fee della tranzasione: MaxFeePerGas(in gwei)=BaseFeePerGas + Tip
(dove tip e' la percentuale che va ai miner, diciamo il 20% per essere sicuri di essere inclusi velocemente oppure usare tecniche MEV per ottimizzare al massimo)
crea una transazione con gasLimit=GasBurned, MaxFeePerGas, che esegue lo smart contract CalledDeathStar da un indirizzo random di quelli origine.
(anche l'indirizzo origine varia per evitare di essere riconosciti e bloccati facilmente)
# opzionale
while (la nostra transazione non e' inclusa in un blocco minato)
{
usare tecniche MEV per controllare nella mempool le fee delle altre transazioni
se sono state caricate tranzasioni con fee piu' alte alzare le fee alla nostra transazione
reimmettendo in rete una transazione con la stessa nonce e fee aumentate.
}
}
5) eseguire lo script.
Un ringraziamento ai ragazzi della comunita' italiana di bitcointalk.org (filippone, acquafredda, HostFat, jack0m ed altri)
che mi hanno dato spunti interessanti per la realizzazione di questo studio.
References:
1)
https://ethereum.github.io/yellowpaper/paper.pdf2)
https://medium.com/hackernoon/the-anatomy-of-a-block-stuffing-attack-a488698732ae3)
https://dl.acm.org/doi/fullHtml/10.1145/33911954)
https://www.coindesk.com/markets/2021/07/27/how-to-fix-ethereums-mev-problem-and-give-traders-the-best-price/5)
https://www.paradigm.xyz/2020/08/ethereum-is-a-dark-forest/6)
https://infernaltoast.medium.com/how-bitcoin-and-ethereum-solved-the-halting-problem-differently-cffbb4e3045c7)
https://www.quora.com/Why-is-Bitcoin-not-Turing-complete