Skip to main content
Blog

Joomla website gehackt via YOOtheme Pro, net voor beveiligingspatch

23 oktober 2026

Op 21 oktober schreef ik over twee kritieke beveiligingsupdates op één dag: PHP (PHP2Shell) en YOOtheme Pro.

Wat ik op dat moment nog niet wist: een van mijn eigen websites was diezelfde ochtend al gehackt via precies dat lek in YOOtheme Pro. Die website was verder helemaal up to date. Joomla 6.2 en alle extensies bijgewerkt. Toch was het raak.

In deze blog lees je hoe de hack werkte, hoe ik hem heb onderzocht en opgelost, en wat ik voortaan anders doe. Onderaan staat een checklist waarmee je je eigen sites kunt controleren.

1. Mijn eerste schrik: was het PHP2Shell?

Ik ontdekte de hack op woensdag 22 oktober, tijdens onderhoudswerkzaamheden aan de site. Dat was één dag nadat zowel het PHP-lek (PHP2Shell) als het YOOtheme-lek bekend werd. Mijn eerste gedachte was dus: dit kan het PHP2Shell issue zijn. Dat lek zit in PHP zelf en treft dus elke PHP-applicatie op de server. In het ergste geval was niet alleen deze website, maar de hele VPS server waar de website op staat, gecompromitteerd. Mijn angst werd groter toen ik niet meer via SSH kon inloggen. Dat voelde als het scenario waar je als beheerder het meest bang voor bent: een aanvaller die de hele server heeft overgenomen en jou dan buitensluit.

Na verder onderzoek bleek de oorzaak een stuk onschuldiger. Op de server draait fail2ban die verdacht gedrag op de server blokkeert. Ik had de website eerst via FTP geanalyseerd en daarbij veel verbindingen gemaakt. Fail2ban zag dat als verdacht gedrag en had mijn eigen IP-adres geblokkeerd. Fail2ban deed zijn werk goed.

Nadat ik weer toegang had, heb ik eerst de server zelf gecontroleerd:

  • In de logbestanden waren geen andere SSH-logins te zien dan die van mezelf.
  • Er waren geen nieuwe cronjobs aangemaakt die op de achtergrond op bepaalde tijden bepaalde programma's kunnen opstarten (bijvoorbeeld "slapende" backdoor scripts).
  • In ~/.ssh/authorized_keys stonden geen onbekende sleutels waarmee je vanaf afstand op de server kunt inloggen.
  • De andere websites op dezelfde server zijn goed van elkaar afgeschermd en niet gewaren niet getroffen. Alleen deze ene website was gehackt.

De server was dus niet overgenomen. De aanvaller was binnengekomen via een andere manier maar niet via PHP2Shell issue.

2. Tijdlijn van de hack

Ik heb de gehackte website en alle logbestanden van het afgelopen jaar naar mijn eigen computer gekopieerd. Door het daar lokaal te analyseren kon ik het verloop van de hack vrij precies reconstrueren (tijden in Nederlandse tijd):

WanneerWat
1 – 19 oktober De website wordt continue bezocht door geautomatiseerde scans naar bekende lekken in WordPress en Joomla-extensies (JCE, Astroid, uploadtrucs). Allemaal mislukt.
21 okt, 08:44 Het lek in YOOtheme Pro wordt misbruikt. Er wordt een achterdeur (webshell) in /images/ geplaatst.
21 okt, 12:12 Het lek wordt nogmaals misbruikt.
21 okt, ± 15:00 YOOtheme geeft de patch (versie 5.0.53) vrij, een uur eerder dan de geplande release van 16:00.
21 okt, 15:11 Ik werkte YOOtheme Pro bij naar 5.0.53. Het lek is dicht en latere pogingen worden geweigerd. Maar het hacker backdoor script stond al op de server.
21 okt, 23:34 De achterdeur wordt vanaf allerlei IP-adressen gebruikt.
22 okt, 00:17 De eerste extra webshells en testbestanden verschijnen in de root.
22 okt, 06:48 Verborgen payloads in nepmappen en nep-afbeeldingen. Daarnaast komen er zo'n 5.600 .htaccess-bestanden in alle mappen.
22 okt, 09:25 Google krijgt spampagina's te zien: index.php is vervangen en robots.txt is aangepast.
22 okt, 14:31 Een tweede groep plaatst een eigen webshell.
22 okt, 17:41 Een derde groep verwijdert de shells van de anderen en plaatst eigen shells. Daarbij worden ook enkele echte bibliotheekbestanden leeggemaakt.
22 okt, 17:55 Ik ontdekte de hack tijdens onderhoudswerkzaamheden. De site meteen offline gehaald, onderzocht en hersteld.

