La recente vulnerabilità del pool Curve è diversa dagli incidenti di hacking di criptovaluta che abbiamo visto prima, perché questa volta il problema non è direttamente correlato alla vulnerabilità dello smart contract stesso, ma al compilatore sottostante del linguaggio di programmazione utilizzato da Vyper.
Vyper è un linguaggio di programmazione orientato al contratto intelligente che adotta uno stile simile a Python ed è specificamente progettato per interagire con la Ethereum Virtual Machine (EVM).
L’impatto di questa vulnerabilità è molto grave e ogni giorno le notizie riportano enormi quantità di perdite. La situazione sembra essere sotto controllo, ma non prima che gli hacker abbiano rubato più di 70 milioni di dollari. Secondo la post-valutazione di LlamaRisk, anche alcuni pool di progetti DeFi sono stati attaccati da hacker, tra cui il pool pETH/ETH di PEGD che ha perso 11 milioni di dollari, il pool msETH/ETH di Metronome che ha perso 3,4 milioni di dollari e il pool alETH/ETH di Alchemix che ha perso 11 dollari. 22,6 milioni di dollari USA, mentre il pool Curve DAO ha perso circa 24,7 milioni di dollari USA.
La vulnerabilità è chiamata bug di reentrancy e si verifica in alcune versioni del linguaggio di programmazione Vyper, in particolare v0.2.15, v0.2.16 e v0.3.0. Quindi qualsiasi progetto che utilizzi queste versioni specifiche di Vyper potrebbe diventare bersaglio di attacchi.
Cos'è la reentrata?
Per capire perché si verifica questa vulnerabilità, cerchiamo prima di capire cos'è la rientranza e come funziona.
Il rientro significa che una funzione può essere interrotta durante l'esecuzione e può essere richiamata in modo sicuro prima che la chiamata precedente sia completata. Questo meccanismo è spesso utilizzato in applicazioni quali la gestione degli interrupt hardware e la ricorsione.
Affinché una funzione sia rientrante, deve soddisfare alcune condizioni:
Innanzitutto, non può utilizzare dati globali e statici. Questa è una convenzione che significa che quando una funzione viene eseguita, non deve dipendere da dati globali o variabili statiche. Perché se una funzione viene interrotta durante l'esecuzione e poi richiamata, i dati globali e statici potrebbero essere distrutti o potrebbero perdere informazioni.
In secondo luogo, non può modificare il proprio codice. Indipendentemente dal momento in cui una funzione viene interrotta, l'esecuzione dovrebbe poter continuare nello stesso modo. Se una funzione modifica il proprio codice durante l'esecuzione, potrebbero verificarsi degli errori quando viene richiamata nuovamente.
Infine, non può chiamare altre funzioni che non siano rientranti. Ciò significa che all'interno di una funzione rientrante non dovresti chiamare altre funzioni che potrebbero non essere rientranti. Ciò potrebbe causare risultati imprevedibili, con conseguenti arresti anomali o errori del programma.
È troppo difficile da capire, quindi non entreremo nei dettagli.
Come è stato sfruttato?
Spieghiamo come gli attacchi di reentrancy portano al furto di fondi e alla perdita di 70 milioni di dollari nell'attacco Curve.
Innanzitutto, sappiamo che un attacco di reentrancy è un metodo mediante il quale un contratto dannoso richiama ripetutamente una funzione in uno smart contract. Nell'attacco Curve, questa funzione viene utilizzata per prelevare la liquidità dell'utente dal pool. Questa funzione ha un bug perché non esegue controlli sufficienti prima di aggiornare l'importo.
Diamo un'occhiata al flusso dell'attacco:
Supponiamo che uno smart contract vulnerabile abbia 10 ether.
L'attaccante richiama la funzione di deposito e deposita 1 ether.
L'attaccante richiama quindi la funzione di prelievo per prelevare 1 ether. Questa funzione controlla se l'attaccante ha 1 ether nel suo account.
Tuttavia, questa funzione non ha aggiornato il saldo nel contratto prima di trasferire 1 ether sull'account dell'attaccante. Ciò significa che il contratto ritiene ancora che vi siano 10 ether al suo interno.
L'attaccante richiama nuovamente la funzione di prelievo (rientra nel mercato) e si prepara a prelevare nuovamente 1 ether.
Poiché il contratto ritiene ancora che siano presenti 10 ether, trasferirà nuovamente 1 ether all'attaccante.
Questo processo si ripete finché non c'è più liquidità nel contratto.
In questo modo, l'attaccante può richiamare ripetutamente la funzione di prelievo e trasferire quasi tutta la liquidità del contratto sul proprio conto, con conseguente furto dei fondi del contratto.
Questa vulnerabilità è molto vantaggiosa per gli aggressori perché l'importo del contratto non viene aggiornato in tempo reale, consentendo loro di ripetere l'attacco continuamente finché non ci saranno più fondi da prelevare dal contratto. #Crv