Een besmette WordPress-site opschonen na wp2shell

Is een site via wp2shell (CVE-2026-63030) overgenomen, dan is bijwerken niet genoeg. De aanvaller heeft op meerdere plekken tegelijk een terugweg ingebouwd, en zolang er één achterblijft is de site binnen een dag opnieuw besmet.


Dit artikel loopt die plekken langs in de volgorde waarin je ze moet aanpakken. Je doet vrijwel alles vanuit het WordPress-dashboard en de bestandsbeheerder in cPanel. Je hebt geen Terminal nodig, behalve voor één optionele controle helemaal aan het eind.


Ga hier vanuit één principe: alles wat je niet kunt verklaren, is verdacht tot je het tegendeel hebt vastgesteld.


Voordat je begint

Werk de site nog niet bij. Zolang de backdoor er in zit, sluit je met een update alleen de ingang waarmee de aanvaller binnenkwam, terwijl hij via zijn eigen weg gewoon terug kan. Bijwerken is stap 7, niet stap 1.


Zet de site niet meteen offline. Een site die uit de lucht gaat, zorgt vooral voor onrust bij je klant en verandert niets aan de besmetting. Uitzondering: verstuurt de site actief spam of staan er klantgegevens open, dan is offline halen wel de juiste eerste stap.


Trek er een aaneengesloten blok tijd voor uit. Je moet het in één keer volledig doen, want een half opgeschoonde site is lastiger te beoordelen dan een besmette site: de sporen zijn dan weg, maar de backdoor niet.


De bestandsbeheerder openen

Een paar stappen doe je in de bestanden van de site. Zo kom je daar:

  1. Log in op cPanel.
  2. Klik onder Bestanden op Bestandsbeheer.
  3. Klik rechtsboven op Instellingen en zet Verborgen bestanden weergeven aan. Zonder deze instelling zie je .htaccess niet staan, en dat is een van de bestanden die je moet controleren.
  4. Ga naar de map van de site. Voor je hoofddomein is dat public_html. Voor een addon-domein of subdomein is dat de map die je bij het aanmaken hebt opgegeven.

Je bent op de goede plek als je daar wp-config.php, wp-content en wp-admin ziet staan.


Stap 1: kijk of er meer sites in het account staan

Een aanvaller die één site in een account overneemt, komt in veel gevallen bij de andere sites in datzelfde account. Ze staan onder dezelfde gebruiker op dezelfde server. Schoon je er één op, dan is die binnen een dag opnieuw besmet vanuit de buurman.


Ga in cPanel naar Domeinen en noteer alle domeinen en subdomeinen in dit account. Kijk per stuk of er WordPress op draait, en behandel elke installatie apart en volledig.


Let vooral op oude installaties in een submap, bijvoorbeeld een oude site onder /oud of een testomgeving onder /staging. Die worden zelden bijgewerkt en het vaakst vergeten.


Stap 2: onbekende beheerders opsporen

Dit is meestal het eerste dat de aanvaller heeft aangemaakt, en de datum ervan vertelt je wanneer de site is overgenomen.

  1. Ga in WordPress naar Gebruikers.
  2. Klik boven de lijst op Beheerder om alleen beheerders te zien.
  3. Zet de lijst op datum door op de kolom Geregistreerd te klikken. Zie je die kolom niet, klik dan rechtsboven op Scherminstellingen en zet hem aan.

Let op accounts met wpsvc_, wp2_ of w2s_ als begin van de naam, op namen als admin1, support of wpadmin die niemand kan verklaren, op willekeurige lettercombinaties, en op e-mailadressen op domeinen die niets met het project te maken hebben. Kijk vooral naar de registratiedatum: een beheerder die op een willekeurige dinsdagnacht is aangemaakt, is er niet door een collega bij gezet.


Noteer die datum. Die heb je in stap 6 nodig.


Verwijder het account via verwijderen. WordPress vraagt dan wat er met de berichten van dat account moet gebeuren: kies Alle inhoud toewijzen aan en wijs ze toe aan een bestaand account. Kies hier niet voor verwijderen, anders raak je mogelijk echte pagina's kwijt.


Loop daarna de rest van de gebruikerslijst na. Het komt voor dat een bestaand abonnee-account stilletjes beheerder is gemaakt, wat minder opvalt dan een nieuw account.


Stap 3: PHP-bestanden in de uploadsmap

In wp-content/uploads horen geen PHP-bestanden. Het is een map die van buitenaf te benaderen is, en dat is precies waarom een webshell daar terechtkomt.


  1. Ga in de bestandsbeheerder naar wp-content/uploads.
  2. Typ in het zoekveld bovenin .php en zet de zoekopdracht op deze map.
  3. Bekijk elk resultaat.

Eén uitzondering die je legitiem tegenkomt: WPML zet PHP-bestanden in zijn twig-cache. Die horen daar. Al het andere is verdacht en mag weg.


