Un popup fals de Cloudflare, două vulnerabilități în lanț și 6.369 de fișiere: anatomia unei compromiteri Magento
de Claudiu Hulea · IT Management Consultant
Cum arată, pas cu pas, investigarea unui atac real — și de ce upgrade-ul de securitate pe care toată lumea îl crede suficient nu închide, de fapt, ușa.
Totul a început cu un angajat atent.
Într-o dimineață, cineva din echipa unui client — un magazin construit pe Magento 2.4.5 — a observat ceva ciudat pe pagina principală: un popup care imita perfect o verificare Cloudflare. „Let us know you’re human“, scria. Și trei pași simpli: apasă Win + R, apoi Ctrl + V, apoi Enter.
Pentru un ochi neantrenat, pare o verificare anti-bot obișnuită. În realitate, e una dintre cele mai eficiente tehnici de inginerie socială din ultimul an, numită ClickFix: un script copiază pe furiș o comandă în clipboard-ul victimei, apoi o convinge s-o lipească în dialogul Run al Windows-ului și s-o execute. Rezultatul — un infostealer care rulează direct pe stația angajatului, în afara oricărui antivirus care s-ar fi uitat la browser.
Popup-ul nu era decât vârful aisbergului. Ce am găsit dedesubt a fost o compromitere completă, activă de nouă luni, cu două vulnerabilități critice înlănțuite și 6.369 de fișiere malițioase presărate prin instalare.
Iată cum arată o investigație reală.
Prima privire: skimmerul din baza de date
Popup-ul ClickFix era livrat de un script terț, încărcat de pe un domeniu extern printr-un fragment de cod injectat în baza de date — mai exact într-un bloc CMS afișat pe toate paginile magazinului.
Detaliul care încurcă multe scanări automate: domeniul nu apărea niciodată în clar. Era codificat base64, ascuns într-un apel atob(). O căutare simplă SELECT ... WHERE content LIKE '%domeniu%' întoarce zero rezultate chiar și pe un site infectat. Trebuie să cauți după atob, nu după domeniu.
Am eliminat scriptul, am golit cache-ul (inclusiv Varnish — altfel skimmerul rămâne servit din cache ore întregi) și am blocat vizitatorii de a mai fi expuși. Dar asta era doar simptomul. Întrebarea reală: cum a ajuns acolo?
Vulnerabilitatea #1: PolyShell — uploadul care nu ar trebui să existe
Pe disc, în pub/media/custom_options/quote/, am găsit peste o mie de fișiere .php. Acolo nu au ce căuta niciodată fișiere PHP — e un director de upload pentru opțiunile custom ale produselor.
Fișierele erau polyglot-uri: începeau cu antetul GIF89a (deci trec de orice validare care verifică „e o imagine?“), urmat imediat de <?php. Un backdoor complet: verificare prin cookie-parolă, execuție de comenzi prin eval(base64_decode()), upload arbitrar de fișiere.
Vectorul, confirmat ulterior de cercetarea Sansec despre „PolyShell“: REST API-ul Magento pentru coșuri de oaspete, neautenticat:
POST /rest/V1/guest-carts/{cartId}/items
Adăugând un produs cu o opțiune de tip fișier, atacatorul încarcă polyglot-ul. Magento îl scrie pe disc în timpul validării, înainte să apuce să respingă ceva. Fără verificare de tip, fără restricție de extensie.
Partea neliniștitoare: pe site-ul investigat niciun produs nu avea opțiuni de tip fișier configurate, și totuși fișierele ajungeau pe disc. Vectorul e accesibil prin REST indiferent de configul magazinului.
Vulnerabilitatea #2: CosmicSting — cum s-a ajuns în baza de date
PolyShell explică webshell-urile de pe disc. Dar cum a fost injectat skimmerul în baza de date? Aici multe rapoarte se opresc la „atacatorul a injectat în CMS“ fără să spună cum.
Analiza logurilor a dat răspunsul. Skimmerul a fost scris printr-o singură cerere:
PUT /rest/V1/cmsBlock/1
…cu un token de admin valid. Dar în aceeași perioadă, 2.490 de încercări de a obține un token prin parolă au eșuat toate cu 401. Atacatorul nu avea nevoie de parolă — forja tokenul.
Cum? Prin CVE-2024-34102, cunoscut ca CosmicSting (CVSS 9.8): o vulnerabilitate XXE care permite citirea fișierului app/etc/env.php. Din el, atacatorul a extras crypt/key — cheia de criptare Magento. Iar cu acea cheie, poate semna tokenuri JWT de admin oricâte vrea.
Două vulnerabilități, în lanț: CosmicSting deschide ușa (citire fișier → furt cheie → forjare token), PolyShell oferă persistența pe disc.
Momentele care fac diferența
O investigație bună nu e o listă de comenzi. E o serie de întrebări la care refuzi să răspunzi din reflex. Câteva care au contat aici:
Execuția a eșuat — și de ce e important. Cele peste o mie de webshell-uri erau pe disc, dar niciunul nu se executa: configul nginx bloca rularea PHP în directorul de media. Am confirmat empiric — toate cele 669 de accesări directe primeau același răspuns de 1692 bytes (pagina de fallback), nu output de webshell. Concluzia schimbă totul: atacatorul avea control asupra conținutului aplicației, dar nu asupra sistemului de operare. Serverul nu trebuia reinstalat.
Căutarea case-sensitive care aproape a ratat 140 de fișiere. Prima curățare a folosit find -name '*.php'. În Linux, asta e case-sensitive — și a ratat 140 de fișiere cu extensii .PHP, .Php, .php7..gif, .inc. Le-am prins abia refăcând scanarea după conținut (grep '<?php'), nu după extensie. Lecție: la curățare, nu te încrede în extensii.
Restricția de admin care nu restricționa nimic. Am pus o regulă nginx care limita accesul la panoul de admin la rețeaua internă. Testată din exterior — panoul răspundea în continuare 200. Cauza: lanțul de proxy-uri (Cloudflare → WAF → Varnish → nginx) făcea ca nginx să vadă ca sursă 127.0.0.1 (Varnish, pe loopback), care e „intern“, deci regula lăsa tot traficul să treacă. Fără real_ip_recursive configurat corect pe toate hop-urile, orice restricție de IP e iluzorie. E genul de greșeală care arată bine în config și nu protejează nimic.
De ce rotirea cheii nu e suficientă. Am rotit crypt/key — pas evident după ce știi că a fost furată. Dar Magento validează tokenurile JWT de admin cu toate cheile din crypt/key, nu doar cu cea curentă. Am verificat în cod: prepareAllAccepted(). Cât timp cheia compromisă rămâne în fișier, tokenurile forjate cu ea rămân valide. Cheia veche trebuie eliminată, nu doar înlocuită cu una nouă. (Cu grija de a nu strica datele deja criptate cu ea — se reencriptează întâi.)
Lecția cea mare: patch-ul pe care toată lumea îl crede suficient
După curățare, am făcut ce ar face oricine: upgrade Magento la ultimul patch de securitate de pe linia respectivă (2.4.5-p14). Asta a închis CosmicSting — nativ, verificat.
Dar nu a închis PolyShell.
Pentru că, așa cum documentează Sansec, vulnerabilitatea de upload afectează toate versiunile Magento până la 2.4.8, cu fix doar în 2.4.9 (încă în pre-release la momentul scrierii), fără backport pe liniile de producție.
Asta e capcana. Un operator conștiincios face upgrade la ultimul patch, vede că e „la zi“ și presupune că e protejat. Dar vectorul prin care au intrat 80% din magazinele Magento neprotejate în această campanie rămâne deschis în core, indiferent cât de patch-uit ești.
Soluția, până la 2.4.9, e la nivel de infrastructură și cod defensiv:
- nginx — blochează execuția fișierelor executabile în
pub/media(nu doar.php— și.php8,.phtm,.phar) și accesul complet lacustom_options. - plugin la nivel de aplicație — respinge extensiile periculoase chiar la stratul de upload (
Magento\Framework\File\Uploader), care implicit acceptă orice extensie când nu e setat un whitelist. - WAF — blochează endpoint-urile vulnerabile.
Niciuna nu e un patch. Toate, împreună, țin locul patch-ului.
Ce ar trebui să verifice orice operator Magento
Dacă administrezi un magazin Magento, iată checklist-ul minim scos din acest incident:
- Fișiere executabile în
pub/media— caută după conținut, nu extensie:grep -rl '<?php' pub/media/. Orice rezultat = compromitere. - Nivelul de patch —
bin/magento --version. Dacă nu are sufix-pN, ești vulnerabil la CosmicSting și altele. - 2FA pe admin — obligatoriu în Magento 2.4, dar deseori dezactivat „ca să fie mai comod“.
- CSP — implicit e pe report-only (nu blochează nimic). Trebuie trecut pe enforced.
- Restricția de admin pe IP — și verificat că funcționează efectiv prin lanțul de proxy-uri, nu doar că e în config.
- Backdoor-uri de persistență — caută
accesson.phpși fișiere similare împrăștiate învar/,vendor/. - Dacă a fost compromis — rotește
crypt/key(și elimină cheia veche), parolele, tokenurile.
Concluzie
Atacatorul din spatele acestei campanii nu era sofisticat. Uneltele erau crimeware „de raft“, infrastructura era hosting offshore, iar tiparul de activitate — 24/7, fără pauză, luni întregi — arăta clar automatizare, nu țintire. Magazinul acesta a fost pur și simplu unul dintre miile scanate în masă.
Și exact asta e ideea. Nu trebuie să fii o țintă importantă ca să fii compromis. Trebuie doar să rulezi o versiune neprotejată dintr-o platformă populară, într-un moment în care un exploit public lovește 80% din magazinele vulnerabile în câteva săptămâni.
Apărarea nu a fost o singură măsură eroică. A fost un strat peste altul — execuție blocată, upload blocat, cheie rotită, WAF, headere, 2FA — fiecare acoperind ce lasă descoperit celălalt. Iar prima linie de apărare a fost, de fapt, un om atent care a observat un popup care nu era în regulă.
Braincap oferă servicii de răspuns la incidente, audit de securitate și securitate cibernetică pentru infrastructuri de comerț electronic. Dacă bănuiești o compromitere sau vrei o evaluare de securitate a magazinului tău, ne poți contacta la office@braincap.ro sau prin pagina de contact.
Surse
- Sansec — Magento PolyShell research
- CVE-2024-34102 (CosmicSting), CVSS 9.8 — vulnerabilitate XXE în Magento / Adobe Commerce.
Întrebări frecvente
Ce a fost, pe scurt, această compromitere Magento?
O compromitere completă a unui magazin Magento 2.4.5, activă de nouă luni: un popup fals de tip ClickFix la vizitatori, un skimmer injectat în baza de date și 6.369 de fișiere malițioase pe disc. La bază, două vulnerabilități înlănțuite: CosmicSting (CVE-2024-34102) și PolyShell.
Ce sunt CosmicSting și PolyShell?
CosmicSting (CVE-2024-34102, CVSS 9.8) e o vulnerabilitate XXE care permite citirea env.php și furtul cheii de criptare, cu care atacatorul forjează tokenuri de admin. PolyShell e o vulnerabilitate de upload prin REST API-ul de coșuri de oaspete, care lasă webshell-uri polyglot pe disc. CosmicSting deschide ușa, PolyShell dă persistența.
De ce nu e suficient upgrade-ul de securitate?
Pentru că patch-ul (ex. 2.4.5-p14) închide CosmicSting, dar NU PolyShell: vulnerabilitatea de upload afectează toate versiunile până la 2.4.8, cu fix doar în 2.4.9. Un operator „la zi" rămâne expus prin acest vector. Până la 2.4.9, apărarea e la nivel de infrastructură: blocarea execuției în pub/media, respingerea extensiilor periculoase la upload, WAF.
Ce ar trebui să verifice un operator Magento?
Fișiere executabile în pub/media (caută după conținut, `grep -rl "<?php" pub/media/`), nivelul de patch (`bin/magento --version`), 2FA pe admin, CSP pe enforced (nu report-only), restricția de admin pe IP care chiar funcționează prin lanțul de proxy, backdoor-uri de persistență, și — dacă a fost compromis — rotirea și eliminarea cheii vechi crypt/key.