Een ondernemer belde me omdat er rare links in de footer van zijn website stonden. Gokreclame, in het Engels, onderaan elke pagina. Zijn eerste vraag was of ik die weg kon halen.
Dat kon. Maar de spam was niet het probleem. De spam was het symptoom.
Wat er onder zat
Ik kreeg toegang en ging kijken. In drie verschillende functions.php-bestanden stond dezelfde regel:
@eval(get_option('woocommerce_security_version'));
Een keer in het thema, een keer in het child-thema en een keer in een standaard WordPress-thema dat nog geinstalleerd stond maar niet werd gebruikt. Drie plekken, want als je er een vindt en weghaalt, draaien de andere twee gewoon door.
Wat die regel doet: hij haalt code op uit de database en voert die uit. De code zelf staat dus niet in een bestand waar een scanner naar kijkt, maar in een database-optie. En die optie heette woocommerce_security_version.
Daar zit de truc. Wie door zijn database scrollt en die naam ziet, denkt aan WooCommerce en gaat verder. Er stond nog een tweede: wordfence_security_loader. Ook die klinkt als iets van een beveiligingsplugin. Het was de tweede achterdeur.
De eerste optie serveerde de gokspam en gaf de aanvaller een manier om in te loggen door een parameter aan een URL te plakken. De tweede deed hetzelfde met een andere parameter, en stal daarnaast inloggegevens van iedereen die inlogde.
Er was geen vreemd beheerdersaccount aangemaakt. Dat is precies waarom niemand iets doorhad. De aanvaller had er geen nodig.
Waarom het maanden onzichtbaar bleef
De site draaide op een sterk verouderde stack. Op het moment dat ik erin kwam stonden er 39 updates open. WordPress zelf liep meer dan een jaar achter. Tussen die openstaande updates zat minstens een plugin met een bekend beveiligingslek.
Daar kwam iets bij wat ik vaker zie: op deze site draaiden twee paginabouwers tegelijk. Elk daarvan sleept zijn eigen code, eigen updates en eigen kwetsbaarheden mee. Twee bouwers op een site is niet alleen traag, het is ook twee keer zoveel oppervlak waar iets mis kan gaan.
En updaten werd daardoor eng. Dat is het echte mechanisme. Iemand durft niet meer bij te werken omdat de site kwetsbaar in elkaar zit, en juist daardoor wordt de site kwetsbaar.
De opruiming, in volgorde
Ik werk hierbij altijd in dezelfde volgorde, en de eerste stap is de belangrijkste.
Eerst een verse back-up. Database en bestanden, in dit geval samen ruim 260 MB, weggeschreven voordat ik iets aanraakte. Je maakt een back-up van een besmette site niet om hem terug te zetten, maar om te kunnen terugkijken als je later iets mist.
Daarna pas opruimen. De drie eval-regels eruit. Beide database-opties eruit. Er stond ook nog een los PHP-bestand tussen de geuploade afbeeldingen, met een naam van acht willekeurige tekens. Die map hoort alleen plaatjes te bevatten, dus alles wat daar op .php eindigt is per definitie fout.
Toen de sleutels. WordPress gebruikt zogeheten salts om sessies te ondertekenen. Die heb ik vernieuwd, zodat elke sessie die de aanvaller nog had ongeldig werd. Wachtwoorden opnieuw gezet.
Toen pas controleren. Cache leeg, homepage opvragen, tellen: nul spamregels, nul fouten, gewoon een 200.
Wat ik niet kon bewijzen
De drie thema-bestanden waren geschreven op 11 april, om 10:54:06. Alle drie op dezelfde seconde, dus geautomatiseerd.
Alleen: de serverlogboeken van die dag waren er niet meer. Weggerouleerd, met lege bestanden van 20 bytes op de plek waar ze hadden moeten staan. De activiteitenlogger in WordPress ging 60 dagen terug, en april lag daarbuiten.
Dus ik kan zeggen wat er is gebeurd en wanneer. Ik kan niet bewijzen langs welke deur ze naar binnen kwamen. Op basis van de verouderde stack is een lek in een plugin of thema het meest waarschijnlijk, en het stelen van inloggegevens was de buit, niet de ingang.
Dat is een les op zichzelf. Hoe langer je wacht, hoe minder er te achterhalen valt. Na twee maanden is het spoor koud.
En daarna bijwerken, met een test eromheen
Opruimen is de helft. Een schone site met 39 openstaande updates is over een maand weer besmet. Daarom is updates bijhouden geen bijzaak maar de kern van beveiliging, en de basis van goed onderhoud.
Voor ik iets bijwerkte heb ik een nulmeting gedaan: de homepage, de overzichtspagina met het filter, het contactformulier en het inschrijfformulier, allemaal handmatig doorlopen en vastgelegd. Daarna 32 plugins bijgewerkt, plus WordPress zelf naar de nieuwste versie. Daarna exact dezelfde test opnieuw.
Twee dingen heb ik bewust laten staan. De gratis versie van een paginabouwer kon niet mee, want die zou niet meer overeenkomen met de betaalde versie en dan breekt de site. Hetzelfde gold voor de plugin die het filter draait. Dat zijn geen dingen die je op vrijdagmiddag even doorduwt.
Van 39 openstaande updates naar 6, waarvan de rest wacht op een licentie.
Wat ik je zou aanraden
Vier dingen, op volgorde van hoeveel ze schelen.
Werk bij, en zorg dat je durft bij te werken. Dat tweede is het punt. Als je bang bent dat je site breekt, is de site het probleem, niet de update.
Gooi weg wat je niet gebruikt. Elk thema en elke plugin die geinstalleerd staat is code die uitgevoerd kan worden, ook als hij uit staat. Op deze site zat de achterdeur onder andere in een standaardthema dat niemand gebruikte.
Kies een paginabouwer. Niet twee.
Zorg dat je terug kunt kijken. Back-ups die verder teruggaan dan een paar dagen, en logboeken die langer bewaard blijven dan 60 dagen. Op het moment dat je ze nodig hebt kun je ze niet meer aanzetten. Meer hierover staat in mijn uitleg over WordPress beveiligen.
Denk je dat je site besmet is?
Een paar signalen die je zelf kunt controleren: vreemde links onderaan je pagina’s, bezoekers die klagen dat ze doorgestuurd worden, of Google die je site in de zoekresultaten markeert. Zoek je site ook eens op in een incognitovenster, want sommige spam wordt bewust verborgen voor ingelogde beheerders.
Kom je er niet uit, stuur me een bericht. Ik kijk een uur gratis mee en zeg eerlijk wat ik zie.

