Quando un miner si è preso il mio server

Sabato sera ho ricevuto una mail dal mio provider che iniziava con "abbiamo ricevuto una segnalazione di abuso per il tuo indirizzo IP". Il tipo di mail che si legge due volte prima di crederci davvero. Il server, secondo la segnalazione, aveva tentato un attacco SSH verso un altro sistema. Non ero io, ovviamente, ma qualcosa che girava sul mio server sì.

Mi sono collegato e ho lanciato un banale controllo dei processi attivi. Non ci ho messo molto a trovarlo: un processo che consumava il 99% della CPU, con un nome scelto ad arte per confondersi con un file legittimo, tipo "nginx-cache" invece di qualcosa di ovviamente sospetto. Dentro, i parametri di avvio non lasciavano dubbi: un miner di criptovaluta, che scaricava potenza di calcolo verso un pool esterno usando il mio server come manodopera gratuita. Vicino, un secondo processo, quello probabilmente responsabile della segnalazione ricevuta: uno strumento di scansione per attacchi SSH automatizzati.

La prima cosa che ho pensato guardando l'orario di avvio del processo è stata "quindi è lì da giorni e non me ne sono accorto", il che mi ha fatto sentire piuttosto scemo. Poi ho controllato meglio: quel formato di orario senza data, tipo "11:38", significa solo che è partito nella stessa giornata. Non giorni. Ore. Piccola differenza psicologica enorme: da "sono stato negligente per una settimana" a "l'ho beccato lo stesso pomeriggio". Vale comunque la pena ricordarselo per la prossima volta: leggere bene l'output di ps aux prima di farsi prendere dal panico.

La causa era una versione di Gitea, la piattaforma self-hosted che uso per i miei repository, rimasta indietro di qualche release rispetto all'ultima. Due vulnerabilità critiche pubbliche, di quelle con un punteggio di gravità molto alto, permettevano a chiunque potesse registrarsi sull'istanza di eseguire comandi arbitrari sul server. E la registrazione pubblica, per pigrizia mia di mesi prima, era rimasta aperta. Risultato: ventuno account fasulli creati da bot automatizzati, quasi tutti con nomi generati a caso, uno dei quali aveva silenziosamente piazzato il miner e lo script di scansione.

Fermare il container e aggiornare alla versione corretta sembrava il passo più semplice di tutti, e infatti è stato quello dove ho perso più tempo. Il primo tentativo di ripulire gli account fasulli è fallito con un errore criptico su una colonna del database che non esisteva. Il database era rimasto sullo schema della versione vecchia, mentre il comando che stavo usando si aspettava già lo schema della versione nuova. Serviva un passaggio di migrazione esplicito prima di poter fare qualunque altra cosa, cosa abbastanza ovvia col senno di poi ma che sul momento mi ha fatto pensare per qualche minuto di aver rotto tutto ancora di più.

Una volta risolto quello, il resto è filato liscio: migrazione dello schema, cancellazione degli account fasulli, aggiornamento alla versione con le due falle corrette, chiusura della registrazione pubblica. Ho passato anche un bel po' di tempo a verificare che il problema fosse rimasto confinato dove pensavo fosse confinato: nessuna traccia nei repository, nessuna chiave SSH aggiunta di nascosto, nessun accesso riuscito che non fosse il mio. Alla fine il quadro tornava tutto: un attacco automatizzato, opportunistico, che punta a un guadagno economico immediato tramite il mining, non un attacco mirato con qualcuno dall'altra parte che sapeva chi fossi.

La lezione più banale, e per questo la più facile da dimenticare, è che una configurazione lasciata com'era all'installazione (quella cosa che pensi "tanto la sistemo poi") prima o poi qualcuno la trova. Le due cose che ho cambiato per davvero, oltre a fare la patch: chiudere la registrazione pubblica per default su qualunque nuovo servizio esposto, e segnarmi da qualche parte un promemoria periodico per controllare gli aggiornamenti di sicurezza dei servizi self-hosted, invece di aspettare che sia un miner di criptovaluta a ricordarmelo.

← Torna a tutti i post