Vulnerabilità degli Smart Contract (Part 1)

Fabio Cricrì
6 min readJun 10, 2021

Tecniche di attacco e di prevenzione

In questo articolo diamo innanzitutto un’occhiata all’elenco degli attacchi più conosciuti alla DeFi riportandone anche le cause e i fix che li hanno risolti.

Flash loan attack

Un flash loan è un prestito valido solo all’interno di una transazione: l’operazione fallisce se non viene rimborsato il debito prima della fine della transazione.

Vediamo i passi tipici di un flash loan attack:

  1. l’utente prende prestito massiccio (token A) da un protocollo (esempio Pancakeswap) che supporta i contratti flash loan;
  2. scambia il token A con il token B su un DEX, dumpando il prezzo di A;
  3. deposita il token B come collaterale (garanzia) su un protocollo DeFi utilizzato dal DEX per prendere in prestito una quantità maggiore di token A grazie al prezzo manipolato;
  4. l’utente utilizza parte dei token A presi in prestito per rimborsare completamente il flash loan iniziale e tiene i token rimanenti.

Manipolazione Oracoli

Questa è la causa numero 1 degli attacchi al momento ed è dovuto al fatto che tutte le piattaforme attaccate (Uniswap, Sushiswap o Curve) non utilizzano oracoli decentralizzati ma ottengono le informazioni sui prezzi esclusivamente dai liquidity pool.

Analizzando il primo storico attacco di questo tipo, che ha interessato la piattaforma bZx, sono stati manipolati i prezzi dei token sfruttando il fatto che dipendono esclusivamente dai pool di liquidità e non sono assicurati da oracoli decentralizzati.

Prevenzione

Il modo più semplice per risolvere questo problema è utilizzare oracoli decentralizzati come i feed di prezzo di Chainlink .Chainlink è il principale fornitore di oracoli di tipo decentralizzato ed è considerata la soluzione più performante per correggere questi attacchi.

Tuttavia, anche utilizzando Chainlink per ottenere un feed sui prezzi del token, bisognerà attenersi alle best practices e evitare alcuni errori. Ecco un esempio di smart contract scritto in Solidity che ci permette, supponendo che si tratti di un token ERC20, di ottenere l’ultimo prezzo del token utilizzando il feed dei prezzi di Chainlink:

smart contract per l’utilizzo del feed sul prezzo di Chainlink

Reentrancy attack

Un attacco di rientro (utilizzato nell’exploit alla piattaforma DAO) si verifica quando una funzione riesce ad effettuare una chiamata “esterna” a un altro smart contract che può effettuare una chiamata ricorsiva alla funzione originale come in un loop e ripetendo interazioni non permesse.

Prevenzione

Per prevenire questa minaccia è consigliabile richiamare le transazioni “esterne” al termine dello smart contract e, quando possibile, usare la funzionetransfer() (usata per trasferire ether ad un certo indirizzo) e alla quale la EVM assegnerà un gas limit pari a 2300, un valore sufficiente per compiere la transazione ma insufficiente per poter effettuare una chiamata di rientro. Ecco un esempio di smart contract che nasconde un’altra vulnerabilità:

Bisognerebbe modificare il codice in modo che la chiamata di trasferimento del token esterno avvenga dopo che il saldo è stato aggiornato a 0.

In alternativa, è consigliabile aggiungere una variabile mutex (abbreviazione di “mutual exclusion”, ovvero esclusione reciproca) che blocchi la chiamata della funzione fino a quando la funzione stessa non termina.

L’attacco DAO è anche un esempio dell’attacco di rientro, ed è anche considerato più ricorrente nel mondo DeFi e in generale sull’ecosistema Ethereum.

Front Running

Poiché tutto sulla catena è un’informazione pubblica, l’attaccante potrebbe osservare le transazioni sulla blockchain e trovarne alcune deleterie per le proprie esposizioni sul mercato:

ad esempio, potrebbe intercettare una “whale” (grande possessore di criptovaluta) che tenta di dumpare un token che l’attaccante detiene e, per evitare di subire un danno economico,decide di pagare gas extra per poter dumpare prima della whale.

