Piratages PrestaShop : skimmers, paiements détournés et portes dérobées que nous avons vus
Faux formulaires de carte au paiement, encaissements qui partent sur le compte de quelqu'un d'autre, portes dérobées cachées dans des modules que personne n'utilise. Sans dire chez qui, nous racontons ce que nous avons trouvé en nettoyant des boutiques PrestaShop, comment nous traitons un incident et pourquoi c'est la boutique non mise à jour qui finit sur cette liste.
Une boutique en ligne ne se fait pas pirater comme dans les films. Pas d'écrans rouges ni de tête de mort sur la page d'accueil. En général, c'est tout le contraire : la boutique fonctionne parfaitement, les commandes arrivent, les clients paient et le propriétaire ne remarque rien. Pendant ce temps, quelqu'un copie les cartes à l'étape du paiement, encaisse sur un compte qui n'est pas le vôtre ou garde une porte dérobée pour revenir quand il le souhaite.
Chez Rekire, nous nettoyons des boutiques PrestaShop compromises plus souvent que nous le voudrions. Cet article rassemble ce que nous avons vu lors de ces interventions. Les cas sont réels, mais nous les racontons de façon à ce qu'il soit impossible de savoir de quelle boutique il s'agit : ni secteur, ni ville, ni dates, ni chiffres, ni détails permettant de la retrouver. Ce qui compte, ce n'est pas qui, mais comment, parce que le comment se répète.
C'est un article long, et c'est voulu. Si votre boutique tourne sur une ancienne version de PrestaShop, nous vous demandons de le lire jusqu'au bout.
Qu'est-ce qu'un skimmer et pourquoi c'est l'attaque préférée contre une boutique
Un skimmer (aussi appelé cloneur de cartes ou attaque de type Magecart) est un morceau de JavaScript qui s'introduit dans votre boutique et vole les données de carte au moment même où le client les saisit. Numéro, date d'expiration, CVV et nom du titulaire partent vers un serveur de l'attaquant, et la commande suit son cours normal.
C'est l'attaque la plus rentable qui existe contre une boutique en ligne, pour trois raisons :
- Elle ne casse rien. Le client achète, vous êtes payé, personne ne se plaint. Les données volées sont utilisées des semaines plus tard, ailleurs, et quand la banque du client détecte la fraude, personne ne fait le lien entre la carte et votre boutique.
- Elle n'a pas besoin que votre passerelle de paiement soit vulnérable. Peu importe que vous utilisiez le TPE virtuel de votre banque, Stripe ou PayPal. Le skimmer n'attaque pas la passerelle : il attaque la page sur laquelle se trouve le client.
- Elle passe à l'échelle. Une boutique au trafic normal livre des dizaines de cartes par semaine sans que l'attaquant ait autre chose à faire.
Cas 1 : le formulaire de carte qui n'existait pas
Le premier signal a été une alerte automatique de notre module de sécurité : un gabarit de l'étape de paiement du thème avait changé alors que personne n'avait touché au thème.
En tirant le fil, toute la séquence est apparue, reconstituée à partir des journaux du serveur :
- Quelqu'un s'est connecté au panneau de l'hébergement avec le bon identifiant et le bon mot de passe. Ce n'était pas une faille de PrestaShop : le mot de passe avait fuité.
- Depuis le gestionnaire de fichiers du panneau, il a écrit environ 60 Ko de JavaScript dans un fichier du thème lui-même, vide jusque-là. Un fichier au nom banal, de ceux que personne n'ouvre.
- Il a ajouté une seule ligne à la fin du gabarit de l'étape de paiement : un
<script src>qui chargeait ce fichier. Depuis le domaine même de la boutique, si bien qu'aucun filtre de « domaines externes » ne l'aurait signalé. - Il a déposé un petit fichier PHP pour vider le cache des gabarits, l'a exécuté et est reparti. Le tout en moins de vingt minutes.
Le JavaScript ne faisait rien pendant que le client naviguait. Il ne s'activait que lorsque le client choisissait le paiement par carte. À ce moment-là, il affichait un formulaire de carte identique à celui de la boutique et, une fois rempli, envoyait les données encodées avec navigator.sendBeacon vers une autre boutique en ligne, elle aussi piratée, qui servait de boîte aux lettres. Utiliser le site d'une autre victime comme destination est courant : un domaine commercial ordinaire n'éveille pas les soupçons.
Il est resté actif environ une semaine. Le travail qui a suivi a été aussi important que le nettoyage : extraire la liste des commandes et des paiements de ces jours-là pour prévenir l'établissement de paiement, et évaluer avec le responsable de la boutique la notification à l'AEPD (l'autorité espagnole de protection des données), que le RGPD (article 33) impose dans un délai de 72 heures après avoir pris connaissance de la violation.
Ce qui est apparu en dessous
En passant en revue les employés du back-office, nous avons trouvé pire : plus d'une vingtaine de faux super-administrateurs, tous avec la même adresse e-mail et le nom « Prestashop Addons », créés par rafales d'une seconde des mois plus tôt. Cette façon de les créer — beaucoup à la fois, avec la même adresse — est la signature d'une injection SQL, pas de quelqu'un qui passe par le formulaire de connexion. L'origine la plus probable était un contrôleur du constructeur de pages d'un thème commercial qui répondait à n'importe qui, sans vérifier la session, et insérait un paramètre non filtré dans une requête.
Aucun audit précédent ne les avait repérés. La boutique avait la porte ouverte depuis des mois, et le skimmer n'a été que ce qui a fini par se voir.
Cas 2 : les paiements qui partaient sur un autre compte
C'est le cas qui explique le mieux pourquoi nous disons qu'une attaque ne se voit pas. La boutique vendait normalement. Les commandes par carte apparaissaient dans le back-office comme payées, avec leur numéro de transaction, le bon statut et leur facture. Tout concordait… sauf que cet argent n'est jamais arrivé sur le compte bancaire de la boutique.
L'attaquant avait remplacé le fichier principal du module de paiement de la banque par une copie modifiée. Cette modification faisait ceci :
- Elle remplaçait le paiement par carte par un formulaire d'une passerelle internationale reliée à un compte de l'attaquant. Elle laissait Bizum intact et masquait un autre moyen de paiement, pour que le client aille directement à la carte.
- Elle écrivait un faux enregistrement dans les tables du module de la banque, de sorte que la commande ressemblait à un paiement normal dans le back-office.
- Elle ne s'activait pas pour les employés de la boutique, ni pour les adresses e-mail qui ressemblaient à des adresses de test ou à celles de l'agence qui assurait la maintenance. Qui testait la boutique voyait le paiement habituel.
- Elle prévenait l'attaquant de chaque encaissement par Telegram.
- Elle conservait ses clés hors du dossier web, dans le répertoire personnel du compte d'hébergement.
- Et elle pouvait s'autodétruire, en restaurant les fichiers d'origine qu'elle avait gardés juste à côté.
L'entrée s'est faite par FTP, avec le compte principal de l'hébergement, qui avait le même mot de passe que le panneau. Les journaux FTP montraient des dizaines de sessions depuis la même adresse pendant des semaines, à envoyer et retoucher des fichiers comme s'il s'agissait d'un développeur de plus.
Et comment l'a-t-on découvert ? Par une erreur de l'attaquant lui-même, et c'est la partie qui nous intéresse. La boutique venait de migrer vers PrestaShop 9. Le code malveillant était écrit pour l'ancienne version et, en le réinjectant, l'attaquant a envoyé les fichiers du module de paiement de l'ancienne boutique. Sous PrestaShop 9, ces fichiers ne fonctionnaient plus : la boutique est restée blanche. Sans cette panne, le détournement aurait continué. En croisant les commandes avec la trace laissée par le faux code, des dizaines d'encaissements détournés sont apparus sur plusieurs mois.
Cas 3 : des portes dérobées là où personne ne regarde
Un skimmer ou un détournement exigent que l'attaquant puisse écrire dans votre boutique. Pour revenir quand il le souhaite, il laisse un web shell : un fichier PHP qui, appelé par son URL, lui permet d'exécuter des commandes ou d'écrire des fichiers sur votre serveur. En voici quelques-uns que nous avons trouvés, et regardez bien où ils étaient :
- Une ligne de 30 octets (un
evalde ce qui arrive dans la requête) dans le dossier d'un module qui n'était pas installé. Le dossier était sur le disque depuis des années, personne ne le vérifiait, et PrestaShop 1.7 exécute n'importe quel.phpdemodules/si on le demande par URL. - Un fichier de moins de 200 octets, dont le nom commençait par un point, à la racine de la boutique. Il ne faisait qu'une chose : écrire sur le serveur tout fichier qu'il recevait. Aucun scanner automatique ne l'a vu ; il est apparu en comparant la boutique, fichier par fichier, avec une copie antérieure.
- Un shell complet de plus de 80 Ko (gestionnaire de fichiers, exécution de commandes, envoi de fichiers) dans le dossier d'un module natif de PrestaShop, avec l'en-tête de licence de PrestaShop, « PrestaShop » comme auteur et des fonctions aux noms innocents. Une copie exacte se trouvait dans un autre module abandonné, au cas où la première serait supprimée.
- Un gestionnaire de fichiers déguisé en lecteur de codes QR, écrit en PHP propre et lisible, dans une extension d'un WordPress qui partageait l'hébergement avec la boutique. De là, le JavaScript du thème PrestaShop a été réécrit sans jamais toucher à PrestaShop.
- Une ligne dans le dossier
vendor/d'un module qui incluait un fichier à l'extension.jpeg… qui était en réalité du PHP. La boutique avait subi deux nettoyages avec cette porte ouverte, parce que l'outil utilisé excluaitvendor/par défaut. - Un chargeur de 6 Ko dans un module de transport par ailleurs légitime, qui ouvrait un WebSocket et exécutait ce qu'on lui envoyait. Il n'y avait rien d'autre sur le disque : le code malveillant arrivait à chaque visite et servait à envoyer l'URL du back-office, avec son jeton, vers un domaine externe.
Les sabotages d'un seul caractère
Le cas qui nous a le plus appris est celui d'une boutique où, en plus des portes dérobées, l'attaquant avait modifié deux fichiers du cœur de PrestaShop. Dans l'un, une expression régulière qui nettoie les balises HTML avait été assouplie pour ne plus rien nettoyer. Dans l'autre, il avait supprimé la fermeture de l'index de classes que génère PrestaShop, si bien que tout ce qui était ajouté à la fin s'exécutait comme du code : réinfection automatique, sans avoir besoin d'aucun fichier à lui.
Aucune règle de recherche de motifs n'aurait vu cela. C'est la comparaison octet par octet avec le ZIP officiel de PrestaShop de la même version qui l'a trouvé.
Par où ils entrent (presque toujours)
Avec tous les cas sur la table, les voies d'entrée se répètent :
| Voie d'entrée | Ce que nous avons vu | Ce qui la ferme |
|---|---|---|
| Mot de passe du panneau ou du FTP ayant fuité | Connexion valide au panneau de l'hébergement ou au FTP principal, sans aucune faille technique | Mots de passe uniques, 2FA sur le panneau, SFTP, comptes FTP réduits au minimum et renouvellement après tout incident |
| Module vulnérable à l'injection SQL | Super-administrateurs créés par rafales ; contrôleurs publics qui ne vérifient rien | Modules à jour, retrait de ceux qui ne servent pas, revue régulière de la liste des employés |
Fichiers PHP accessibles dans modules/ | Web shells dans des modules désinstallés ou abandonnés | PrestaShop 9 (qui le refuse d'origine) ou un .htaccess avec des exceptions bien pesées |
| Un autre site sur le même hébergement | Un WordPress non maintenu utilisé pour écrire dans la boutique | Séparer les comptes d'hébergement ou tenir les deux sites aussi à jour l'un que l'autre |
| L'ordinateur de la personne qui administre | Logiciels qui volent les mots de passe enregistrés dans le navigateur et dans le client FTP | Ne pas enregistrer les mots de passe FTP dans le client, gestionnaire de mots de passe, 2FA |
Notez qu'une seule des cinq est une faille de programmation « pure ». Les autres relèvent de la maintenance : ce qui est installé, ce qui est en trop et qui détient les clés.
Pourquoi presque toutes les boutiques piratées étaient anciennes
Ce n'est pas un hasard. Dans presque tous les incidents que nous avons traités, la boutique tournait sous PrestaShop 1.6 ou 1.7, avec PHP 7.x et des modules qui n'avaient pas été mis à jour depuis des années. Cela additionne des risques qui se multiplient entre eux :
- PHP 7.4 ne reçoit plus de correctifs de sécurité depuis fin 2022, et les versions antérieures encore moins longtemps. Une nouvelle faille de PHP ne sera jamais corrigée pour votre serveur.
- Les anciennes branches de PrestaShop ne reçoivent plus de correctifs, et de nombreux modules tiers ont cessé de publier des versions pour elles. Quand une vulnérabilité d'un module populaire est rendue publique, le correctif sort pour la version actuelle. Si vous ne pouvez pas l'installer parce que votre boutique est trop ancienne, la vulnérabilité est publique et votre boutique reste ouverte.
- Les boutiques anciennes accumulent des modules orphelins : des dossiers de modules essayés et désinstallés il y a des années, toujours sur le disque et, en 1.7, exécutables par URL. Sous PrestaShop 9, le
.htaccessdemodules/refuse déjà l'exécution directe de PHP. - Plus la boutique est ancienne, plus on a peur d'y toucher. Et ce qu'on ne touche pas, on ne le vérifie pas.
Mettre à jour n'est pas une garantie absolue : la boutique du cas 2 était déjà sous PrestaShop 9, mais l'attaquant était entré avant, avec le mot de passe de l'hébergement. Ce que fait en revanche une boutique à jour, c'est fermer les voies d'entrée connues et rendre visible tout changement suspect. Une boutique ancienne, c'est une boutique où les voies connues restent ouvertes et où personne ne compare rien avec rien.
Ce que nous faisons chez Rekire quand une boutique est piratée
Quand une boutique compromise nous arrive, nous suivons toujours le même ordre. L'ordre compte : supprimer d'abord le fichier malveillant est le moyen le plus rapide pour que l'attaquant revienne par le même chemin une semaine plus tard.
- Copie forensique avant de toucher à quoi que ce soit. Fichiers et base de données, conservés hors du site. Si vous supprimez sans copier, vous perdez la preuve de ce qui s'est passé, depuis quand et quelles données ont été exposées.
- Travailler sur une copie isolée. Nous rapatrions la boutique dans notre environnement, sans accès à Internet, avec les e-mails capturés et les passerelles désactivées, pour l'analyser sans risque qu'elle écrive à des clients ou encaisse des paiements.
- Comparer avec une référence connue. Le cœur, avec le ZIP officiel de la même version de PrestaShop. Les modules, avec leur paquet d'origine. La boutique entière, avec une copie antérieure s'il y en a une. Ce qui a changé sans raison est le premier suspect.
- Examiner ce qui n'est pas dans les fichiers. Employés et profils, comptes de webservice et leurs permissions, tâches planifiées du serveur, clés de configuration des passerelles, JavaScript dans les pages CMS, dans la configuration ou dans les descriptions de produits.
- Trouver la voie d'entrée. Journaux d'accès web, du FTP et du panneau. Sans savoir par où ils sont entrés, le nettoyage reste provisoire.
- Fermer l'entrée, puis nettoyer. Corriger ou retirer le module vulnérable, verrouiller les dossiers, supprimer les comptes FTP superflus. Ensuite, mise en quarantaine de ce qui est malveillant, conservé comme preuve au lieu d'être supprimé.
- Renouveler tous les identifiants. Panneau, FTP, base de données, employés, clés d'API des passerelles et des services. Et fermer toutes les sessions ouvertes du back-office.
- Mesurer les dégâts. Quelles commandes et quels paiements sont passés par la boutique pendant que le code était actif, pour prévenir l'établissement de paiement et décider avec le responsable du traitement de la notification à l'AEPD.
- Mettre en place une surveillance. Une base de référence saine et des alertes qui se déclenchent au moment même où quelque chose change à nouveau.
- Proposer la solution de fond. Si la boutique est sur une version qui n'est plus maintenue, le plan de migration. Nettoyer une boutique ancienne sans la migrer, c'est gagner du temps, pas régler le problème.
RKR Security Alert : le module né de tout cela
Chacun des incidents racontés ici nous a obligés à faire à la main des vérifications qui pouvaient être automatisées. C'est de là qu'est né RKR Security Alert, le module de sécurité que nous avons développé chez Rekire et que nous utilisons dans nos propres audits. Il fonctionne de PrestaShop 1.7.6 à 9.2, justement parce que les boutiques qui en ont le plus besoin sont celles qui n'ont pas encore migré.
Ce qu'il surveille
- Les données de paiement et la configuration. Il prend un instantané de la configuration, des modules, des employés, des URL de la boutique et des comptes de webservice, et le compare avec l'état actuel. Il ne dépend pas des événements de PrestaShop : si quelqu'un modifie quelque chose directement en SQL, sans passer par le back-office, le changement apparaît quand même. Les changements touchant les passerelles de paiement sont marqués comme critiques.
- Les employés. Créations, modifications et suppressions, avec les comptes de super-administrateur mis en évidence. Les faux administrateurs du cas 1 auraient déclenché une alerte le jour même de leur création.
- Les connexions. Connexion au back-office depuis une nouvelle IP, avec pays, ville et alerte s'il s'agit d'un proxy, d'un VPN ou d'un centre de données.
- Les gabarits du paiement. Empreinte de tous les gabarits du tunnel de commande de tous les thèmes installés, pas seulement du thème actif. Qu'un seul d'entre eux change constitue déjà l'alerte : c'est exactement ce qui a trahi le cas 1.
- Les modules par version. Si les fichiers d'un module changent sans que sa version ait changé, ou si un nouveau module apparaît, vous êtes prévenu. C'est ce qui aurait trahi le remplacement du module de paiement du cas 2.
- Les tâches planifiées et le verrouillage des dossiers.
Ce qu'il recherche dans les fichiers
- Cloneurs de paiement, portes dérobées et web shells, exécution de commandes, obfuscation, JavaScript injecté et code caché dans des images.
- Des web shells reconnus à ce qu'ils savent faire et pas seulement à leur signature : lister, écrire et supprimer des fichiers à partir d'un chemin reçu en paramètre. C'est ainsi qu'il attrape ceux écrits en PHP propre, comme le faux lecteur de QR du cas 3.
- Comparaison du cœur avec le ZIP officiel de PrestaShop, la seule méthode qui détecte la modification d'un seul caractère dans un fichier légitime.
- Une détection critique ne peut pas être masquée par un motif de chemin : nous l'avons appris de la boutique qui avait subi deux nettoyages avec un chargeur dans
vendor/.
L'analyse se fait par étapes et reprend là où elle s'est arrêtée, si bien qu'elle ne tombe pas à cause de la limite de temps du serveur, et chaque détection est accompagnée de sa preuve : ce qui a été trouvé, à quelle ligne et par où on peut l'atteindre.
La sentinelle du navigateur
Certaines attaques ne laissent rien sur le disque, comme le chargeur par WebSocket du cas 3, ou n'apparaissent que lorsque le client fait quelque chose, comme le faux formulaire du cas 1. Pour celles-là, le module inclut une sentinelle qui observe la page une fois affichée dans le navigateur : elle alerte si un champ de carte apparaît hors d'une iframe après le chargement de la page, si le tunnel de commande envoie des données vers un nouveau domaine avec sendBeacon, fetch ou XHR, si un WebSocket externe s'ouvre ou si une page écrit une commande système dans le presse-papiers sans que l'utilisateur ait cliqué sur quoi que ce soit (la technique du faux captcha connue sous le nom de ClickFix). La sentinelle n'enregistre jamais le contenu de ces requêtes : dans un tunnel de commande, elles contiendraient de vraies données de carte.
Conçu pour des boutiques déjà touchées
Il s'installe en mode premier audit : il ne considère rien comme « normal » tant que vous n'avez pas examiné le rapport. Si la boutique était déjà infectée au moment de l'installation, l'infection n'entre pas dans la base de référence. Les alertes arrivent par Telegram, classées par gravité (vous pouvez réserver un groupe à ce qui est important et un autre à ce qui est informatif), et restent aussi dans la boîte de réception du panneau, même si vous n'utilisez pas Telegram.
Et un choix de conception qui nous paraît essentiel : rien ne sort de votre boutique. L'analyse se fait sur votre serveur, avec des règles fournies avec le module. Aucun fichier, aucun fragment ni aucune donnée de votre base n'est envoyé à qui que ce soit.
Liste de vérification pour cette semaine
Si vous êtes arrivé jusqu'ici, voici ce que vous pouvez faire sans l'aide de personne :
- Allez dans Paramètres avancés → Équipe et vérifiez chaque employé. S'il y en a un que vous ne reconnaissez pas, surtout avec un profil de super-administrateur, considérez la boutique comme compromise.
- Rapprochez les encaissements de la dernière semaine dans le tableau de bord de votre passerelle avec les commandes payées de la boutique.
- Faites un achat test avec une adresse e-mail qui n'est pas celle de la boutique, depuis un navigateur sans session d'administrateur, et regardez si le formulaire de paiement est bien celui d'habitude.
- Changez le mot de passe du panneau d'hébergement et du FTP, en veillant à ce qu'il ne soit utilisé nulle part ailleurs, et activez la validation en deux étapes du panneau si votre hébergeur la propose.
- Demandez à votre hébergeur la liste des comptes FTP et supprimez ceux que vous n'utilisez pas.
- Regardez dans Modules ce que vous avez installé et, par FTP, quels dossiers se trouvent dans
modules/. Ce qui est sur le disque mais pas dans la liste est en trop. - Vérifiez quelle version de PrestaShop et de PHP vous utilisez. S'il s'agit de PrestaShop 1.6 ou 1.7, ou de PHP 7.x, fixez une date pour la migration.
Migrer n'est pas un luxe : c'est la plus importante des mesures de sécurité
Nous savons que migrer une boutique est une corvée qui fait un peu peur. Il faut revoir les modules, le thème, les URL, les paiements, les factures. Mais après avoir vu tous ces cas de l'intérieur, notre conclusion est claire : la boutique la plus chère à maintenir est celle qu'on ne met pas à jour. Un incident coûte le nettoyage, la notification, les rétrofacturations, le temps de l'équipe et, surtout, la confiance des clients dont les cartes ont été utilisées ailleurs.
Une migration vers PrestaShop 9 avec une version actuelle de PHP ferme d'un coup les voies d'entrée connues des anciennes versions, vous oblige à faire l'inventaire de ce que vous avez installé et vous place sur une version qui continue de recevoir des correctifs. Si, en plus, vous surveillez ce qui change, la prochaine tentative se remarque le jour même.
Comment le résoudre dans PrestaShop
RKR Security Alert surveille la configuration, les paiements, les employés, les connexions, les gabarits du tunnel de commande et les fichiers, compare le cœur avec le ZIP officiel et vous alerte par Telegram dès que quelque chose change, de PrestaShop 1.7.6 à 9.2. RKR Sentinel vous signale les erreurs du site avant que vos clients ne vous en parlent, et une boutique qui devient soudain blanche, comme celle du cas 2, est une erreur qu'il vaut mieux voir dans la minute. RKR Order Guard évite les commandes, statuts de paiement et factures en double, pour que ce qu'indique le back-office soit fiable au moment du rapprochement avec la banque.
Et si vous soupçonnez que votre boutique est compromise ou si vous voulez la migrer avant qu'elle ne le soit, avec les forfaits d'heures de support de Rekire, nous réalisons l'audit, le nettoyage selon la méthode de cet article et la migration vers PrestaShop 9.