instituție publică

Webshell pe o revistă academică: șters, revenea în mai puțin de un minut

Client
Revistă academică a unei universități din România
Platformă
Open Journal Systems 3.5.0.3 (revistă științifică online)
Infecție
Webshell care se reinstala prin cron + backdoor în .bashrc
Durată
o dimineață (curățare, securizare, verificare)
Downtime
zero

Cazul acesta nu a pornit de la o sesizare a clientului. L-am găsit noi, în timpul unei verificări de rutină pe server — revista funcționa normal, nimeni nu observase nimic, iar în panoul de administrare nu apărea niciun semn.

Pe platformă exista un webshell: un fișier care îi permitea unei persoane din exterior să administreze site-ul de la distanță, prin browser, cu exact aceleași drepturi ca ale contului de găzduire. Marcajele de timp îl datau din 13 martie 2026. Aproximativ șase luni.

Un fișier care se dădea drept componentă a platformei

Webshell-ul, un fișier PHP de aproximativ 460 KB, era plasat în directorul de migrări al platformei:

classes/migration/upgrade/v3_4_0/I4235_QuickSubmitSubmissionProgressType.php

Numele nu era ales la întâmplare. Open Journal Systems ține în acel director zeci de fișiere de migrare cu nume din același tipar: un identificator de sarcină, urmat de o descriere în CamelCase. Atacatorul a combinat prefixul unui fișier real cu numele altuia, ambele existente în platformă. Rezultatul e un nume care, într-o listare de director alături de alte cincizeci la fel, nu atrage atenția nimănui.

Singurul lucru care îl trăda era dimensiunea. Fișierele de migrare legitime au între 2 și 15 KB; acesta avea 460.

De ce ștergerea fișierului nu rezolva nimic

Partea care schimbă complet natura intervenției: fișierul nu era singur. O sarcină automată (cron) rula în fiecare minut și îl redescărca de pe internet, de la o adresă fixă.

Consecința practică e importantă de înțeles, pentru că e tiparul în care majoritatea curățărilor eșuează: dacă cineva ștergea doar fișierul — reacția firească, și singura pe care o face un scanner automat — acesta reapărea în mai puțin de un minut. Site-ul ar fi părut curat exact atâta timp cât dura verificarea de după ștergere, iar la următoarea căutare fișierul ar fi fost din nou acolo, cu o dată de creare nouă, sugerând o „reinfectare” care în realitate nu s-a întâmplat niciodată. Nu a existat nicio a doua intrare pe server: a existat un mecanism care nu fusese oprit.

Sursa era un depozit public de cod, adică o infrastructură pe care atacatorul nu trebuia să o întrețină și care nu putea fi blocată la nivel de reputație — traficul mergea către o adresă legitimă, folosită zilnic de milioane de proiecte.

Backdoor-ul din configurarea contului

A treia componentă nu era în site, ci în cont. În fișierul de configurare al shell-ului (.bashrc) era inserat un backdoor de tip gsocket — un instrument care deschide un canal de acces de la distanță fără să aibă nevoie de o adresă IP publică sau de un port deschis în firewall.

Era ascuns prin trei tehnici suprapuse, fiecare adresându-se unui alt mod de a te uita la fișier:

  • Text codificat, ca linia să nu conțină niciun cuvânt căutabil — o căutare după „gsocket” sau după orice nume de program nu returna nimic.
  • Un marcaj fals de tipul „NU ȘTERGEȚI ACEASTĂ LINIE”, comentariu care imită convenția prin care unele programe legitime își marchează propriile adăugiri în fișierele de configurare. Cine îl vedea era descurajat să îl atingă.
  • O secvență de curățare a ecranului, executată imediat după: la deschiderea unei sesiuni pe server, terminalul se ștergea, iar linia nu apărea în istoricul vizibil al ecranului.

În plus, programul pornit de acea linie se prezenta sub numele unui proces intern al sistemului de operare — deci nici într-o listare a proceselor în execuție nu ieșea în evidență.

O precizare de calibrare, pentru că nu vrem să prezentăm situația mai gravă decât era: componenta executabilă a acestui backdoor lipsea deja la momentul verificării. Nu era funcțional. Rămăseseră cheile de acces și mecanismul care l-ar fi pornit — adică tot ce ar fi fost necesar ca să redevină activ, dar nu și programul propriu-zis.

Cum a fost posibil

Un webshell plasat pe server nu folosește nimănui dacă nu poate fi rulat. Aici putea.

Directoarele care conțin codul aplicației — classes/, lib/, dbscripts/ — erau accesibile direct din browser. Sunt directoare cu cod intern al platformei, care nu au niciun motiv să răspundă la cereri web: nimeni nu deschide un fișier de migrare într-un browser. Erau însă servite ca orice altă pagină, ceea ce înseamnă că un fișier PHP strecurat acolo se executa prin simpla lui accesare la o adresă web.

