WordPress backdoor herkennen is een vaardigheid die je hoopt nooit nodig te hebben, maar als je 100+ WordPress-sites onderhoudt, zoals ik, kom je ze tegen. De goede boodschap: een gehackte site is vervelend, geen ramp, mits je weet waar je moet kijken. In dit artikel loop ik door de zeven plekken waar backdoors zich verstoppen, welke code-patronen ze verraden, en hoe je veilig opruimt zonder dat je morgen weer dezelfde scan-mail krijgt.
Dit is een post-incident artikel. Geen tijd voor paniek, geen tijd voor overhaaste delete-acties. Wel tijd voor een methodische ronde door je site.

Wat een backdoor is en waarom hij vaak terugkomt na een schoonmaak
Een backdoor is een stukje code dat een aanvaller op je site achterlaat om later opnieuw binnen te komen, zonder dat hij weer hoeft in te breken. Het is niet de hack zelf, maar de verzekering tegen het verlies van toegang.
Daarom komt een hack zo vaak terug na een “snelle schoonmaak”: de scanner heeft de zichtbare malware verwijderd, maar de backdoor staat nog ergens. Twee weken later komt dezelfde aanvaller terug, herstelt zijn malware en je krijgt opnieuw een melding van je hoster.
Een echte schoonmaak begint dus met de backdoor opsporen, niet met de zichtbare schade. Wat ik in mijn praktijk zie: plugin-scans missen 20 tot 30% van de backdoors die ik handmatig vind. Niet omdat de plugins slecht zijn, maar omdat aanvallers hun code constant aanpassen om signature-detectie te omzeilen.
WordPress backdoor herkennen: 7 plekken waar ze zich verstoppen
Backdoors zitten zelden op willekeurige plekken. Ze zitten op plekken die automatisch worden geladen, of waar PHP-execution mogelijk is zonder dat het opvalt. De zeven standaardlocaties:
/wp-content/mu-plugins/: must-use plugins laden automatisch, verschijnen niet in de plugin-lijst. Favoriet bij aanvallers./wp-content/plugins/: bestaande plugins met geinjecteerde code, of een nieuwe plugin met een onschuldige naam./wp-content/themes/<theme>/functions.php: een paar extra regels onderaan, vaak voor of na een vrije regel./wp-content/uploads/: PHP-bestanden in /uploads horen er nooit te zijn. Een.phpin een 2023-mapje is bijna altijd raak./.htaccess: soms een rewrite-regel die /uploads/cache.php uitvoert, of een conditional die alleen actief is voor een specifieke user-agent.- WP-core (
wp-includes/,wp-admin/): geinjecteerde code in core-bestanden zoalswp-includes/option.php. Hoort identiek aan de wordpress.org-checksum te zijn. - Database:
wp_options.active_plugins,wp_users.user_meta, of een hiddentransientdie bij elke pageload via een plugin wordt geevalueerd.

