Cross-chain, DeFi and smart contracts · Lezione 5 di 6
Analizzare exploit e attacchi informatici
11 min di lettura
Quando un protocollo o un exchange subisce un attacco informatico, nel giro di poche ore agli analisti vengono poste sempre le stesse domande: che cosa è successo, quanto è stato sottratto, dove si trova ora e chi è stato. Le risposte emergono dall’analisi dettagliata di un piccolo numero di transazioni, seguita da un lungo lavoro di tracciamento. Questa lezione riunisce le competenze di decodifica del modulo (token, proxy, swap, prestiti flash e bridge) e le applica a casi pubblici.
Il ciclo di vita dell’exploit nei dati
La maggior parte degli incidenti, qualunque sia la causa principale, attraversa le stesse fasi, e ogni fase lascia prove diverse:
| Fase | Cosa fa l’attaccante | Prove da raccogliere |
|---|---|---|
| Finanziamento | Ottiene fondi per il gas per nuovi indirizzi | Primo trasferimento in entrata per ogni indirizzo dell’attaccante e relativa provenienza |
| Preparazione | Distribuisce contratti d’attacco, esegue test, talvolta prima su altre chain | Creazioni di contratti, tentativi falliti e relative cause di revert, bytecode |
| Esecuzione | Esegue una o più transazioni d’attacco | Tracce, log, variazioni dei saldi per indirizzo e token |
| Consolidamento | Scambia token congelabili o illiquidi con ETH o altri asset neutri e raccoglie i fondi | Swap su DEX con forte impatto sul prezzo, trasferimenti tra indirizzi dell’attaccante |
| Dispersione | Suddivide i fondi, li trasferisce tramite bridge, usa mixer, li scambia con Bitcoin e li converte in denaro | Schemi di suddivisione, depositi su bridge, depositi nei mixer, indirizzi di deposito presso exchange |
Le fasi si sovrappongono e, in caso di compromissione di chiavi, la preparazione avviene off-chain. Organizzare le prove in questo modo evita che un’indagine si concentri subito sulla transazione più visibile, trascurando il finanziamento che potrebbe consentire di identificare l’attaccante.
Analizzare la transazione d’attacco
Inizia dalla traccia, non dai log. I log registrano ciò che i contratti hanno scelto di annunciare; la traccia registra ogni chiamata, il suo valore e se è riuscita. Un ordine di lavoro pratico:
- Elenca gli attori: l’account di proprietà esterna che ha inviato la transazione, il contratto d’attacco che ha chiamato, i contratti della vittima e gli eventuali indirizzi che ottengono un profitto.
- Calcola le variazioni dei saldi per ogni indirizzo e token nell’intera transazione (qui funziona la query di compensazione della lezione Swap su DEX e flussi di liquidità). Il guadagno netto dell’attaccante e la perdita netta della vittima fanno da riferimento per tutto il resto.
- Esamina l’albero delle chiamate dall’inizio, individuando i prestiti flash (vedi la lezione Prestiti, bridge e contabilità dei protocolli), così da non conteggiare il capitale preso in prestito come perdita.
- Individua il passaggio in cui lo stato del protocollo è diventato incoerente. Questa è la causa principale e di solito corrisponde a una singola chiamata di funzione.
Un riepilogo delle variazioni dei saldi per una fittizia transazione d’attacco mostra il risultato del passaggio 2:
{
"tx_hash": "0x7c0d…e91a",
"block_number": 21000417,
"balance_changes": [
{"address": "0xa77a…c0de", "role": "attack contract", "token": "DAI", "delta": "+2400000.00"},
{"address": "0x5af3…71b2", "role": "victim pool", "token": "DAI", "delta": "-2401000.00"},
{"address": "0x87f1…4e2a", "role": "flash-loan lender", "token": "DAI", "delta": "+1000.00"},
{"address": "0x3e9d…02f7", "role": "sender EOA", "token": "ETH", "delta": "-0.041"}
]
}
Il prestito flash di 2.000.000 DAI del creditore non compare affatto, perché il capitale è uscito e rientrato nella stessa transazione; rimane solo il premio di 1.000 DAI (0,05%). La vittima ha perso 2.401.000 DAI, il contratto d’attacco ha trattenuto 2.400.000 DAI e il mittente ha pagato 0,041 ETH di gas.
L’exploit di Euler Finance del 13 marzo 2023 illustra il metodo. Le analisi pubblicate dai ricercatori di sicurezza di una delle transazioni d’attacco lo riducono ai passaggi seguenti:
Contratto d’attacco, una delle diverse transazioni d’attacco (pool DAI)
1. Prestito flash di 30.000.000 DAI da Aave
2. Deposito di 20.000.000 DAI su Euler -> token di garanzia (eDAI)
3. mint(): leva finanziaria su sé stesso -> debito di 200.000.000 dDAI, 195.600.000 eDAI
4. Rimborso di 10.000.000 DAI -> 10.000.000 dDAI bruciati
5. Nuovo mint() -> altri 200.000.000 dDAI e 195.600.000 eDAI
6. donateToReserves(100,000,000 eDAI) -> nessun controllo di solvibilità: l’account è ora insolvente
7. Un secondo contratto d’attacco liquida il primo con uno sconto del 20%
8. Prelievo di 38.900.000 DAI, rimborso del prestito flash più il premio e trattenimento del resto
Il passaggio 6 è la causa principale: una funzione che riduceva la garanzia senza verificare lo stato di salute dell’account. I passaggi 1 e 8 si annullano a vicenda per quanto riguarda il capitale preso in prestito. Ripetuto su diversi pool, l’attacco ha sottratto circa 197 milioni di dollari in DAI, WETH, WBTC, stETH e USDC. L’attaccante ha scambiato la maggior parte dei fondi con ETH e DAI, ha inviato 100 ETH a un mixer e poi ha negoziato con il protocollo tramite messaggi on-chain, restituendo tutti i fondi recuperabili entro il 3 aprile 2023. Vale la pena decodificare i messaggi on-chain: sono testi nei dati di input di normali trasferimenti e fanno parte della documentazione dell’incidente.
Finanziamento, preparazione e imitatori
Il finanziamento di un indirizzo dell’attaccante è spesso il miglior indizio per attribuire l’attacco. Tra le fonti più comuni ci sono i prelievi dai mixer (i pool di Tornado Cash usavano tagli fissi come 0,1, 1, 10 e 100 ETH), i bridge da un’altra chain, i servizi di exchange istantaneo e, talvolta, un prelievo da un exchange, che può essere approfondito tramite procedura legale (vedi la lezione Seguire il flusso di valore attraverso exchange e servizi). Controlla anche:
- Il distributore di ogni contratto d’attacco e gli altri contratti che ha distribuito, comprese le versioni di test su altre chain.
- La somiglianza del bytecode con contratti d’attacco precedenti, che può collegare gli incidenti.
- I tentativi falliti precedenti a quello riuscito: le relative cause di revert mostrano che cosa stava testando l’attaccante e quando ha iniziato.
Non tutti gli indirizzi che ottengono un profitto appartengono all’attaccante originale. I bot MEV copiano le transazioni in attesa che sono redditizie e alcuni gruppi white hat anticipano gli attacchi per salvare i fondi. Nel caso di Euler, un indirizzo che sosteneva che il proprio bot avesse copiato per errore il primo attacco finì comunque per trasferire i DAI all’attaccante, perché il contratto copiato aveva codificato al suo interno l’indirizzo dell’attaccante. Nell’incidente del bridge Nomad dell’agosto 2022, centinaia di indirizzi si limitarono a riprodurre la transazione del primo attaccante sostituendo il proprio indirizzo. Etichetta questi attori separatamente, indicando il livello di certezza, e non rendere mai pubblica l’identità di un privato sulla base di collegamenti di questo tipo (vedi la lezione Attribuzione ed etichettatura).
Quando il bug non è nel codice
Alcuni dei furti più ingenti non hanno coinvolto alcuna vulnerabilità nei contratti intelligenti. Nel furto del bridge Ronin del marzo 2022, gli attaccanti controllavano cinque delle nove chiavi dei validatori richieste dal bridge, un numero sufficiente per firmare prelievi di circa 173.600 ETH e 25,5 milioni di USDC; il furto passò inosservato per sei giorni. Nell’aprile 2022, le autorità statunitensi attribuirono il furto al gruppo Lazarus della Corea del Nord. On-chain, i prelievi erano validamente firmati; solo il contesto (dimensioni, destinatario e tempistiche insolite) li rendeva sospetti.
Il furto di Bybit del 21 febbraio 2025, pari a circa 1,5 miliardi di dollari, è stato il più grande furto di criptovalute mai registrato al momento in cui è avvenuto ed è un esempio di quanto sia importante capire che cosa abbiano effettivamente approvato i firmatari. Il cold wallet dell’exchange era un proxy Safe multisig. Gli investigatori hanno scoperto che l’interfaccia del wallet era stata compromessa attraverso il computer di uno sviluppatore del fornitore del wallet: i firmatari vedevano un normale trasferimento, mentre i loro hardware wallet firmavano qualcos’altro. Una volta decodificata, la transazione firmata appare così:
SafeProxy.execTransaction(...) -- selettore 0x6a761202, tre firme valide
to = contratto dell’attaccante
data = transfer(...) -- nome della funzione apparentemente innocuo
operation = 1 -- DELEGATECALL, non CALL
DELEGATECALL attacker contract.transfer(...) -- viene eseguito usando lo storage del proxy
SSTORE slot 0 := malicious implementation -- il puntatore al singleton Safe viene sostituito
Poi: sweepETH(...) e sweepERC20(...) chiamati sul proxy, senza bisogno di firme
Poiché un proxy Safe conserva il puntatore alla propria implementazione nello slot di storage 0 (vedi la lezione Decodificare le interazioni con i contratti intelligenti), una delegatecall che scrive nello slot 0 trasferisce il controllo dell’intero wallet. Le successive transazioni di drenaggio hanno spostato circa 401.346 ETH, 90.375 stETH, 15.000 cmETH e 8.000 mETH. Il 26 febbraio 2025, l’FBI ha attribuito il furto ad attori nordcoreani che chiama TraderTraitor, ha pubblicato un elenco di indirizzi e ha segnalato che i fondi venivano convertiti in Bitcoin e distribuiti su migliaia di indirizzi su più chain. Le conclusioni per gli analisti: decodificare ogni campo operation nelle transazioni multisig, generare un avviso per qualsiasi delegatecall verso un contratto sconosciuto e monitorare gli slot di implementazione dei proxy di alto valore.
Tracciamento dopo l’incidente
Le prime ore determinano quanto si possa congelare o segnalare. Una sequenza tipica:
- Crea l’insieme iniziale: ogni indirizzo controllato dall’attaccante individuato attraverso le transazioni d’attacco e i collegamenti relativi al finanziamento e al distributore.
- Tieni d’occhio gli asset congelabili. Alcuni emittenti di stablecoin possono congelare i saldi, motivo per cui gli attaccanti li scambiano per primi; segnala tempestivamente gli indirizzi.
- Condividi gli indirizzi e gli hash delle transazioni con exchange, bridge e altri servizi che potrebbero ricevere i fondi, attraverso i canali di segnalazione predisposti.
- Traccia in avanti, passaggio dopo passaggio e attraverso le chain, il consolidamento e la dispersione (vedi le lezioni Tracciare i fondi in avanti e all’indietro, Tracciamento cross-chain e Mixer, CoinJoin e offuscamento nei grafi).
-- Primi due passaggi dagli indirizzi iniziali di un incidente, ordinati per flussi più ingenti
WITH seeds AS (
SELECT address FROM incident_addresses WHERE incident_id = 'INC-0142'
), hop1 AS (
SELECT t.to_address, SUM(t.amount_usd) AS usd, MIN(t.block_time) AS first_seen
FROM value_transfers t JOIN seeds s ON t.from_address = s.address
WHERE t.to_address NOT IN (SELECT address FROM seeds)
GROUP BY t.to_address
)
SELECT h.to_address AS hop1, t.to_address AS hop2, SUM(t.amount_usd) AS usd
FROM hop1 h
JOIN value_transfers t
ON t.from_address = h.to_address AND t.block_time >= h.first_seen
GROUP BY h.to_address, t.to_address
ORDER BY usd DESC;
La query presuppone una tabella value_transfers che combina già i trasferimenti nativi ricavati dalle tracce con i trasferimenti di token, ciascuno valutato al momento del trasferimento. La prima CTE trova gli indirizzi che hanno ricevuto fondi dagli indirizzi iniziali (escludendo i trasferimenti tra questi ultimi); il passaggio finale segue ciascuno di tali indirizzi per un ulteriore passaggio, considerando solo i trasferimenti successivi alla prima ricezione. I flussi ingenti del secondo passaggio verso servizi noti sono quelli per cui potrebbero esistere registrazioni off-chain.
Redigere il rapporto sull’incidente
Classifica la causa principale, perché determina quali prove siano rilevanti:
| Categoria della causa principale | Esempio pubblico | Firma tipica nei dati |
|---|---|---|
| Errore logico | Euler, 2023 | Prestito flash più una sequenza insolita di chiamate che lascia uno stato impossibile |
| Inizializzazione o controllo degli accessi | Nomad, 2022 | Molti chiamanti ottengono un esito positivo con gli stessi dati di chiamata |
| Verifica delle firme | Wormhole, 2022 | Token coniati senza un deposito corrispondente |
| Compromissione di chiavi | Ronin, 2022 | Prelievi validamente firmati, nessun bug nel codice |
| Interfaccia o catena di fornitura | Bybit, 2025 | Transazione validamente firmata con una delegatecall imprevista |
| Governance | Beanstalk, 2022 | Potere di voto preso in prestito, proposta eseguita nella stessa transazione |
Valuta le perdite ai prezzi del blocco di ciascuna transazione d’attacco, elenca tutte le transazioni d’attacco con l’altezza del blocco e mantieni separati gli importi recuperati dalle perdite. Le lezioni Redigere il rapporto analitico e Protezione dei dati, etica e divulgazione responsabile spiegano come presentare e condividere questi risultati.
Focus sull’esame: le cinque fasi di un exploit e le prove lasciate da ciascuna; analisi della transazione d’attacco a partire dalla traccia, calcolo delle variazioni dei saldi e compensazione del capitale del prestito flash; passaggi dell’attacco a Euler e relativa causa principale (donateToReserves senza controllo dello stato di salute); fonti di finanziamento, collegamenti tramite distributore e bytecode, tentativi falliti e imitatori come indizi per l’attribuzione; compromissioni di chiavi e interfacce (Ronin, Bybit) e delegatecall Safe che ha riscritto lo slot 0; priorità delle prime ore (insieme iniziale, asset congelabili, notifiche ai servizi); query sui passaggi che combinano trasferimenti nativi e di token; categorie delle cause principali e valutazione delle perdite ai prezzi del blocco.Domande di esercitazione
Verifica la tua comprensione. Queste domande non contano per l’esame.
Accedi per salvare i tuoi progressi e riprendere da dove hai lasciato. È gratuito. Accedi