Het belangrijkste punt in deze tijdlijn: de inbraak gebeurde 's ochtends, ruim zes uur voordat de beveiligingsupdate van YOOtheme beschikbaar was. Ook de snelste updateprocedure had dit niet kunnen voorkomen. De release stond gepland om 16:00, maar om 15:10 hoorde ik van internationale Joomla-collega's dat de patch rond 15:00 al was vrijgegeven. Ik had de website om 15:11 al bijgewerkt, ongeveer tien minuten na de release. Maar een update haalt een achterdeur die al geplaatst is niet weg.

3. Hoe de hack werkte

3.1 Het lek in de afbeeldingsverwerking van YOOtheme Pro

YOOtheme Pro heeft een functie die afbeeldingen bewerkt en in een cache bewaart. In de kwetsbare versies (5.0.0 tot en met 5.0.52) kon een aanvaller met een speciaal opgebouwde URL twee dingen tegelijk laten doen:

  1. een bestand van een externe server laten downloaden (parameter FROMFILE);
  2. dat bestand opslaan op een zelfgekozen plek en met een zelfgekozen extensie (parameter SAVE).

De aanvaller liet de site een "afbeelding" ophalen waarin PHP-code verstopt zat. Die werd opgeslagen als .php-bestand in /images/. Op de server mocht PHP in die map gewoon draaien. Daarmee had de aanvaller direct een werkende achterdeur, met toegang tot alle bestanden en via configuration.php ook tot de database.

3.2 De achterdeur werd gedeeld of verkocht

Na de eerste inbraak bleef het niet bij één aanvaller. In de logbestanden zag ik minstens drie verschillende groepen die elk hun eigen webshells plaatsten. Ze vochten onderling om de site. De ene groep maakte de shells van de andere leeg en zette in elke map een .htaccess-bestand neer dat PHP blokkeerde, behalve voor hun eigen bestanden. Een .htaccess-bestand bevat instellingen voor Apache webservers die bepalen wat wel en niet is toegestaan binnen een map op de webserver. Maar op deze server draait nginx, en nginx negeert .htaccess. Die ruim 5.600 bestanden hadden dus geen enkel effect.

3.3 Het doel: SEO-spam via cloaking

Het uiteindelijke doel was geld verdienen met zoekmachinespam. Daarbij worden zoekmachines zoals Google misleid om bezoekers naar ongewenste of misleidende pagina’s te lokken. De index.php van Joomla werd vervangen door een script dat eerst kijkt wie de pagina opvraagt:

  • Gewone bezoekers zagen de normale website. Daardoor viel de hack niet direct op.
  • Googlebot en Bingbot kregen Japanse spampagina's van een nepwebwinkel te zien, live opgehaald van de server van de aanvaller.

Daarnaast werd robots.txt aangepast met een verwijzing naar een spam-sitemap. Binnen enkele uren had Google honderden spam-URL's gecrawld, zoals /?woord/123456789012 en /?c=code. In de zoekresultaten verschenen ze zelfs met prijzen, sterrenbeoordelingen en een recente datum. Die gegevens kwamen niet van Google, maar uit de nep-HTML zelf.

4. Wat ik heb gevonden

  • Ongeveer 15 webshells en backdoors, verspreid over onder andere /images/, submappen daarvan, /administrator/templates/, /components/ en /libraries/.
  • Nepmappen met willekeurige namen in de root, en nepmappen diep in de site met een bestaande naam die nog een keer herhaald werd (bijvoorbeeld .../com_jedchecker/com_jedchecker/).
  • Versleutelde payloads vermomd als .png, .bmp, .mp3 en .jpg, met een PHP-loader ernaast.
  • Een vervangen index.php met het SEO-spamscript, en een aangepaste robots.txt.
  • Een php.ini in /images/ die probeerde de PHP-beveiliging uit te schakelen.
  • Ongeveer 5.600 .htaccess-bestanden.
  • Vijf legitieme bibliotheekbestanden die leeggemaakt waren.