Doe daarna hetzelfde in wp-content/cache als die map bestaat.


Krijg je bij het verwijderen een foutmelding over rechten, probeer dan niet zelf de rechten aan te passen. Stuur ons het volledige pad van het bestand, dan halen wij het weg. Er is namelijk een manier om een bestand vast te zetten die je vanuit je eigen account niet kunt opheffen.


Stap 4: mu-plugins, drop-ins en nep-plugins

Dit is de plek waar de hardnekkigste persistentie zit, en de plek die het vaakst wordt overgeslagen.


Kijk eerst of de map wp-content/mu-plugins bestaat. Bestanden in die map worden bij elke pagina-aanroep geladen, staan niet in je pluginoverzicht en kun je in het dashboard niet uitschakelen. In een standaardinstallatie is die map er niet. Staat er iets in dat je niet zelf hebt neergezet, dan is dat vrijwel zeker onderdeel van de besmetting.


Kijk daarna in wp-content zelf of daar losse PHP-bestanden staan, zoals object-cache.php of advanced-cache.php. Dat heten drop-ins en WordPress laadt ze automatisch. Ze horen er alleen te staan als een plugin ze heeft neergezet en je die plugin kunt aanwijzen. Gebruik je bijvoorbeeld geen cacheplugin, dan hoort er geen cachebestand te staan.


Ga tot slot in WordPress naar Plugins en loop de hele lijst door, ook de inactieve. Verdacht zijn:


  • plugins met een reeks willekeurige letters en cijfers achter de naam, dus iets als seo-tools-a3f91c
  • plugins die je niet kent en die niemand geïnstalleerd heeft
  • plugins waarbij als auteur "WordPress.org Community" staat, want dat is geen bestaande auteur

Stap 5: wp-config.php en .htaccess

Deze twee bestanden zijn geliefd bij aanvallers omdat ze bij elk bezoek worden uitgevoerd en zelden worden gelezen.


Open wp-config.php in de bestandsbeheerder via Bewerken en lees hem helemaal door, tot onderaan. Je zoekt naar regels die er niet horen: een include of require die naar een ander bestand op de server verwijst, een regel met auto_prepend_file, of een stuk code met base64_decode of eval erin. Dat laatste staat vaak op één hele lange regel helemaal onderaan, voorbij het punt waarop je normaal stopt met scrollen.


Doe daarna hetzelfde met .htaccess. Kijk niet alleen naar die in de hoofdmap, maar ook naar .htaccess-bestanden in submappen zoals wp-content en uploads. Je zoekt naar regels die bezoekers doorsturen naar een andere website, en naar regels die PHP laten uitvoeren in mappen waar dat niet hoort.


Een standaard .htaccess van WordPress is kort: een blok tussen # BEGIN WordPress en # END WordPress. Staat er buiten dat blok iets dat je niet kunt verklaren, en heb je geen cacheplugin of redirectplugin die dat erin heeft gezet, dan is dat verdacht.


Weet je niet zeker of een regel er hoort? Verwijder hem dan niet meteen, maar sla eerst een kopie van het bestand op en stuur ons de inhoud. Een verkeerd weggehaalde regel kan de site onbereikbaar maken.


Stap 6: kijk naar het tijdstip

Je weet uit stap 2 ongeveer wanneer de site is overgenomen. Bestanden die rond dat moment zijn gewijzigd, zijn vaak wat je in de vorige stappen hebt gemist.


  1. Ga in de bestandsbeheerder naar de hoofdmap van de site.
  2. Klik op de kolomkop Laatst gewijzigd om te sorteren op datum, met de nieuwste bovenaan.
  3. Loop de bestanden na die rond de datum uit stap 2 zijn gewijzigd.

Doe dit ook in wp-content en in wp-includes. Elk PHP-bestand dat in dat venster is gewijzigd zonder dat er op dat moment een update of een aanpassing liep, verdient een blik.


Ga daarnaast in cPanel naar Geplande taken en kijk of daar taken staan die je niet herkent. Een taak die op vaste tijden een onbekend bestand aanroept, is een manier om de besmetting terug te zetten nadat jij hem hebt opgeruimd.


Stap 7: WordPress opnieuw neerzetten en bijwerken

Nu pas ga je bijwerken. Je zet eerst de WordPress-bestanden zelf opnieuw neer, zodat aanpassingen in de core worden overschreven.


  1. Ga naar Dashboard > Updates.
  2. Klik op Nu opnieuw installeren. Deze knop staat er ook als je al op de nieuwste versie zit. Hij vervangt alleen de WordPress-bestanden zelf en laat je thema's, plugins, uploads en database met rust.
  3. Werk daarna WordPress bij naar 7.0.3 of hoger als dat nog niet gebeurd is.
  4. Werk al je plugins bij, en daarna je thema's.