Questo fenomeno è noto nella finanza tradizionale come “front running”. Il fenomeno è agevolato dal fatto che, come con la maggior parte delle blockchain, i nodi Ethereum raggruppano le transazioni per formare i blocchi e decidono quali convalidare in base alla loro convenienza:gasPrice. Il potenziale vettore d’attacco è dovuto al fatto che il miner sceglie quali transazioni dal pool verranno incluse nel blocco, questo è tipicamente ordinato per gasPricedelle transazione. L'attaccante può quindi:

  1. ottenere i dati della transazione;
  2. creare una propria transazione con un maggiore gasPrice;
  3. ottenere che la loro transazione venga inclusa in un blocco prima dell'originale.

Per ottenere i dati della transazione, ovvero rintracciare la transazione da attaccare ecco uno smart contract di esempio FindThisHash.sol:

FindThisHash.sol

Attraverso questo smart contract, l’attaccante utilizzando un attacco brute-force (in quanto la funzione di hash è progettata per essere unidirezionale ovvero one-way e quindi non invertibile), verifica che la transazione sia quella da attaccare. Per farlo chiama la funzione solve()con MiaTransazionecome parametro (che è la transazione da attaccare e trarne vantaggio economico), verifica la condizione hash == sha3(solution) e infine imposta il giusto valore di gasPriceper dare priorità alla propria transazione.

Prevenzione (Prima soluzione)

Il modo migliore per prevenirli è con una soluzione detta Commit Reveal Scheme, Schema di rivelazione del commit.

Questa soluzione permette di “nascondere” tramite hashing la propria transazione e di rivelarne i contenuti agli altri solo dopo che va a buon fine e termina. Questo sistema impedisce ai “miners” e ai “front runners” di conoscere e di eseguire la stessa transazione in anticipo. Nel caso concreto del gioco sasso-carta-forbici, per assicurare che Alice e Bob possano giocare un game leale dovremmo avere che:

  1. le scelte di Alice e Bob siano nascoste l’una all’altra (segretezza).
  2. né Alice né Bob possano cambiare le loro scelte dopo che l’impegno è stato preso (vincolanti).

Per esempio, Alice sceglie forbici e ne ricava un hash. Il nonce (stringa casuale) assicura che l’output dell’hash (detto digest) sia univoco e non invertibile banalmente. Successivamente Alice invia il suo digest a Bob, che esegue lo stesso processo. Le scelte di Alice e Bob sono così nascoste in modo sicuro.

Commit Reveal Scheme part 1

Una volta che entrambe le parti si sono impegnate nelle loro scelte, possono quindi rivelare le loro scelte originali: comunicano al loro partner la scelta e il loro nonce, questi ne calcolano l’hash e lo confrontano con quello ricevuto inizialmente. Verificati gli impegni, si applicano le regole di sasso-carta-forbici e si sceglie un vincitore.

Commit Reveal Scheme part 2

Prevenzione (Seconda soluzione)

Una seconda tecnica di prevenzione prevede che lo smart contract ponga un limite superiore al gasPrice in modo da impedire che gli attaccanti possano aumentare il gasPricea loro piacimento ottenendo quindi un controllo sulle transazioni. Questa misura però mitiga solo una classe di attaccanti, gli utenti malevoli che abbiamo denominato “front runners”. I miners in questo scenario possono ancora attaccare il contratto ordinando a loro piacimento le transazioni nel blocco, indipendentemente dal prezzo del gas.

Prevenzione (Terza soluzione)

Abbiamo visto che esistano due classi di utenti che possono eseguire questo tipo di attacchi:

  1. utenti: che modificano il gasPricedelle loro transazioni;
  2. minatori: che possono riordinare le transazioni in un blocco a loro discrezione.

Un contratto vulnerabile alla prima classe di utenti è significativamente più pericoloso in quanto i miners possono eseguire l'attacco solo dopo aver “convalidato” il blocco ed è molto improbabile che risulti il più veloce fra tutti i miners della rete.

--

--