Ik heb alle PHP- en JavaScript-bestanden vergeleken met het officiële Joomla 6.2.0-pakket. Afgezien van index.php, de .htaccess-bestanden en de leeggemaakte bestanden was de Joomla-core onaangetast. In de Joomla-beheeromgeving vond ik geen enkel bewijs dat iemand had ingelogd. De aanvallers hadden dat ook niet nodig: via de webshells konden ze alles al.

5. Hoe ik het heb opgelost

5.1 Eerst veiligstellen

  • Alle gehackte bestanden en mappen in hun geheel verplaatst naar een aparte map en de rechten daarop op 000 gezet. Zo konden de schadelijke bestanden niet meer worden geopend of uitgevoerd, maar bleven ze wel bewaard voor verder onderzoek.
  • Tijdelijk een "website in onderhoud"-melding geplaatst met logo en contactinformatie voor bezoekers.
  • Alle logbestanden naar mijn eigen computer gekopieerd. Zonder die logs had ik het exacte inbraakmoment en de aanvalsmethode nooit kunnen achterhalen.

5.2 Lokaal analyseren

Ik heb de gehackte bestanden en logbestanden op mijn eigen computer onderzocht. Dat deed ik in een afgeschermde Docker-omgeving, waarin ik een aparte webserver met de website kon draaien. Zo kon ik veilig en rustig reconstrueren wat er was gebeurd, de bestanden vergelijken met een schone Joomla-installatie en alle achterdeurtjes (webshells), IP-adressen van aanvallers en spam-URL’s in kaart brengen.

5.3 Een schone backup terugzetten, maar welke?

Ik heb ervoor gekozen om de site niet bestand voor bestand op te schonen. Bij drie of meer aanvallers en versleutelde payloads in nepmappen is de kans te groot dat je iets mist. Daarom heb ik een backup teruggezet.

Daarbij zit een valkuil. Op 21 oktober heb ik met Akeeba-backup twee backups gemaakt, maar dat was allebei na de inbraak. Ze bevatten de achterdeur dus al. Ik heb daarom de laatste volledige backup van vóór de hack gebruikt, van 13 oktober. Controleer altijd of het bestand van de eerste achterdeur niet in de backup zit voordat je die terugzet. 

De backup heb ik in een volledig lege webroot teruggezet. Zet je een backup terug over de bestaande bestanden heen, dan blijven de webshells, nepmappen en .htaccess-bestanden gewoon staan.  Enkele artikelen die na 13 oktober waren gepubliceerd, heb ik handmatig vanuit de database gekopieerd en teruggeplaatst in de schone website.

Een dag later, op 23 oktober adviseerde YOOtheme in een e-mail om bij een hack een back-up van 19 oktober of eerder terug te zetten, of van vóór de eerste verdachte aanvraag in de logbestanden, en daarna YOOtheme Pro direct bij te werken.

5.4 Direct alles bijwerken

Een backup van vóór de hack bevat ook de kwetsbare versie van YOOtheme Pro. Ik heb daarom alles bijgewerkt voordat de site weer publiek bereikbaar werd: YOOtheme Pro 5.0.53, JCE, Akeeba, de YourSites-client enzovoort. Scanners proberen het lek nog steeds, dus dit moet echt eerst gebeuren.

Daarna heb ik gecontroleerd dat de herstelde site schoon is:

  • de Joomla-core is identiek aan het officiële pakket;
  • er staan geen webshells en geen PHP-bestanden in /images/;
  • er zijn geen onbekende gebruikers of extensies;
  • er zijn geen publiek schrijfbare bestanden meer.

5.5 Wachtwoorden en secrets vervangen

Ga ervan uit dat alles wat PHP kon lezen ook in de handen van de aanvaller kan zijn gekomen. Ik heb daarom het volgende vervangen:

  • een nieuwe database, databasegebruiker, wachtwoord en tabelprefix;
  • een nieuwe Joomla-secret. 
    De Joomla-secret is een geheime beveiligingssleutel die Joomla gebruikt om bepaalde gegevens en beveiligingscodes te beschermen;
  • een nieuw Akeeba Secret Word;
  • een nieuw FTP-wachtwoord voor de backupserver;
  • een nieuw YourSites-wachtwoord.
    Met YourSites monitor, beheer en update ik Joomla-websites op afstand;
  • een nieuw SMTP-wachtwoord (aangevraagd).

5.6 De spam-URL's uit Google laten verdwijnen