Aceasta este cauza structurală a incidentului. Nu explică cum a intrat atacatorul prima oară, dar explică de ce, odată intrat, a putut transforma un fișier oarecare într-un panou de control.

Ce nu am putut stabili

Rămâne întrebarea de la care pornește orice investigație: cum a obținut atacatorul accesul inițial? Nu am putut răspunde, și preferăm să spunem asta explicit decât să oferim o ipoteză frumoasă.

Ce știm sigur este că nu e vorba de o platformă neglijată: revista rula Open Journal Systems 3.5.0.3, o versiune recentă, deci vectorul nu a fost o vulnerabilitate cunoscută a unei versiuni depășite — explicația cea mai comună, și cea care ar fi fost cel mai la îndemână de invocat.

Ce ne lipsește sunt jurnalele. Cele de acces web se păstrează pe server doar câteva luni, iar compromiterea datează din martie 2026. Urma inițială nu mai există fizic. Orice reconstituire a ei ar fi speculație, iar o speculație prezentată drept concluzie e mai dăunătoare decât un „nu știm” asumat: te face să securizezi calea greșită.

Cronologia

13 martie 2026
Webshell-ul este scris pe server, în directorul de migrări al platformei. Calea de intrare nu mai poate fi stabilită — jurnalele din perioada respectivă nu se mai păstrează.
martie – septembrie 2026
Acces de citire și scriere la toate fișierele site-ului, întreținut printr-o sarcină automată care rescria webshell-ul în fiecare minut. Site-ul funcționează normal tot acest interval.
9 septembrie 2026, dimineața
O verificare de rutină pe server scoate la iveală compromiterea.
9 septembrie 2026
Curățare: sarcina automată întâi, apoi fișierul. Urmează backdoor-ul din configurarea contului și cheile de acces rămase.
9 septembrie 2026, după curățare
Se blochează accesul web la directoarele de cod. Verificare timp de 25 de minute că webshell-ul nu reapare.

Curățarea, pas cu pas

Înainte de orice modificare — copii de siguranță complete ale fișierelor și bazei de date, plus o copie a configurației de server originale.

Apoi, în această ordine, care contează:

  • am eliminat întâi sarcina automată, nu fișierul. Inversată, ordinea nu ar fi produs niciun efect: fișierul s-ar fi întors în mai puțin de un minut. Restul configurației de sarcini automate a rămas neatinsă;
  • am șters webshell-ul, apoi am urmărit directorul timp de 25 de minute ca să confirmăm că nu revine;
  • am curățat linia inserată în .bashrc, păstrând restul fișierului de configurare așa cum era;
  • am șters cheile de acces rămase de la backdoor — fără ele, mecanismul nu mai poate fi repornit nici dacă cineva readuce programul;
  • am verificat că nu rulează procese ascunse pornite anterior și rămase active;
  • am păstrat toate fișierele găsite, jurnalele și marcajele de timp, separat, în afara site-ului, ca probă pentru o eventuală analiză ulterioară.

Securizarea

Curățarea rezolvă incidentul; securizarea rezolvă cauza. Am adăugat o regulă de server care blochează accesul web la fișierele PHP din directoarele de cod ale aplicațieiclasses/, lib/, dbscripts/. Un fișier strecurat acolo în viitor nu mai poate fi executat prin browser; rămâne, în cel mai rău caz, un fișier inert.

Am verificat apoi două lucruri, în această ordine: că restricția funcționează efectiv — nu doar că regula a fost scrisă, ci că o cerere către un fișier din acele directoare chiar este respinsă — și că site-ul nu este afectat de ea. O regulă corectă pe hârtie, dar netestată, e o presupunere, nu o măsură de securitate.

Verificările de la final

O curățare e completă doar dacă poate fi demonstrată. Verificările noastre, toate trecute:

  • sarcina automată malițioasă — eliminată
  • webshell-ul — șters, neapărut în 25 de minute de monitorizare
  • backdoor-ul din configurarea contului — eliminat
  • cheile de acces rămase — șterse
  • 0 procese ascunse în execuție
  • scanare antimalware completă a contului — 0 detecții
  • acces web la directoarele de cod — blocat, verificat prin cerere efectivă
  • directorul de fișiere al revistei, aflat în afara zonei publice — fără fișiere executabile plasate de atacator
  • directorul public/ — la fel, curat
  • conturile de administrare — toate legitime, niciunul creat de atacator
  • funcționarea site-ului — normală

Ce i-am recomandat clientului

