Report analitici · Lezione 6 di 6
Caso di studio: un’indagine end-to-end
11 min di lettura
Le 41 lezioni precedenti hanno trattato ciascuna una competenza. Le indagini reali le usano tutte insieme, sotto pressione, con dati incompleti e persone in attesa di risposte. Questo caso segue un exploit fittizio dal primo avviso al rapporto finale, mostrando a ogni passaggio quale competenza viene utilizzata e come l’analista decide quanta fiducia accordare a ciascun risultato. Tutti i nomi, gli indirizzi, gli hash, le altezze dei blocchi e gli importi sono inventati.
La segnalazione e la domanda
Alle 09:58 UTC del 14 marzo 2026, Corvane Finance, un protocollo di prestito fittizio su Ethereum, rileva che il suo mercato USDC è stato prosciugato. Il suo team invia a un gruppo indipendente di analisi l’hash della transazione dell’exploit, 0x9c4e…a71b, con una richiesta di una sola riga: «Seguite il denaro».
L’analista riformula la richiesta come una domanda analitica, come descritto nella lezione Dalla domanda all’ipotesi:
Dove sono finiti gli asset sottratti nella transazione 0x9c4e…a71b, fino ai blocchi limite; quali servizi di custodia ne hanno ricevuto una parte; e quanta fiducia riponiamo in ciascun collegamento?
La dichiarazione dell’ambito definisce i punti di partenza (la transazione dell’exploit), le chain (Ethereum, un rollup, Bitcoin), l’intervallo (blocchi Ethereum da 24.790.112 a 24.812.000 e l’intervallo Bitcoin corrispondente), un limite di 10 salti per le peel chain Bitcoin e una regola di arresto al raggiungimento di un servizio di custodia. Viene inserita nel fascicolo del caso prima dell’esecuzione della prima query.
Passaggio 1: lettura della transazione dell’exploit
L’analista recupera la transazione, la sua ricevuta e le sue tracce da un nodo archivio (vedi API dei nodi e accesso ai dati) e registra l’hash del blocco per documentarne la provenienza. Lo stato della ricevuta è 1 (esito positivo) e i log decodificati mostrano cosa è uscito dal protocollo:
{
"transactionHash": "0x9c4e…a71b",
"blockNumber": 24790112,
"status": "0x1",
"decodedLogs": [
{"token": "USDC", "event": "Transfer", "from": "0x5Fd0…3C2a",
"to": "0x7aE3…b19C", "value": "1912400000000"},
{"token": "WETH", "event": "Transfer", "from": "0x5Fd0…3C2a",
"to": "0x7aE3…b19C", "value": "210000000000000000000"}
]
}
0x5Fd0…3C2a è il mercato USDC di Corvane e 0x7aE3…b19C è il contratto dell’attaccante. Normalizzando le unità (vedi Qualità dei dati, normalizzazione e provenienza): USDC ha 6 decimali, quindi 1.912.400.000.000 equivale a 1.912.400 USDC; WETH ne ha 18, quindi il secondo valore equivale a 210 WETH. Le tracce mostrano un prestito flash, una manipolazione del prezzo in un pool con poca liquidità e il drenaggio: la classica dinamica descritta nella lezione Analizzare exploit e attacchi. Una transazione successiva trasferisce tutto dal contratto al deployer, l’account di proprietà esterna 0xE7c1…44aD.
L’account è stato creato due giorni prima: il suo primo trasferimento in entrata, ricevuto prima che avesse inviato transazioni (nonce ancora a 0), era di 1,0 ETH prelevato da un mixer basato su smart contract. Come spiega la lezione Mixer, CoinJoin e offuscamento nei grafi, questo finanziamento ci dice ben poco su chi ci sia dietro; l’analista lo registra come un vicolo cieco, non come una pista.
Passaggio 2: flussi di token in SQL
Per individuare ogni movimento di token in uscita dagli indirizzi dell’attaccante, l’analista interroga i log grezzi in base alla firma dell’evento, come nella lezione Interrogare i log e le tracce EVM:
-- Trasferimenti ERC-20 inviati dal contratto dell’exploit o dall’account dell’attaccante
SELECT
l.block_number,
l.transaction_hash,
l.contract_address AS token,
'0x' || SUBSTR(l.topic2, 27, 40) AS recipient,
l.data AS raw_amount_hex
FROM logs l
WHERE l.block_number BETWEEN 24790112 AND 24812000
AND l.topic0 = '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
AND SUBSTR(l.topic1, 27, 40) IN ('7ae3…b19c', 'e7c1…44ad') -- in pratica, hex minuscolo completo
ORDER BY l.block_number, l.log_index;
topic0 è l’hash keccak-256 di Transfer(address,address,uint256). topic1 e topic2 contengono rispettivamente il mittente e il destinatario, completati fino a 32 byte; l’indirizzo corrisponde quindi agli ultimi 40 caratteri esadecimali, a partire dalla posizione 27 dopo «0x» e i 24 zeri di riempimento. L’importo è contenuto in data in formato esadecimale; la funzione che lo converte in un numero varia a seconda del motore.
I risultati mostrano tre swap tramite un aggregatore DEX nell’arco di 15 minuti, che convertono 1.912.400 USDC in 731,2 ETH, a una media di circa 2.615 USDC per ETH includendo l’impatto sul prezzo (vedi Swap DEX e flussi di liquidità). I 210 WETH vengono convertiti in ETH. L’account dell’attaccante detiene ora 941,2 ETH di proventi.
Passaggio 3: attraversare le chain
Tra le 10:31 e le 11:05 UTC, i fondi si dividono in tre direzioni (vedi Tracciamento cross-chain):
- 600 ETH vengono inviati in sei depositi da 100 ETH a un protocollo di swap cross-chain. Ogni deposito contiene un memo con un indirizzo Bitcoin di destinazione, bc1q…7k3f. Su Bitcoin, i sei pagamenti in uscita del protocollo verso quell’indirizzo ammontano a 22,10 BTC e ciascuno include in un output OP_RETURN l’hash Ethereum corrispondente in entrata. Il collegamento è esplicito nei dati di entrambe le chain.
- 300 ETH vengono inviati in tre depositi da 100 ETH a un bridge rapido, i cui eventi di deposito non indicano un destinatario; un fornitore di liquidità effettua il pagamento sul rollup usando i propri fondi. L’unico modo per collegare i due lati è basarsi su importo e orario. La query per contare i candidati descritta nella lezione Fiducia, incertezza e formulazione restituisce esattamente un pagamento compreso tra 99,80 e 100,00 ETH entro 20 minuti da ciascun deposito, tutti e tre verso 0x4B9e…07Fd, per un totale di 299,82 ETH.
- 41,2 ETH restano nell’account dell’attaccante, senza movimenti fino ai blocchi limite.
Passaggio 4: la peel chain Bitcoin e gli exchange
Da bc1q…7k3f, la prima transazione spende tutti e sei gli output e avvia una peel chain: nove salti, ciascuno con un piccolo pagamento in uscita e un resto di importo maggiore. L’analista la segue con una query ricorsiva sulle tabelle degli input e degli output (vedi Interrogare i dati UTXO):
-- Segui la peel chain: a ogni salto mantieni come resto l’output di valore maggiore
WITH RECURSIVE chain (hop, txid, vout, value_sat) AS (
SELECT 1, transaction_hash, output_index, value FROM outputs
WHERE transaction_hash = 'e2d9…5a10' AND output_index = 1 -- resto del salto 1
UNION ALL
SELECT c.hop + 1, o.transaction_hash, o.output_index, o.value
FROM chain c
JOIN inputs i ON i.spent_transaction_hash = c.txid
AND i.spent_output_index = c.vout
JOIN outputs o ON o.transaction_hash = i.transaction_hash
WHERE c.hop < 9 AND o.value = (SELECT MAX(value) FROM outputs
WHERE transaction_hash = i.transaction_hash)
)
SELECT hop, txid, value_sat / 1e8 AS value_btc FROM chain ORDER BY hop;
Il passaggio ricorsivo collega ciascun output di resto alla transazione che lo spende e mantiene l’output di valore maggiore di quella transazione, che in una peel chain corrisponde al resto. Il supporto per WITH RECURSIVE e i relativi limiti variano tra i motori. «Output di valore maggiore» è solo una regola empirica, quindi l’analista verifica ogni salto confrontandolo con gli indicatori della lezione Euristiche per rilevare il resto: il resto va sempre a un indirizzo P2WPKH nuovo, corrispondente al tipo di input; i pagamenti sono di importo tondo (0,75, 0,95, 1,00 BTC), mentre il resto no; e ogni transazione condivide lo stesso schema di versione, tariffa e locktime, un’impronta digitale del wallet coerente.
| Destinazione dei trasferimenti della peel chain | Trasferimenti | Totale |
|---|---|---|
| Indirizzi di deposito dell’exchange K | 3 | 2,95 BTC |
| Indirizzi di deposito dell’exchange O | 2 | 1,80 BTC |
| Indirizzi non raggruppati, non spesi | 4 | 3,10 BTC |
| Resto dopo il salto 9, non speso | – | 14,248 BTC |
| Commissioni complessive dei nove salti | – | circa 0,002 BTC |
Le righe sommano a 22,10 BTC, la quantità iniziale. Le attribuzioni agli exchange derivano da ciò che è accaduto in seguito: ciascun indirizzo di deposito è stato successivamente speso insieme a oltre 100 altri indirizzi in un unico hot wallet, secondo lo schema di raccolta descritto nelle lezioni Euristica della titolarità basata sugli input condivisi e Seguire il valore attraverso exchange e servizi. L’hot wallet dell’exchange K compare in un elenco di indirizzi di riserva pubblicato dall’exchange stesso, quindi si tratta di un’etichetta autoidentificata; quello dell’exchange O è contrassegnato solo da un’etichetta di terzi (vedi Attribuzione ed etichettatura).
Passaggio 5: verificare le ipotesi e dichiarare il livello di fiducia
Chi controlla bc1q…7k3f? L’analista crea una piccola matrice ACH con tre ipotesi: l’attaccante (H1), un indirizzo appartenente al protocollo di swap stesso (H2) oppure una terza parte, ad esempio un desk OTC pagato dall’attaccante (H3). I riferimenti OP_RETURN sono compatibili con tutte e tre: dimostrano che i fondi sono arrivati lì, non chi controlla l’indirizzo. Gli elementi diagnostici sono il memo impostato dall’attaccante (incompatibile con H2), l’assenza di una cronologia precedente dell’indirizzo (incompatibile con un indirizzo di protocollo di lunga data) e il passaggio immediato alla peel chain con piccoli depositi sugli exchange (incompatibile con un desk che regola una transazione usando i propri wallet consolidati). H1 resta plausibile; H3 si basa su un unico argomento comportamentale, quindi la verifica di sensibilità la mantiene come opinione minoritaria.
I giudizi principali, usando la scala ICD 203 dichiarata nella sezione del rapporto dedicata alla metodologia:
- Fatto: 1.912.400 USDC e 210 WETH sono usciti dal mercato Corvane nella transazione 0x9c4e…a71b, blocco 24.790.112.
- È quasi certo che 600 ETH dei proventi siano diventati 22,10 BTC inviati a bc1q…7k3f. Il livello di fiducia è alto: il collegamento è registrato su entrambe le chain.
- È molto probabile che 2,95 BTC siano arrivati agli indirizzi di deposito dell’exchange K. Il livello di fiducia è moderato: l’etichetta è autoidentificata, ma il percorso si basa sul rilevamento del resto per un massimo di sette salti.
- È probabile che 1,80 BTC siano arrivati agli indirizzi di deposito dell’exchange O. Il livello di fiducia è basso, perché l’etichetta proviene da un’unica fonte di terzi.
- È probabile che l’attaccante controlli 0x4B9e…07Fd sul rollup. Il livello di fiducia è moderato: tre corrispondenze distinte basate su importo e orario, ciascuna con un solo candidato.
I saldi rimasti fermi (41,2 ETH, 299,82 ETH, 3,10 BTC e 14,248 BTC) vengono riportati come fatti validi ai blocchi limite.
Passaggio 6: rapporto, visualizzazioni e divulgazione
Il rapporto segue la lezione Scrivere il rapporto analitico: un riepilogo di una pagina con i cinque giudizi, l’ambito, la metodologia, un risultato per ciascun giudizio, le alternative e i limiti, oltre a un’appendice di 35 transazioni con hash completi, altezze dei blocchi e hash dei blocchi, generata tramite query. Seguendo la lezione Visualizzare flussi e grafi, include due diagrammi Sankey, uno in ETH e uno in BTC, anziché un unico diagramma che mescoli le unità; un grafo dei flussi con il collegamento al bridge tratteggiato; e una cronologia con una corsia per ogni chain, che mostra come il primo deposito all’exchange sia avvenuto meno di cinque ore dopo l’exploit.
La divulgazione segue la lezione Protezione dei dati, etica e divulgazione responsabile. Gli exchange K e O vengono avvisati entro un’ora tramite i rispettivi canali di conformità; ciascuno riceve solo i propri indirizzi di deposito, gli hash delle transazioni, gli importi e la probabilità e il livello di fiducia del collegamento. L’indirizzo sul rollup viene segnalato all’operatore del bridge come un collegamento probabile, non accertato. Un indirizzo non raggruppato della peel chain si risolve tramite un servizio di denominazione in quello che sembra essere il nome di una persona: viene escluso da ogni documento condiviso e inserito solo nell’appendice ad accesso limitato per le procedure legali. L’analista ha inoltre trovato due fork del codice di Corvane con la stessa configurazione vulnerabile dell’oracolo dei prezzi, che detengono ancora fondi; entrambi i team vengono avvisati in privato e la versione pubblica del rapporto, che non menziona persone private né indirizzi non raggruppati, viene diffusa solo dopo che i team confermano di aver corretto la vulnerabilità.
Focus sull’esame: trasformare «segui il denaro» in una domanda analitica con ambito definito; leggere lo stato di una ricevuta e i log Transfer decodificati, filtrare i log tramite topic0, estrarre gli indirizzi dai topic completati e normalizzare USDC (6 decimali) e WETH (18 decimali); perché un collegamento tramite memo e OP_RETURN è più solido di una corrispondenza basata su importo e orario; seguire ricorsivamente una peel chain e confermare il resto usando diverse euristiche; attribuire gli indirizzi di deposito tramite le raccolte e capire perché un’etichetta autoidentificata è più affidabile di un’etichetta di terzi; indicare separatamente probabilità e livello di fiducia per ogni giudizio; riconciliare ogni unità di valore, comprese le commissioni e i saldi rimasti fermi; divulgazione minima con il livello di fiducia indicato, un’appendice riservata sull’identità e una notifica privata ai fork vulnerabili.