WordPress brengt patch uit voor wp2shell-lek dat aanvallers code laat uitvoeren
Een beveiligingsbedrijf heeft kwetsbaarheden ontdekt die het mogelijk maken om op afstand code uit te voeren op WordPress-sites. De proof-of-concept voor dit 'wp2shell'-lek staat online. WordPress heeft de beveiligingslekken gedicht.
De rce-lek bevindt zich in de WordPress-kern, ontdekte Searchlight Cyber. Anders dan bij de meeste WordPress-kwetsbaarheden zijn daardoor ook sites zonder plug-ins kwetsbaar. De rce-aanval is mogelijk in WordPress-versies vanaf 6.9.0. Hoewel het beveiligingsbedrijf door de ernst van de kwetsbaarheid geen technische informatie deelt, staan er al meerdere proof-of-concepts op GitHub. Die beschrijven in detail hoe aanvallers de kwetsbaarheid kunnen uitbuiten.
De aanval maakt gebruik van twee kwetsbaarheden, CVE-2026-60137 en CVE-2026-63030. De eerste maakt een SQL-injectie in WP_Query mogelijk. Anonieme aanvallers kunnen die combineren met de tweede kwetsbaarheid in de REST-api. Zo kunnen ze de authenticatie omzeilen en code uitvoeren. Het lek wordt actief uitgebuit, zeggen beveiligingsbedrijven tegen SecurityWeek.
WordPress heeft de kwetsbaarheden gepatcht in versies 6.9.5 en 7.0.2. Door de ernst van het lek werkt WordPress sites met de getroffen versies automatisch bij. Sites die automatische updates hebben uitgeschakeld, moeten echter nog steeds handmatig updaten. Ook WordPress-versies 6.8.0 tot en met 6.8.5 zijn kwetsbaar voor de onderliggende SQL-injectie. Deze versies bevatten de kwetsbaarheid in de REST-api niet. WordPress heeft de SQL-injectie in versie 6.8.6 gepatcht.
:strip_exif()/i/2008162052.jpeg?f=imagenormal)
Lees meer
Reacties (36)
Dit is geen los beveiligingslek, maar een exploitketen die twee kwetsbaarheden combineert (CVE-2026-63030, aanwezig in WordPress 6.9 t/m 7.0.1). Een unauthenticated SQL-injectie in WP_Query (via de author_exclude/author__not_in-parameter) wordt gecombineerd met een fout in het REST API batch-endpoint (/batch/v1). Door een speciaal gevormd batchverzoek raakt de interne afhandeling van requests uit sync, waardoor een request wel volgens het ene endpoint wordt gevalideerd, maar uiteindelijk door een ander (publiek) endpoint wordt uitgevoerd.
Een belangrijk detail dat in veel berichtgeving ontbreekt, is dat de REST-permission checks zelf niet worden omzeild. Als dat wel zo was, zou dit een directe one-shot RCE zijn geweest.
Een andere belangrijke nuance is dat de SQL-injectie zelf read-only is. De injectie bevindt zich in een SELECT-context en WordPress staat geen stacked queries toe, waardoor een aanvaller niet rechtstreeks INSERT- of UPDATE-queries kan uitvoeren. In plaats daarvan gebruikt de publieke "wp2shell"-PoC een UNION SELECT om vervalste database-rijen in het queryresultaat te injecteren. Vervolgens verwerkt WordPress die gegevens zelf via bestaande functionaliteit (zoals de oEmbed-cache en een customize_changeset), waardoor uiteindelijk een administratoraccount wordt aangemaakt. De schrijfacties worden dus door WordPress zelf uitgevoerd; de SQL-injectie manipuleert alleen de data die WordPress denkt uit de database te lezen. Nadat een administratoraccount is verkregen, wordt een plugin met webshell geïnstalleerd om code op de server uit te voeren.
De PoC is inmiddels openbaar beschikbaar en de eerste exploitatiepogingen worden al waargenomen. Daarom is het verstandig om zo snel mogelijk te updaten naar WordPress 7.0.2 (of de beveiligingsupdates voor de 6.8- en 6.9-reeksen).
[Reactie gewijzigd door Stroopwafels op 20 juli 2026 10:42]
Ik zou in ieder geval het volgende controleren:
- Nieuwe of recent aangemaakte administratoraccounts.
- Onbekende of recent geïnstalleerde plugins.
- Onbekende .php-bestanden in wp-content/uploads/ (daar horen normaal gesproken geen PHP-bestanden te staan, afgezien van bijvoorbeeld een index.php of bestanden van sommige cacheplugins).
- Onbekende .php-bestanden in wp-content/mu-plugins/.
Daarnaast is het ook de moeite waard om je access logs te controleren. Als je daar verzoeken naar /batch/v1 ziet, zeker in combinatie met vreemde of malformed requests, kan dat een aanwijzing zijn dat iemand heeft geprobeerd deze kwetsbaarheid te exploiten op je site.
Tuurlijk kan je de logs an sich blokkeren maar dat lost het probleem niet op dat er mensen zijn die dat eindeloos blijven proberen, is het niet bij jouw is het bij een ander. Gigantische verspilling van resources, sites hebben rustig 3 tot 4x zo verkeer dan daadwerkelijke bezoekersverkeer (ook crawlers/bots/ai spelen daar een grote rol daarin).
En ja ik gebruik fail2ban, maar dan nog hebben ze x aantal pogingen voordat ze gebanned worden, en je moet enorm voorzichtig zijn voor false positives, want legitieme bezoekers wil je natuurlijk nooit blokkeren. Daarnaast moet je steeds weer nieuwe dingen blokkeren en bijwerken/bijhouden. Kost ook gewoon tijd en dus geld.
[Reactie gewijzigd door watercoolertje op 20 juli 2026 09:37]
Hoe nuttig en effectief is dat nog in een wereld met dynamische IP-adressen?
Je bant een IP-adres, de dader krijgt een nieuw IP-adres, en een onschuldig iemand kan je website niet bezoeken omdat die dat IP-adres gekregen heeft.
Wat heeft een West Taiwanees te zoeken op mijn website? Helemaal niets toch, die komt niet eens voorbij hun grote firewall.
En ik heb geen problemen met een Zuid Koreaan, maar die kan ook geen NL lezen dus jammer dan.
Is dat misschien niet netjes? Vast.
Blokkeer je dan misschien een half PPB die wel legit waren uit die landen? Vast.
Zie het maar als schijnveiligheid. Ook denk ik niet dat ze voor simpele scans hun "achterdehand westerse IPs" gebruiken. Laatst probeerde Kim Jong Un ook nog even mijn site te bezoeken.... Bijzonder.
Maar goed punt, inderdaad best een praktische manier van aanvliegen.
Hiernaast heb ik in mijn .htaccess ook nog een "noodknop" zitten. Indien er ellende aan de gang is en ik kan nog wel via SFTP erbij dan kan ik met 1 getal te wijzigen de toegang beperken tot NL / BE / DE / GB voor de gebruikers en alles wat een inlog vereist tot alleen mijn eigen IP. Gelukkig nog nooit gebruik van hoeven maken maar het is wel fijn om het alvast in de htaccess te hebben staan - voor het geval dat.
edit: bovendien komt 99.9% van het gedonder over IPv4 binnen. Met schaarste enzovoorts wordt het wel moeilijker om als "bad actor" lukraak van adres te wijzigen
[Reactie gewijzigd door SampleUser op 20 juli 2026 12:51]
Zie bijvoorbeeld https://krebsonsecurity.com/tag/residential-proxy/
Als het een ISP is waarvan ik weet dat ze goed abusemeldingen afhandelen (dus ook niet geoutsourced aan een of ander AI bedrijf) dan krijg ik een conceptmelding in mijn mailbox die ik direct doorzet.
Zolang er "failed states" zijn die dit soort gedrag toelaten/tolereren of tenminste een oog dichtdoen hiervoor zal deze ruis bestaan.
Overigens komt WordPress mij sowieso enorm de keel uit als het gaat om kwetsbaarheden in de core of in/door zwakke plugins, die veel schade veroorzaken.
[Reactie gewijzigd door Klauwhamer op 20 juli 2026 09:34]
Op Tweakers zag ik de eerste scans op 17 juli langs komen en totaal zijn er sindsdien 404 requests gedaan op /wp-json/batch/v1 (en die kregen allemaal een 403)
Als dat mogelijk gaat zijn gaat níemand meer bijdragen aan open source en dan ligt letterlijk de wereldeconomie plat.
Zitten ook mensen tussen die gewoon op bugbounties aan het jagen zijn en dus in principe goede bedoelingen hebben.
Die updates heb ik normaal op handmatig staan bij de grootste websites, maar in dit geval leken ze geforceerd te worden?
Ik heb overal define( 'WP_AUTO_UPDATE_CORE', 'minor'); in wp-config.php
Gek dat ze geen mailing list hebben van allen geregistreerde admins.
Hoe zou jij die lap code willen schrijven om tot dezelfde oplossing te komen?
In dit concrete voorbeeld wordt een ' NOT IN' gebruikt waarbij er wat bijkomende uitdagingen bijkomen, maar ook dan is het nog steeds mogelijk om een prepared statement te gebruiken (hoewel het wel wat lastiger wordt). [edit]De nu gebruikte oplossing om de user input eerst te casten naar integers is natuurlijk in dit concrete geval voldoende en zoals ik al aangaf is een [NOT] IN statement best wel bewerkelijk/lastig om te realiseren in een Prepared Statement...[/edit]
Natuurlijk kun je ook zelf aan validatie doen (hetgeen WordPress ook doet - anders zouden er veel meer issues zijn), maar zo veel mogelijk aan reeds opgebouwde functionaliteit van het framework uitbesteden is vaak een betere optie.
Nu is WordPress al best oud en had PHP in het verleden niet dezelfde goede bescherming als tegenwordig, dat laat onverlet dat het een goed idee zou zijn dat men bij WordPress eens zou gaan werken aan het vervangen van legacy oplossingen...
[Reactie gewijzigd door Little Penguin op 20 juli 2026 15:13]
$arr = ['Amsterdam','Breda','Maastricht'];
$in = str_repeat('?,', count($arr) - 1) . '?';
$sql = "SELECT id, name FROM accounts WHERE city IN ($in)";
$stmt = $mysqli->prepare($sql);
$types = str_repeat('s', count($arr));
$stmt->bind_param($types, ...$arr);
$stmt->execute();
bind_param is er vanaf php 5 als je mysqli gebruikt, voor postgresql kun je overstappen naar PDO, dat is ook uit ongeveer dezelfde tijd volgens mij. PDO heeft ook bind_param en bind_value, er zit wat verschil tussen hoe bind_param werkt op mysqli met PDO (dat ook het mysql/mariadb protocol aankan), als je iets nieuws doet even zelf uitzoeken aub, ik gebruik te weinig php tegenwoordig.
WordPress maakt gebruik van PHP...
[Reactie gewijzigd door HyperioN op 20 juli 2026 09:35]
Om te kunnen reageren moet je ingelogd zijn
/u/500314/crop641c5e830069a_cropped.png?f=community)
/u/468514/crop67a52a3ca0480_cropped.png?f=community)
:strip_icc():strip_exif()/u/249917/jaapschaap.jpg?f=community)
/u/8/oog3.png?f=community)
:strip_icc():strip_exif()/u/83500/lfsmall.jpg?f=community)
:strip_icc():strip_exif()/u/1434986/crop649350276f23c_cropped.jpg?f=community)
:strip_icc():strip_exif()/u/176404/crop5d8a18233281d_cropped.jpeg?f=community)
/u/268967/crop5e8a0fac1d139.png?f=community)
/u/466919/Tweakers_p9_v2.png?f=community)
/u/954149/crop5984ccfcadb91.png?f=community)