Signalen in de code: welke functies en patronen verraden malware
Backdoors gebruiken bijna allemaal een handvol PHP-functies om hun ware doel te verbergen. Een grep op deze functies vangt vaak 70 tot 80% van de bekende backdoors:
grep -rEn "eval\(|base64_decode\(|gzinflate\(|str_rot13\(|assert\(|create_function\(|passthru\(|shell_exec\(" /pad/naar/wp-content/ --include="*.php"Wat je zoekt:
eval(met daarna een variabelebase64_decode((vaak in combinatie met gzinflate)gzinflate(enstr_rot13((obfuscatie)assert(met een variabelepreg_replacemet de/e-modifier (deprecated, alleen door malware gebruikt)create_function((deprecated sinds PHP 7.2)passthru(,shell_exec(,system((direct shell-access)
Plus de patronen rond die functies:
- Lange obfuscated strings (honderden tekens, base64-achtig)
$_REQUESTof$_GETin productie-code zonder validatie- Een PHP-bestand dat met
<?phpen honderden spaties begint, zodat de echte payload buiten beeld blijft in editors
Een legitieme functie kan op deze patronen lijken. WooCommerce gebruikt base64_decode in webhook-handling. Een grep-treffer is een signaal, geen bewijs. Lees de context.
Forensische WordPress-check
Doorloop zeven plekken waar een backdoor kan zitten
Werk rustig en systematisch. De opdrachten hieronder zoeken en vergelijken alleen. Ze verwijderen of wijzigen niets.
Voer opdrachten uit vanuit de hoofdmap van WordPress. Open een plek voor de opdracht en uitleg.
1. wp-content/uploads
Let op PHP-bestanden in een map die normaal vooral media bevat.
find wp-content/uploads -type f -name '*.php' -print
2. Must-use plugins
Bekijk ieder bestand in mu-plugins, ook als het niet in de gewone pluginlijst staat.
find wp-content/mu-plugins -type f -name '*.php' -print
3. Thema-bestanden en functions.php
Let op onverwachte code in het actieve thema en onbekende PHP-bestanden in andere thema’s.
grep -R -nE --include='*.php' 'base64_decode|eval[[:space:]]*\(|gzinflate|str_rot13|assert[[:space:]]*\(' wp-content/themes
4. wp-config.php
Controleer onverwachte includes, lange versleutelde tekst en uitvoerende functies.
grep -nE 'base64_decode|eval[[:space:]]*\(|gzinflate|str_rot13|assert[[:space:]]*\(' wp-config.php
5. Gewijzigde core-bestanden
Vergelijk core-bestanden en bestanden in de hoofdmap met officiële checksums.
wp core verify-checksums --include-root
6. Verdachte cron-events
Let op onbekende hooks, ongebruikelijke namen en events die opvallend vaak terugkomen.
wp cron event list --fields=hook,next_run,recurrence
7. Onbekende admin-gebruikers
Vergelijk beheerders met je eigen administratie. Een onbekend account vraagt onderzoek.
wp user list --fields=ID,user_login,user_email,roles,user_registered
Voortgang
0/7 gecontroleerd
Volgende stap
Begin bij wp-content/uploads.
Zoek onder meer naar base64_decode, eval, gzinflate, str_rot13, assert, create_function en preg_replace met de oude e-modifier.
grep -R -nE --include='*.php' 'base64_decode|eval[[:space:]]*\(|gzinflate|str_rot13|assert[[:space:]]*\(|create_function|preg_replace[[:space:]]*\([^)]*/e' .Controleer WordPress core en plugins die op WordPress.org staan.
wp core verify-checksums --include-root
wp plugin verify-checksums --all --strict- Isoleer. Beperk toegang en voorkom verdere schade.
- Leg bewijs vast. Bewaar logs, bestanden, tijdstippen en screenshots voordat je opruimt.
- Ruim gestructureerd op. Werk op staging of vanuit een gecontroleerde back-up en verander niet alles tegelijk.
- Dicht de ingang. Update kwetsbare software, vervang sleutels en reset relevante wachtwoorden.
- Monitor. Controleer bestanden, logs, gebruikers en uitgaand verkeer na herstel.
Een hulpmiddel. Bij een echte infectie zijn een back-up, staging en zo nodig hulp aan te raden. Vind je niets, dan is de site niet automatisch schoon.
WP-CLI: core en plugins vergelijken met officiele checksums
WP-CLI heeft een ingebouwd commando dat WordPress-core-bestanden vergelijkt met de officiele checksums op wordpress.org. Een paar seconden werk, en je weet of er iets is aangepast.
Core controleren:
wp core verify-checksumsAlle plugins controleren (alleen plugins van wordpress.org):
wp plugin verify-checksums --allBij een afwijking krijg je een lijst met bestanden. Dat is je startpunt. Een afwijking in wp-includes/option.php is alarmerend, een afwijking in een plugin die je zelf hebt aangepast is dat niet (maar wel een herinnering dat je die aanpassing moet documenteren).
Wat checksums niet vangen:
- Nieuwe bestanden die niet in de officiele lijst staan (bv een nieuw
wp-includes/cookie.phpdat er nooit was). - Wijzigingen in betaalde plugins of premium-thema’s (geen wordpress.org checksums).
- Wijzigingen in
wp-config.php,.htaccess(geen onderdeel van core).
Voor die gaten gebruik je WP-CLI’s officiele documentatie en aanvullende handmatige audits.

Server-logs en cronjobs: wat een aanvaller meestal achterlaat
Naast bestanden controleer je drie minder voor de hand liggende plekken.
Access-logs. Zoek requests naar bestanden die je niet kent: /wp-content/uploads/cache.php, /wp-admin/css/log.php, scripts in random-mappen. Een geslaagde 200-response op zo’n URL is bijna altijd raak.
Server-cronjobs. Linux: crontab -l als webserver-user, plus /etc/cron.d/. Een aanvaller kan een cronjob neerzetten die elk uur zijn malware terugplaatst. Dat is precies waarom de schoonmaak een dag later weer ongedaan lijkt te zijn gemaakt.
WordPress-cron. wp cron event list toont alle geplande hooks. Onbekende hooks met een random naam: verdacht. Schakelen via WP-CLI:
wp cron event delete <hook-naam>.user.ini of php.ini in wp-content. Een lokale PHP-configuratie kan auto_prepend_file zetten op een bestand naar keuze van de aanvaller. Dat bestand wordt dan bij elke PHP-request uitgevoerd. Subtiel en gemakkelijk te missen.
Scanners die ik combineer (en waarom ik er nooit één vertrouw)
Drie scanners die ik wisselend inzet:
Wordfence. Scant tegen 44.000 plus malware-signatures. Vangt in mijn ervaring 70-80% van bekende backdoors. Mist nieuwe varianten. Sterk in het detecteren van core- en plugin-modificaties.
Patchstack. Sterker op kwetsbaarheden in de keten (vulnerable plugins met bekende exploits). Minder sterk op directe malware-detectie.
Malcare. Cloud-side scanning, ziet niet alle bestanden op je server. Goed voor een snelle eerste indicatie, niet voor een grondige audit.
Geen enkele scanner is volledig. De handmatige grep, WP-CLI verify-checksums en een blik op de logs vangen wat de scanners missen. In mijn workflow: 1 scanner (Wordfence) voor de bekende dingen, plus handmatig voor de rest.
Wat te doen als je een backdoor vindt: workflow zonder paniek
Een backdoor gevonden. Wat nu? Niet meteen verwijderen.
- Snapshot maken. Volledige backup van bestanden en database voor forensiek. Pas dan ga je aanpassen.
- Backup van vóór de infectie verifieren. Heb je een schone backup van 30 of 60 dagen geleden? Bekijk de inhoud, controleer of de bekende verdachte bestanden er niet inzaten. Een backup die zelf al geinfecteerd is, is geen backup.
- Salts en wachtwoorden roteren. Alle admin-wachtwoorden resetten, alle Application Passwords intrekken. Salts in wp-config.php opnieuw genereren (zie mijn artikel over wp-config.php beveiligen). Alle sessies eindigen via
wp user session destroy --all. - Core herinstalleren.
wp core download --force --skip-content. Dit overschrijft alleen wp-admin en wp-includes met de officiele versie, jouw content blijft. - Plugins en thema’s vervangen vanaf officiele bronnen. Niet “scannen en lossless herstellen”, maar opnieuw uploaden vanuit de officiele zipfile. Premium-plugins: download opnieuw van de leverancier.
- Gebruikers controleren.
wp user listen kijken naar onbekende namen, ongebruikelijke rollen, recente registraties. Onbekende admin gevonden? Verwijderen. - Database-tabellen lezen.
wp_optionsopbase64_decode,gzinflate,eval.wp_users.user_metaop verdachte sessietokens of geinjecteerde meta-keys.
Pas als dit allemaal klaar is, kun je vertrouwen op een schone site. Niet eerder.
Voorkomen: drie maatregelen die de meeste backdoors blokkeren
Drie dingen die ik standaard inzet op klanten waar ik onderhoud doe:
- File-integrity-monitoring. Een dagelijkse hash-check van wp-content. Bij wijzigingen: melding. Plugins zoals Wordfence of een eigen script via een cronjob.
- FTP en SSH beperken. SFTP-toegang alleen voor mijzelf, SSH met key-only authenticatie, geen wachtwoorden. Geen “tijdelijke” FTP-accounts die nooit worden opgeruimd.
- Hardening. Zie wp-config.php beveiligen voor de file-permissions, salts, FILE_EDIT en de Apache- of Nginx-blocks.
Voor de juridische kant na een datalek: een hack is niet automatisch een datalek, maar als persoonsgegevens geraakt zijn, geldt de meldplicht binnen 72 uur bij de Autoriteit Persoonsgegevens (zie mijn datalek-stappenplan). Voor juridische diepgang verwijs ik consequent naar een privacy-advocaat. Lypii geeft daar geen juridisch advies over.
Multi-stack: Dit artikel is WordPress-specifiek (mu-plugins, wp-config, WP-CLI zijn WP-eigen). Voor Laravel ligt de focus op vendor/, storage/, en de scheduled jobs. Voor Statamic op content/ en de control panel. De principes (verwachte locaties, integrity-check, log-analyse) blijven gelijk.
Verbeteren boven herbouwen: een gehackte site herstellen kost minder dan een herbouw, mits je snel handelt. Een gemiddelde forensische check en opruiming is 3-6 uur werk. Buiten kantooruren €95 per uur, ongeplande spoed €105. Meer over WordPress onderhoud en hoe ik herhaling voorkom.
Vermoeden van een hack en geen tijd om dit zelf uit te zoeken? Direct contact en ik kijk vandaag mee.