Na het terugzetten van de backup zijn de spampagina's weg. Google weet dat alleen nog niet. De meeste spam-URL's zijn querystrings op de homepage. Joomla negeert die en toont gewoon de homepage met status 200. Daardoor blijven de URL's lang in de index staan.

Ik heb nginx daarom zo ingesteld dat deze URL's een http statuscode 410 Gone teruggeven. Daarmee vertelt je website aan Google dat de pagina bewust is verwijderd. Een 410 verdwijnt sneller uit de index dan een 404.

# Spam-URL's van de hack: laat zoekmachines weten dat ze weg zijn
if ($args ~* "^([a-z-]+/[0-9]{8,}|c=[a-z0-9]{10,})$") { return 410; }
location ~* "^/(inx_sitemap\.xml|[a-z_-]*sub[a-z0-9_-]*\.xml)$" { return 410; }

Pas de patronen aan op wat jij in je eigen logbestanden ziet, en controleer dat je echte URL's er niet onder vallen. Blokkeer de spam-URL's niet via robots.txt: Google moet ze kunnen crawlen om de 410 te zien.

In Google Search Console en Bing Webmaster Tools doe je daarna het volgende:

  1. Verwijder onbekende eigenaren en gebruikers. 
    Aanvallers kunnen zichzelf toegang geven tot jouw Google Search Console en Bing Webmaster Tools door een HTML-verificatiebestand op de gehackte website te plaatsen.
  2. Verwijder onbekende sitemaps en dien je echte sitemap opnieuw in.
  3. Vraag een tijdelijke verwijdering aan voor alle URL's met het voorvoegsel https://jouwdomein.nl/?.
  4. Kijk bij "Beveiligingsproblemen" en "Handmatige acties" of de site gemarkeerd is, en vraag zo nodig een herbeoordeling aan.

Reken erop dat het twee tot acht weken duurt voordat alle spam uit de zoekresultaten verdwenen is.

6. Wat ik ervan geleerd heb

6.1 Up-to-date is niet genoeg

Deze site werd automatisch bijgewerkt, en dat heeft het lek dezelfde dag nog gedicht. Maar de aanval kwam vóór de update. Tegen zo'n zero-day helpen alleen extra beveiligingslagen. Updaten blijft wel noodzakelijk: zonder de update had het lek nog veel langer opengestaan.

6.2 Geen PHP in uploadmappen

De hele hack draaide om één ding: PHP mocht draaien in /images/. Als PHP daar geblokkeerd was geweest, was het geplaatste bestand onschadelijk geweest. Let op: draai je nginx, dan moet je dit in de nginx-configuratie regelen, want .htaccess werkt daar niet:

location ~* ^/(images|media|cache|tmp)/.*\.(php|phtml|phar|php\d?)$ { deny all; }

6.3 Bestandsrechten en PHP-instellingen

  • Mappen 755, bestanden 644, configuration.php op 444. Geen publiek schrijfbare bestanden.
  • Gebruik disable_functions en open_basedir, en negeer php.ini- en .user.ini-bestanden per map.

6.4 Merk het sneller op

De eerste achterdeur stond er ruim een dag voordat ik de hack ontdekte tijdens onderhoudswerkzaamheden. Gewone bezoekers zagen door de cloaking niets bijzonders. Met monitoring op nieuwe .php-bestanden of gewijzigde core-bestanden had ik het binnen een paar uur geweten. Bijvoorbeeld met een cronjob die checksums vergelijkt. Een Web Application Firewall (WAF) had verzoeken met ../ en een externe URL in de parameters ook kunnen tegenhouden.

6.5 Bewaar je logbestanden en je backups

Zonder logbestanden van een heel jaar had ik nooit precies kunnen zien wanneer en hoe de aanvaller binnenkwam. En zonder een backup van ruim een week oud had ik geen schone versie kunnen terugzetten. Zorg dat je backups ver genoeg teruggaan, en dat ze buiten de server bewaard worden.

7. Gebruik je YOOtheme Pro 5.x? Controleer je website!