Kom je bij een plugin een update tegen die niet doorgaat omdat de plugin niet meer bestaat of niet meer wordt onderhouden, verwijder hem dan of vervang hem. Een plugin die geen updates meer krijgt, is de volgende ingang.


Stap 8: alle wachtwoorden en sleutels vervangen

De aanvaller heeft toegang gehad tot je bestanden en je database. Ga er dus vanuit dat elk wachtwoord en elke sleutel op die site bekend is.


Beheerderswachtwoorden. Ga in WordPress naar Gebruikers, open elk beheerdersaccount, klik op Nieuw wachtwoord instellen en sla op. Doe dit voor alle beheerders, niet alleen voor jezelf.


Beveiligingssleutels. Dit zijn de zogenoemde salts in wp-config.php. Door ze te vervangen worden alle openstaande sessies ongeldig, ook die van de aanvaller.


  1. Ga naar https://api.wordpress.org/secret-key/1.1/salt/ in je browser. Je krijgt daar acht regels code te zien, elke keer opnieuw gegenereerd.
  2. Open wp-config.php in de bestandsbeheerder.
  3. Zoek het bestaande blok met acht regels die beginnen met define('AUTH_KEY' en verder.
  4. Vervang die acht regels door de acht regels van de website hierboven en sla op.

Je wordt daarna uitgelogd uit WordPress. Dat hoort zo.


Databasewachtwoord. Ga in cPanel naar MySQL-databases, zoek de gebruiker die bij deze site hoort en stel een nieuw wachtwoord in. Zet datzelfde wachtwoord daarna in wp-config.php bij DB_PASSWORD. Doe deze twee stappen kort na elkaar: tussen het wijzigen en het aanpassen van wp-config.php is de site niet bereikbaar.


En verder. Vergeet het cPanel-wachtwoord zelf niet, eventuele FTP-accounts, en API-sleutels van betaalproviders of koppelingen die in de site staan.


Stap 9: controleren of het echt schoon is

Loop dit lijstje af voordat je de site vrijgeeft.


  1. Geen onbekende beheerders meer, en geen bestaand account met een rol die het niet hoort te hebben.
  2. Geen PHP-bestanden in uploads en cache.
  3. mu-plugins leeg of verwijderd, en geen onverklaarbare bestanden los in wp-content.
  4. wp-config.php en .htaccess gecontroleerd en schoon.
  5. WordPress opnieuw neergezet, versie 7.0.3 of hoger, plugins en thema's bijgewerkt.
  6. Beheerderswachtwoorden, beveiligingssleutels en databasewachtwoord vervangen.

Open daarna de site in een privévenster en controleer de homepage, een subpagina en het dashboard. Bekijk ook een pagina via een zoekresultaat in Google, want sommige besmettingen sturen alleen bezoekers door die via een zoekmachine binnenkomen.


Houd de site een week in de gaten. Duikt er opnieuw een bestand of een account op, dan is er nog een terugweg blijven staan. Doorzoeken heeft dan meer zin dan nog een keer hetzelfde opschonen.


Optioneel: de laatste controle via de Terminal

Er is één controle die je niet vanuit WordPress kunt doen: elk bestand van de installatie vergelijken met de officiële versie van wordpress.org. Die controle is niet verplicht, maar geeft wel de meeste zekerheid, zeker bij een webshop of een site met klantgegevens.


Zo kom je bij de Terminal:

  1. Log in op cPanel.
  2. Klik onder Geavanceerd op Terminal. Verschijnt er een waarschuwing, bevestig die dan.
  3. Ga naar de map van de site met cd public_html en druk op Enter. Staat de site in een andere map, gebruik dan die naam.

Voer daarna deze regel uit:

wp core verify-checksums

Krijg je geen meldingen terug, dan zijn alle WordPress-bestanden identiek aan de officiële versie. Krijg je wel meldingen over gewijzigde of onbekende bestanden, laat het ons dan weten met de uitvoer erbij, dan kijken we mee.


Zie je Terminal niet staan in cPanel, dan staat die functie voor je account uit. Stuur ons een bericht, dan zetten we hem aan.


Als je er niet uitkomt

Opschonen kost tijd en je moet het in één keer volledig doen. Kom je er niet uit, of wil je het zeker weten omdat er klantgegevens of een webshop in het spel zijn, dan kunnen wij het overnemen voor 49 euro per website.


We verwijderen de malware, backdoors en ongewenste accounts, controleren de WordPress-bestanden op afwijkingen, vervangen de inloggegevens en leveren een rapportage van wat we hebben gevonden en wanneer het is gebeurd. Daarop geldt 100 dagen garantie: raakt de site in die periode opnieuw besmet, dan ruimen we kosteloos opnieuw op.


Stuur ons een bericht met de betreffende domeinen, dan pakken we het op.

Heeft dit artikel je goed geholpen? Dank voor je feedback! Er is een probleem opgetreden bij het verzenden. Probeer opnieuw.