Timp de șase luni, o persoană neautorizată a avut acces de citire și scriere la toate fișierele site-ului — implicit și la fișierul de configurare care conține datele de conectare la baza de date. Recomandările pornesc de aici:

  • Schimbarea parolei bazei de date și actualizarea ei în config.inc.php. Parola a fost lizibilă pentru atacator tot intervalul.
  • Schimbarea parolelor conturilor de administrare. Am verificat lista de conturi și nu am găsit niciunul creat de atacator — administratorul a rămas cel legitim. Schimbarea rămâne necesară, pentru că accesul la fișiere permitea și alte căi de obținere a unei sesiuni.
  • Schimbarea parolelor de găzduire și FTP.
  • Evaluarea unei notificări privind datele cu caracter personal. Platforma conține date ale autorilor, recenzorilor și cititorilor — nume, adrese de e-mail, manuscrise nepublicate. Nu avem nicio dovadă că aceste date au fost extrase; nu putem însă dovedi nici contrariul, pentru că jurnalele din perioada respectivă nu mai există. Am prezentat instituției faptele exact în această formă: evaluarea și decizia îi aparțin.
  • Verificarea conținutului publicat — articole, numere, pagini statice — pentru a confirma că nu au fost operate modificări neautorizate.

Ce merită reținut

Trei lecții, niciuna specifică acestei reviste:

  • Ștergerea fișierului nu este o curățare cât timp mecanismul care îl readuce rămâne pe loc. Un scanner care găsește și șterge un webshell, fără să atingă sarcina automată care îl redescarcă, produce exact impresia de site curat — pentru mai puțin de un minut.
  • O platformă la zi nu compensează o configurare de server permisivă. Versiunea rulată era recentă, actualizările erau făcute. Directoarele cu cod intern erau totuși servite pe web, iar asta a fost suficient.
  • Durata de păstrare a jurnalelor decide ce se poate afla după un incident. Aici e diferența dintre a ști cum a intrat atacatorul și a nu putea răspunde niciodată — iar în cazul datelor personale, dintre o evaluare bazată pe fapte și una bazată pe ce nu poate fi exclus.

Un caz cu un mecanism de persistență înrudit — malware care se rescria singur după fiecare curățare, pe un magazin WordPress — e descris în studiul de caz despre reinfectarea de după curățare. Restul intervențiilor documentate sunt în studiile de caz.

Anexă tehnică — indicatori de compromitere

Pentru administratorii de platforme Open Journal Systems și pentru colegii din industrie care vor să-și verifice propriile servere:

Fișier webshell
classes/migration/upgrade/v3_4_0/I4235_QuickSubmitSubmissionProgressType.php — aproximativ 460 KB, față de 2–15 KB cât au fișierele de migrare legitime
Tipar de denumire
prefixul unui fișier de migrare OJS real, combinat cu descrierea altuia — ambele componente există în platformă, combinația nu
Mecanism de persistență
sarcină cron rulând în fiecare minut, care redescarcă fișierul; ștergerea fișierului singur duce la reapariția lui sub 60 de secunde
Sursa de redescărcare
depozit public de cod — adresă dezactivată aici, ca să nu fie accesată din greșeală: hxxps://raw.githubusercontent[.]com/IEKKUDA6Gox/My-Shell/refs/heads/main/tengkorak.php
Backdoor secundar
gsocket, inserat în .bashrc; conținut codificat, comentariu fals de tipul „NU ȘTERGEȚI ACEASTĂ LINIE”, secvență de curățare a ecranului imediat după; proces deghizat sub numele unui proces intern al sistemului de operare. Componenta executabilă lipsea; cheile de acces și mecanismul de pornire erau prezente
Cauză structurală
directoarele classes/, lib/, dbscripts/ accesibile direct din browser, deci orice fișier PHP plasat acolo este executabil printr-o cerere web
Verificare recomandată
cererea unui fișier PHP din directoarele de cod ale platformei — orice răspuns diferit de refuz înseamnă că un fișier strecurat acolo poate fi executat
Verificare recomandată (persistență)
lista sarcinilor automate ale contului, căutând intrări care descarcă fișiere de pe internet; și .bashrc, căutând linii codificate, comentarii de tip „nu ștergeți” sau secvențe de curățare a ecranului
Verificare recomandată (dimensiune)
compararea dimensiunilor fișierelor dintr-un director cu cele ale fișierelor de același tip — a fost singurul semnal vizibil într-o listare obișnuită

Site-ul tău trece prin ceva similar?

Îl curățăm și îl securizăm într-o singură intervenție, de la 250 lei, cu garanție 30 de zile. Diagnosticul e gratuit, fără obligații.

Cere diagnostic gratuit

Alte studii de caz

Citește și