Cross-chain, DeFi e smart contract · Lezione 5 di 6
Analisi di 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 le stesse domande: che cosa è successo, quanto è stato sottratto, dove si trova ora e chi è stato. Le risposte derivano da un numero limitato di transazioni esaminate in grande dettaglio, seguite da una lunga attività di tracciamento. Questa lezione riunisce le competenze di decodifica di questo modulo e di quelli precedenti (token, proxy, swap, flash loan e bridge) e le applica a casi pubblici.
Il ciclo di vita di un exploit nei dati
La maggior parte degli incidenti, indipendentemente dalla causa radice, attraversa le stesse fasi, e ciascuna fase lascia evidenze diverse:
| Fase | Che cosa fa l'attaccante | Evidenze da raccogliere |
|---|---|---|
| Finanziamento | Ottiene fondi per il gas di nuovi indirizzi | Primo trasferimento in entrata verso ciascun indirizzo dell'attaccante e relativa provenienza |
| Preparazione | Distribuisce contratti di attacco, esegue test, talvolta prima su altre blockchain | Creazioni di contratti, tentativi falliti e relative cause di revert, bytecode |
| Esecuzione | Esegue una o più transazioni di attacco | Tracce, log, variazioni di saldo per indirizzo e token |
| Consolidamento | Converte mediante swap i token congelabili o illiquidi in ETH o in altre attività neutrali, raccoglie i fondi | Swap su DEX con elevato impatto sul prezzo, trasferimenti tra indirizzi dell'attaccante |
| Dispersione | Suddivide i fondi, li trasferisce tramite bridge, usa mixer, li converte in Bitcoin, li converte in valuta fiat | Schemi di distribuzione a ventaglio, depositi su bridge, depositi su mixer, indirizzi di deposito degli exchange |
Le fasi si sovrappongono e, in caso di compromissione delle chiavi, la preparazione avviene off-chain. Tuttavia, organizzare le evidenze in questo modo evita che un'indagine si concentri subito sulla transazione più visibile, trascurando il finanziamento che potrebbe identificare l'attaccante.
Lettura della transazione di attacco
Si inizi 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 il suo esito. Un ordine operativo pratico:
- Elencare gli attori: l'account controllato esternamente che ha inviato la transazione, il contratto di attacco che ha chiamato, i contratti vittima e qualsiasi indirizzo che alla fine ottiene un profitto.
- Calcolare le variazioni di saldo per indirizzo e per token sull'intera transazione (la query di compensazione nella lezione Swap su DEX, exchange istantanei e flussi di liquidità è applicabile anche in questo caso). Il guadagno netto dell'attaccante e la perdita netta della vittima inquadrano tutto il resto.
- Percorrere l'albero delle chiamate dall'alto, contrassegnando i flash loan (prestiti non garantiti che devono essere rimborsati, insieme a una commissione, prima della fine della transazione, altrimenti l'intera transazione viene annullata mediante revert), in modo che il capitale preso in prestito non venga conteggiato come perdita.
- Individuare il passaggio in cui lo stato del protocollo è diventato incoerente. Quella è la causa radice e, di norma, corrisponde a una singola chiamata di funzione.
Un riepilogo delle variazioni di saldo per una transazione di attacco fittizia mostra il risultato del passaggio 2:
{
"tx_hash": "0x7c0d…e91a",
"block_number": 21000417,
"balance_changes": [
{"address": "0xa77a…c0de", "role": "contratto di attacco", "token": "DAI", "delta": "+2400000.00"},
{"address": "0x5af3…71b2", "role": "pool vittima", "token": "DAI", "delta": "-2401000.00"},
{"address": "0x87f1…4e2a", "role": "erogatore flash loan", "token": "DAI", "delta": "+1000.00"},
{"address": "0x3e9d…02f7", "role": "EOA mittente", "token": "ETH", "delta": "-0.041"}
]
}
Il flash loan di 2.000.000 DAI dell'erogatore non compare affatto, perché è uscito ed è rientrato nella stessa transazione; rimane soltanto la commissione di 1.000 DAI (0,05%). La vittima ha perso 2.401.000 DAI, il contratto di attacco ne ha trattenuti 2.400.000 e il mittente ha pagato 0,041 ETH in gas.
L'exploit di Euler Finance del 13 marzo 2023 illustra il metodo. Le analisi pubblicate dai ricercatori di sicurezza riconducono una delle transazioni di attacco ai seguenti passaggi:
Contratto di attacco, una delle diverse transazioni di attacco (pool DAI)
1. Flash loan di 30.000.000 DAI da Aave
2. Deposito di 20.000.000 DAI in Euler -> token di garanzia (eDAI)
3. mint(): auto-leva -> debito di 200.000.000 dDAI, 195.600.000 eDAI
4. Rimborso di 10.000.000 DAI -> 10.000.000 dDAI bruciati
5. Nuova chiamata a mint() -> altri 200.000.000 dDAI e 195.600.000 eDAI
6. donateToReserves(100,000,000 eDAI) -> nessun controllo di solvibilità: account ora insolvente
7. Il secondo contratto di attacco liquida il primo con uno sconto del 20%
8. Prelievo di 38.900.000 DAI, rimborso del flash loan più commissione, trattenimento del resto
Il passaggio 6 è la causa radice: una funzione che riduceva la garanzia senza verificare lo stato di solvibilità dell'account. I passaggi 1 e 8 si compensano per quanto riguarda il capitale preso in prestito. Ripetuto su più pool, l'attacco ha sottratto circa 197 milioni di dollari in DAI, WETH, WBTC, stETH e USDC. L'attaccante ha convertito la maggior parte dei fondi in ETH e DAI, ha inviato 100 ETH a un mixer, quindi ha negoziato con il protocollo tramite messaggi on-chain e ha restituito tutti i fondi recuperabili entro il 3 aprile 2023. Vale la pena decodificare i messaggi on-chain: sono testi nei dati di input di semplici trasferimenti e fanno parte della documentazione del caso.
Finanziamento, preparazione e imitatori
Il finanziamento di un indirizzo dell'attaccante è spesso la pista migliore per l'attribuzione. Le fonti comuni sono prelievi da mixer (i pool di Tornado Cash utilizzavano tagli fissi quali 0,1, 1, 10 e 100 ETH), bridge da un'altra blockchain, servizi di exchange istantaneo e, occasionalmente, un prelievo da un exchange, che può essere approfondito tramite gli strumenti legali disponibili (si veda la lezione Tracciamento attraverso exchange e servizi di custodia). Verificare anche:
- Il soggetto che ha distribuito ciascun contratto di attacco e gli altri contratti da esso distribuiti, comprese le versioni di test su altre blockchain.
- La somiglianza del bytecode con contratti di attacco precedenti, che può collegare gli incidenti.
- I tentativi falliti prima di 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 originario. I bot MEV copiano le transazioni redditizie in attesa di conferma e alcuni gruppi white hat anticipano gli attacchi per salvare i fondi. Nel caso Euler, un indirizzo che sosteneva che il proprio bot avesse copiato accidentalmente il primo attacco ha finito comunque per trasferire i DAI all'attaccante, perché nel contratto copiato l'indirizzo dell'attaccante era codificato in modo fisso. Nell'incidente del bridge Nomad dell'agosto 2022, centinaia di indirizzi si sono limitati a rieseguire la transazione del primo attaccante sostituendovi il proprio indirizzo. Etichettare questi attori separatamente, dichiarando il livello di confidenza, e non pubblicare mai l'identità di un privato sulla sola base di tali collegamenti (si veda la lezione Dall'indirizzo all'entità alla persona: attribuzione ed etichettatura).
Quando il difetto non è nel codice
Alcuni dei maggiori furti non hanno coinvolto alcun difetto degli smart contract. Nel furto al bridge Ronin del marzo 2022, gli attaccanti controllavano cinque delle nove chiavi dei validatori richieste dal bridge, sufficienti a firmare prelievi di circa 173.600 ETH e 25,5 milioni di USDC; il furto è rimasto inosservato per sei giorni. Le autorità statunitensi hanno attribuito il furto al Lazarus Group della Corea del Nord nell'aprile 2022. On-chain, i prelievi erano firmati validamente; soltanto il contesto (importo, destinatario e tempistica insoliti) ne rivelava la natura illecita.
Il furto a Bybit del 21 febbraio 2025, pari a circa 1,5 miliardi di dollari, è stato il più grande furto di criptovalute mai registrato al momento dei fatti e offre una lezione sull'analisi di ciò che i firmatari hanno effettivamente approvato. Il cold wallet dell'exchange era un proxy multisig Safe. Gli investigatori hanno rilevato che l'interfaccia del wallet era stata compromessa attraverso il computer di uno sviluppatore presso il fornitore del wallet, per cui i firmatari vedevano un trasferimento ordinario 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 di funzione apparentemente innocuo
operation = 1 -- DELEGATECALL, non CALL
DELEGATECALL contratto dell'attaccante.transfer(...) -- viene eseguita usando lo storage del proxy
SSTORE slot 0 := implementazione malevola -- puntatore al singleton Safe sostituito
Poi: sweepETH(...) e sweepERC20(...) chiamate sul proxy, senza necessità di firme
Poiché un proxy Safe conserva il puntatore alla propria implementazione nello slot 0 dello storage (si veda la lezione Decodifica delle interazioni con gli smart contract), una delegatecall che scrive nello slot 0 cede il controllo dell'intero wallet. Le transazioni di svuotamento hanno quindi trasferito 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 identifica come TraderTraitor, ha pubblicato un elenco di indirizzi e ha riferito che i fondi venivano convertiti in Bitcoin e distribuiti tra migliaia di indirizzi su più blockchain. Le indicazioni operative per l'analista: 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 elevato valore.
Tracciamento dopo l'incidente
Le prime ore determinano quanto può essere congelato o segnalato. Una sequenza tipica:
- Costruire l'insieme iniziale di indirizzi: tutti gli indirizzi controllati dall'attaccante individuati a partire dalle transazioni di attacco, dal finanziamento e dai collegamenti con il soggetto che ha distribuito i contratti.
- Monitorare le attività congelabili. Alcuni emittenti di stablecoin possono congelare i saldi, motivo per cui gli attaccanti le convertono per prime; segnalare rapidamente gli indirizzi.
- Condividere indirizzi e hash delle transazioni con exchange, bridge e altri servizi che potrebbero ricevere i fondi, tramite i loro canali di segnalazione prestabiliti.
- Tracciare in avanti il consolidamento e la dispersione, passaggio per passaggio, attraverso le blockchain (si vedano le lezioni Tracciamento secondo uno standard probatorio, Passaggi tra blockchain e tracciamento cross-chain e Mixer custodial).
-- Primi due passaggi dagli indirizzi iniziali di un incidente, con i flussi maggiori per primi
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_timestamp) 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_timestamp >= 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 valorizzato al momento del trasferimento. La prima CTE individua gli indirizzi che hanno ricevuto fondi dall'insieme iniziale (escludendo i movimenti tra indirizzi di tale insieme); il passaggio finale segue ciascuno di essi per un ulteriore passaggio, conteggiando soltanto i trasferimenti successivi alla prima ricezione. I grandi flussi al secondo passaggio verso servizi noti indicano dove potrebbero esistere registrazioni off-chain.
Redazione del resoconto di un incidente
Classificare la causa radice, perché determina quali evidenze sono rilevanti:
| Categoria della causa radice | Esempio pubblico | Traccia tipica nei dati |
|---|---|---|
| Difetto logico | Euler, 2023 | Flash loan accompagnato da una sequenza insolita di chiamate che lascia uno stato impossibile |
| Inizializzazione o controllo degli accessi | Nomad, 2022 | Molti chiamanti riescono a eseguire l'operazione con gli stessi calldata |
| Verifica delle firme | Wormhole, 2022 | Token coniati senza un deposito corrispondente |
| Compromissione delle chiavi | Ronin, 2022 | Prelievi firmati validamente, nessun difetto nel codice |
| Interfaccia o catena di fornitura | Bybit, 2025 | Transazione firmata validamente con una delegatecall inattesa |
| Governance | Beanstalk, 2022 | Potere di voto preso in prestito, proposta eseguita nella stessa transazione |
Valutare le perdite ai prezzi del blocco di ciascuna transazione di attacco, elencare tutte le transazioni di attacco con l'altezza del blocco e mantenere gli importi recuperati separati dalla perdita. Le lezioni Redazione della relazione forense: confidenza e linguaggio ed Etica, riservatezza, protezione dei dati e sicurezza dell'investigatore illustrano come presentare e condividere questi risultati.
Focus sull'esame: le cinque fasi di un exploit e le evidenze lasciate da ciascuna; lettura della transazione di attacco a partire dalla traccia, calcolo delle variazioni di saldo ed esclusione del capitale dei flash loan mediante compensazione; i passaggi dell'attacco Euler e la sua causa radice (donateToReserves senza un controllo dello stato di solvibilità); fonti di finanziamento, collegamenti tramite il soggetto che ha distribuito i contratti e il bytecode, tentativi falliti e imitatori come piste per l'attribuzione; compromissioni delle chiavi e dell'interfaccia (Ronin, Bybit) e la delegatecall di Safe che ha riscritto lo slot 0; priorità delle prime ore (insieme iniziale di indirizzi, attività congelabili, notifica ai servizi); query sui passaggi basate su trasferimenti nativi e di token combinati; categorie delle cause radice e valutazione delle perdite ai prezzi del blocco.