Il Reentrancy Attack è un tipo di vulnerabilità molto pericolosa negli smart contracts in cui un attaccante sfrutta una chiamata ricorsiva di un contratto prima che la sua precedente transazione sia completamente eseguita. Sostanzialmente viene sfruttata una funzione del contratto che effettua chiamate esterne ad altri contratti ma non aggiorna immediatamente lo stato del contratto prima di completare queste chiamate esterne. L'attaccante richiama la stessa funzione più volte (in modo ricorsivo, tipo loop) prima che lo smart contract possa aggiornare il suo stato, eseguendo così più prelievi (o operazioni che non dovrebbero essere possibili).
COME AVVIENE L'ATTACCO
Il contratto ha una funzione che permette agli utenti di prelevare fondi (ad esempio, una funzione withdraw), in base al loro saldo. Il contratto effettua una chiamata esterna per trasferire fondi a un altro indirizzo (ad esempio, usando la funzione send). Lo stato del contratto non viene aggiornato immediatamente: la chiamata esterna avviene, permettendo all'attaccante di eseguire azioni prima che il saldo venga ridotto. L'attaccante, grazie alla possibilità di usufruire di una chiamata esterna, esegue nuovamente la funzione di prelievo, causando così più prelievi prima che il saldo venga aggiornato.
Se consideriamo uno smart contract di un wallet che consente agli utenti di depositare e prelevare fondi, un attaccante può sfruttare questo contratto utilizzando questa funziona ricorsiva. Gli utenti possono depositare fondi nel contratto e prelevarli tramite la funzione withdraw, che invia i fondi all'utente e poi aggiorna il suo saldo. L'attaccante crea un contratto che sfrutta la funzione withdraw per richiamarla più volte. L'attaccante richiama la funzione attack nel contratto malevolo, depositando fondi nel contratto vulnerabile. La funzione withdraw del contratto vulnerabile invia i fondi all'indirizzo dell'attaccante, il quale può eseguire un'altra chiamata ricorsiva a withdraw prima che il saldo venga aggiornato. In questo modo, l'attaccante può ripetere l'operazione più volte, prelevando fondi multipli rispetto al suo saldo spettante. Ogni volta che l'attaccante richiama la funzione withdraw, il contratto vulnerabile non ha ancora aggiornato il saldo dell'attaccante. Ciò consente all'attaccante di prelevare ripetutamente più fondi di quelli realmente depositati. Ipotizza di depositare 1 ETH nel contratto, quando l'attaccante chiama la funzione withdraw per la prima volta, riceve 1 ETH, ma lo stato del contratto non è ancora aggiornato. L'attaccante richiama ricorsivamente withdraw e riceve altri 1 ETH e così via. Ogni ciclo di chiamate drena fondi dal contratto (di altri utenti), che non riesce ad aggiornare correttamente il saldo dell'attaccante in tempo reale.
PREVENIRE QUESTI ATTACCHI
Per prevenire questi pericolosi attacchi, la regola fondamentale è aggiornare lo stato del contratto prima di effettuare qualsiasi chiamata esterna cioè basta spostare la riga che aggiorna il saldo dell'utente prima della chiamata esterna. Funzioni di check controllano le condizioni (ad esempio, se l'utente ha abbastanza saldo).