Controleer niet alleen of je YOOtheme Pro 5.0.53 of hoger hebt geïnstalleerd. Kijk ook of aanvallers al zijn binnengedrongen voordat je de update uitvoerde. Het beveiligingslek staat geregistreerd als CVE-2026-102785 en heeft de hoogste risicoscore: 10 uit 10.

  1. Zoek naar aanvalspogingen in de access logs.

    YOOtheme adviseert te zoeken naar yootheme, cache, FROMFILE en SAVE. Begin met de twee meest verdachte termen:

    grep -Ei 'FROMFILE=|SAVE=' access.log*

    Voor een bredere controle:

    grep -Ei 'yootheme|cache|FROMFILE|SAVE' access.log*

    Vooral verzoeken met option=com_ajax, FROMFILE= en SAVE= zijn verdacht. De bredere zoekopdracht kan veel normale verzoeken opleveren, omdat YOOtheme en cache ook bij gewoon websiteverkeer voorkomen.

  2. Zoek naar verdachte PHP-bestanden.

    Controleer vooral media/yootheme/cache. Volgens YOOtheme kunnen daar de eerste schadelijke bestanden worden geplaatst. Daarna kunnen aanvallers meer bestanden verspreiden over de website.

    find images media cache tmp assets -type f -iname "*.php*" 2>/dev/null

    Controleer ook andere mappen. YOOtheme noemt assets/images/accesson.php als voorbeeld van een achterdeur (webshell). Niet alle aanvallers gebruiken dezelfde bestandsnamen of locaties.

  3. Tel de .htaccess-bestanden.

    Een normale Joomla-installatie heeft er doorgaans maar enkele, afhankelijk van de configuratie en extensies.

    find . -name .htaccess | wc -l

    Een plotseling groot aantal kan wijzen op een hack. Op een nginx-server hebben deze bestanden geen effect, maar ze kunnen wel een duidelijk spoor van de aanvallers zijn.

  4. Controleer index.php en robots.txt.

    Vergelijk deze bestanden met een schone Joomla-installatie van dezelfde versie. Let op onbekende code, verdachte aanpassingen en onverwachte wijzigingsdatums. Houd er rekening mee dat robots.txt ook legitieme, websitespecifieke aanpassingen kan bevatten.

  5. Controleer Google op zoekmachinespam.

    Zoek in Google met site:jouwdomein.nl naar vreemde zoekresultaten, bijvoorbeeld Japanse teksten, onbekende productpagina's of andere inhoud die niet bij je website hoort. Controleer ook Google Search Console en Bing Webmaster Tools.

  6. Controleer afbeeldingen die geen afbeeldingen zijn.

    Aanvallers kunnen schadelijke PHP-code verbergen in bestanden die op afbeeldingen lijken. Een eerste controle:

    file images/* | grep -v -i image

    Deze opdracht controleert alleen bestanden direct in de map images. Voor een uitgebreidere controle, inclusief onderliggende mappen:

    find images media -type f -exec file {} + | grep -Ei 'PHP|script|text'

    Deze controle kan ook onschuldige tekstbestanden tonen en vindt niet iedere verborgen webshell. Een bestand dat als afbeelding wordt herkend, kan alsnog schadelijke code bevatten.

Belangrijk: een update verwijdert geen achterdeurtjes

YOOtheme Pro 5.0.53 dicht het beveiligingslek, maar verwijdert geen schadelijke bestanden die aanvallers eerder hebben geplaatst. Een website kan daardoor nog steeds gehackt zijn, ook als de nieuwste versie is geïnstalleerd en alles normaal lijkt te werken.

Vind je niets verdachts? Dat is geen garantie dat je website schoon is. Aanvallers kunnen hun sporen hebben gewist of bestanden op andere locaties hebben geplaatst. Controleer daarom ook de wijzigingsdatums van bestanden en vergelijk de website bij twijfel met een schone installatie.

Vind je aanwijzingen voor een hack, dan is het verstandig om de website tijdelijk offline te halen en een aantoonbaar schone back-up van vóór de aanval terug te zetten. Doe dit in een volledig lege webroot, zodat achtergebleven schadelijke bestanden niet blijven staan. Werk daarna Joomla, YOOtheme Pro en alle extensies bij en vervang mogelijk buitgemaakte wachtwoorden en beveiligingssleutels.

Meer informatie: CVE-2026-102785 en de officiële YOOtheme Pro changelog, en Joomla website gehackt: wat je nu moet doen 

Hulp nodig?

Denk je dat jouw Joomla-site via dit lek gehackt is, of wil je zeker weten dat dat niet zo is? Neem contact met me op. Ik help je graag met het onderzoek, het herstel en het beter beveiligen van je site.

Peter Martin
Joomla Specialist

Peter is Joomla specialist en Linux admin voor snelle, veilige en schaalbare websites.

Recente artikelen