<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>CVE-2026-63030 &#8211; abow &#8211; how do you do IT</title>
	<atom:link href="https://abow.info/tag/cve-2026-63030/feed/" rel="self" type="application/rss+xml" />
	<link>https://abow.info</link>
	<description>Alle möglichen Handkniffe, die ich mir so zusammentrage im Berufsalltag</description>
	<lastBuildDate>Mon, 28 Sep 2026 14:50:48 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://abow.info/wp-content/uploads/2026/06/cropped-favicon-512-32x32.png</url>
	<title>CVE-2026-63030 &#8211; abow &#8211; how do you do IT</title>
	<link>https://abow.info</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>WordPress // wp2shell: Wie mein Blog übernommen wurde und wie ich ihn zurückgeholt habe</title>
		<link>https://abow.info/persoenlich/wordpress-wp2shell-wie-mein-blog-uebernommen-wurde-und-wie-ich-ihn-zurueckgeholt-habe/</link>
					<comments>https://abow.info/persoenlich/wordpress-wp2shell-wie-mein-blog-uebernommen-wurde-und-wie-ich-ihn-zurueckgeholt-habe/#respond</comments>
		
		<dc:creator><![CDATA[Andi Bow]]></dc:creator>
		<pubDate>Mon, 05 Oct 2026 14:43:00 +0000</pubDate>
				<category><![CDATA[Hosting]]></category>
		<category><![CDATA[Persönlich]]></category>
		<category><![CDATA[Security]]></category>
		<category><![CDATA[CVE-2026-63030]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Härtung]]></category>
		<category><![CDATA[Incident Response]]></category>
		<category><![CDATA[WordPress]]></category>
		<category><![CDATA[wp2shell]]></category>
		<guid isPermaLink="false">https://abow.info/?p=889</guid>

					<description><![CDATA[Ende September konnte ich mich nicht mehr in mein eigenes WordPress einloggen. Den Grund zeigte die Benutzerliste: 75 Administratoren, 74 davon nicht von mir. Angreifer hatten abow.info über…]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">Ende September konnte ich mich nicht mehr in mein eigenes WordPress einloggen. Den Grund zeigte die Benutzerliste: <strong>75 Administratoren, 74 davon nicht von mir.</strong> Angreifer hatten abow.info über <strong>wp2shell</strong> übernommen, eine Lücke im WordPress-Core, und das zehn Wochen lang, ohne dass ich etwas gemerkt habe. In diesem Beitrag steht, woran du erkennst, ob es dich auch erwischt hat, wie ich aufgeräumt habe und was ich seitdem anders mache.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Ziel</h2>



<ul class="wp-block-list">
<li>Prüfen, ob deine WordPress-Installation verwundbar ist oder schon übernommen wurde</li>



<li>Eine übernommene Seite sauber neu aufbauen, statt einzelne Dateien zu löschen</li>



<li>Die Seite so absichern, dass der nächste Einbruch nicht klappt oder zumindest sofort auffällt</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Hintergrundwissen: Was ist wp2shell?</h2>



<p class="wp-block-paragraph">Am 17. Juli 2026 hat Searchlight Cyber zwei Lücken im WordPress-Core veröffentlicht, die zusammen eine Codeausführung <strong>ohne Login</strong> erlauben. Ein Plugin braucht es dafür nicht, eine Standardinstallation reicht.</p>



<p class="wp-block-paragraph"><strong>CVE-2026-63030</strong> steckt im Batch-Endpunkt der REST-API, erreichbar unter <code>/wp-json/batch/v1</code> und gleichwertig unter <code>/?rest_route=/batch/v1</code>. Über diesen Endpunkt kann ein Client mehrere REST-Anfragen in einem Aufruf bündeln. Eine präparierte Bündelung bringt WordPress dazu, eine Teilanfrage im falschen Sicherheitskontext auszuführen, die Berechtigungsprüfung fällt weg.</p>



<p class="wp-block-paragraph"><strong>CVE-2026-60137</strong> ist eine SQL-Injection im Parameter <code>author__not_in</code> von <code>WP_Query</code>. Hinter dem ausgehebelten Batch-Endpunkt ist sie ohne Anmeldung erreichbar. Die öffentlichen Exploit-Tools legen damit einen Administrator an und installieren darüber eine Webshell.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>WordPress-Version</th><th>Betroffen</th><th>Fix</th></tr></thead><tbody><tr><td>6.8.0–6.8.5</td><td>nur die SQL-Injection, keine vollständige Kette (die Batch-Route kam erst mit 6.9)</td><td>6.8.6</td></tr><tr><td>6.9.0–6.9.4</td><td>vollständige Kette, Übernahme ohne Login</td><td>6.9.5</td></tr><tr><td>7.0.0–7.0.1</td><td>vollständige Kette, Übernahme ohne Login</td><td>7.0.2</td></tr></tbody></table></figure>



<p class="wp-block-paragraph">Die Patches kamen am selben Tag wie die Veröffentlichung. Die US-Behörde CISA hat die Lücke am 21. Juli in ihren Katalog aktiv ausgenutzter Schwachstellen aufgenommen, am 22. Juli tauchte funktionierender Exploit-Code öffentlich auf. Auf meiner Seite entstand der erste fremde Administrator am <strong>19. Juli</strong>, also schon vorher.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">So lief es bei mir</h2>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="444" src="https://abow.info/wp-content/uploads/2026/09/inlay_wp2shell_zeitleiste-1024x444.png" alt="" class="wp-image-891" srcset="https://abow.info/wp-content/uploads/2026/09/inlay_wp2shell_zeitleiste-1024x444.png 1024w, https://abow.info/wp-content/uploads/2026/09/inlay_wp2shell_zeitleiste-300x130.png 300w, https://abow.info/wp-content/uploads/2026/09/inlay_wp2shell_zeitleiste-766x332.png 766w, https://abow.info/wp-content/uploads/2026/09/inlay_wp2shell_zeitleiste.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p class="wp-block-paragraph">Im Juni bin ich von Strato auf einen VPS mit Docker umgezogen (<a href="https://abow.info/persoenlich/wordpress-umzug-von-strato-auf-einen-hostinger-vps-docker-traefik/">Umzug im Detail</a>). Die Seite lief auf WordPress 7.0. Den Fix vom 17. Juli hat sie nie bekommen. Die wahrscheinlichste Ursache: Ich hatte die Dateien aus dem Strato-Backup per SFTP als <code>root</code> hochgeladen. WordPress läuft im Container als <code>www-data</code> und durfte seine eigenen Core-Dateien damit nicht überschreiben. Plugins haben sich weiter aktualisiert, deshalb fiel es mir nicht auf. Eine Fehlermail hätte ich auch nicht bekommen, denn Mailversand war auf dem neuen Server noch nicht eingerichtet.</p>



<p class="wp-block-paragraph">Ab dem 19. Juli kamen dann ein bis drei neue Administratoren pro Tag dazu, mit wechselnden Namensmustern: <code>wp2_…</code>, <code>w2s_…</code>, <code>wpsvc_…</code>, <code>wordpress_…</code>, dazu erfundene Adressen auf <code>@abow.info</code> und Konten wie <code>adm.abows0367c6</code>, die meinem eigenen Namen ähneln. Das waren nicht ein Angreifer, sondern viele automatisierte Scanner mit denselben öffentlichen Werkzeugen.</p>



<p class="wp-block-paragraph">Was sie hinterlassen haben:</p>



<ul class="wp-block-list">
<li>zwei Webshells in der <code>functions.php</code> meines eigenen Themes (26. Juli), die bei jedem Seitenaufruf mitladen</li>



<li>Backdoor-Plugins mit Namen wie <code>wp2shell_624cd70a</code> und einen Ordner mit Zufallsnamen</li>



<li>fremde Theme-Ordner (<code>twk-…</code>) und Must-Use-Plugins mit Base64-Payload, die automatisch laden und in keiner Plugin-Liste auftauchen</li>



<li>PHP-Dateien im <code>uploads</code>-Ordner</li>



<li>167 Datensätze des Exploits in der Datenbank, darunter neun veröffentlichte Beiträge mit dem Titel „x“, gebucht auf <strong>mein</strong> Konto</li>
</ul>



<p class="wp-block-paragraph">Am 23. August wurde der letzte Fremd-Admin angelegt. Eine Minute später tauchten zwei neue Must-Use-Plugins auf: <code>firewall.php</code> und <code>wp2shell-batch-guard.php</code>. Der letzte Angreifer hat die Lücke hinter sich geschlossen, damit ihm niemand die Seite streitig macht. Danach kamen keine neuen Konten mehr.</p>



<p class="wp-block-paragraph">Aufgefallen ist mir das Ganze erst am 28. September, als mein Login nicht mehr ging und auch die Mail zum Zurücksetzen des Passworts nicht rausging.</p>



<p class="wp-block-paragraph">Über die SQL-Injection konnten die Angreifer die komplette Datenbank lesen. Damit gelten als abgeflossen: die Passwort-Hashes aller Konten und alle Zugangsdaten, die Plugins in ihren Einstellungen speichern, also API-Keys, Tokens und Verbindungen zu Google-Diensten.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Befehl: Bin ich betroffen?</h2>



<p class="wp-block-paragraph">Die Prüfung läuft am einfachsten mit <a href="https://wp-cli.org/">WP-CLI</a> im WordPress-Verzeichnis. Läuft WordPress im Docker-Container, stellst du <code>docker exec -u www-data &lt;container&gt; php wp-cli.phar</code> statt <code>wp</code> voran.</p>



<pre class="wp-block-code"><code># 1) Version
wp core version

# 2) Administratoren mit Anlagedatum
wp user list --role=administrator --fields=ID,user_login,user_email,user_registered

# 3) Core und Plugins gegen die Originale von wordpress.org
wp core verify-checksums
wp plugin verify-checksums --all

# 4) Spuren im Dateisystem
grep -rl "wp2shell" wp-content/ 2&gt;/dev/null
grep -rlE "RXST:|RXEND" wp-content/ 2&gt;/dev/null
ls -la wp-content/mu-plugins/
find wp-content/uploads -type f \( -iname "*.php*" -o -iname "*.phtml" -o -iname "*.phar" \)
find wp-content/plugins wp-content/themes -maxdepth 1 -newermt 2026-07-17

# 5) Treffer auf den Batch-Endpunkt im Access-Log
grep -E '"POST /(wp-json/batch/v1|\?rest_route=/batch/v1)' access.log | grep '" 207 '
</code></pre>



<p class="wp-block-paragraph">Die Datenbank hat eigene Spuren. <code>wp db query</code> braucht den MySQL-Client, der im offiziellen WordPress-Docker-Image fehlt. Dort führst du die Abfragen im Datenbank-Container aus. Das Tabellen-Präfix <code>wp_</code> ersetzt du durch deins.</p>



<pre class="wp-block-code"><code>-- Hilfsdatensätze des Exploits: pro angelegtem Admin meist ein Paar
SELECT post_type, post_status, COUNT(*) AS anzahl
FROM wp_posts
WHERE post_type IN ('customize_changeset', 'request')
  AND post_modified &gt;= '2026-07-17'
GROUP BY post_type, post_status;

-- Menü-Einträge, die auf die Exploit-Werkzeuge zeigen
SELECT post_id, meta_value FROM wp_postmeta
WHERE meta_key = '_menu_item_url' AND meta_value LIKE '%wp2shell%';
</code></pre>



<p class="wp-block-paragraph">So sah eine der beiden Webshells in meiner <code>functions.php</code> aus, gekürzt und entschärft:</p>



<pre class="wp-block-code"><code>/* wp2shell */ if(hash_equals('…32 Zeichen…',(string)($_GET&#91;'t']??''))){$c=$_GET&#91;'c'].' 2&gt;&amp;1'; … @shell_exec($c) … echo 'RXST:'.base64_encode($o).':RXEND'; exit;}
</code></pre>



<p class="wp-block-paragraph">Wer den geheimen Wert im Parameter <code>t</code> kennt, führt über <code>c</code> beliebige Befehle auf dem Server aus. Die Markierung <code>/* wp2shell */</code> und die Klammer <code>RXST:</code> … <code>:RXEND</code> sind gute Suchbegriffe.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Erklärung</h2>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Prüfung</th><th>Worauf du achtest</th></tr></thead><tbody><tr><td><code>wp core version</code></td><td>6.9.0–6.9.4 oder 7.0.0–7.0.1: Die Seite war verwundbar. Sofort aktualisieren und die übrigen Prüfungen trotzdem machen, ein Update entfernt keine Hintertüren.</td></tr><tr><td>Admin-Liste</td><td>Konten, die du nicht kennst, vor allem mit Anlagedatum ab dem 17.07.2026. Achte auf Namen, die deinem ähneln.</td></tr><tr><td><code>verify-checksums</code></td><td>Jede geänderte und jede zusätzliche Datei. Ausnahme im Docker-Image: <code>wp-config-docker.php</code> gehört dort hin.</td></tr><tr><td><code>grep</code> nach <code>wp2shell</code>, <code>RXST</code></td><td>Die verbreiteten Exploit-Tools markieren ihren Code so. Plugin-Ordner heißen oft <code>wp2shell_…</code>.</td></tr><tr><td><code>mu-plugins</code></td><td>Alles hier lädt automatisch und steht in keiner Plugin-Übersicht. Kennst du eine Datei nicht, ist das ein Alarmzeichen.</td></tr><tr><td>PHP in <code>uploads</code></td><td>Hat dort nichts zu suchen. Ausnahme: leere <code>index.php</code> und <code>.htaccess</code>-Dateien, die Plugins wie WPForms zum Schutz anlegen.</td></tr><tr><td>HTTP 207 im Log</td><td>„Multi-Status“ ist die normale Antwort des Batch-Endpunkts. Bei einem verwundbaren Core kann sie bedeuten, dass der Exploit durchgegangen ist. Bei mir passte ein 207-Burst sekundengenau zur Anlage eines Fremd-Admins.</td></tr><tr><td>Changesets und Requests</td><td>Pro Fremd-Admin entstand bei mir ein Paar aus <code>customize_changeset</code> und <code>request</code>. Den Request-Status <code>parse</code> gibt es in WordPress regulär nicht.</td></tr></tbody></table></figure>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Aufräumen: neu aufbauen statt putzen</h2>



<p class="wp-block-paragraph">Einzelne Webshells zu löschen ist ein Ratespiel. Du findest nie sicher alle, und eine übersehene reicht. Ich habe die Seite deshalb auf einem frischen Volume neu aufgebaut und aus der alten Installation nur übernommen, was ich prüfen konnte.</p>



<ol class="wp-block-list">
<li><strong>Offline nehmen und Beweise sichern:</strong> Datenbank-Dump, Kopie der Dateien und die Access-Logs. Läuft WordPress in Docker, hängen die Logs am Container und sind beim nächsten Neuerzeugen weg. Also zuerst <code>docker logs &lt;container> > access.log</code>.</li>



<li><strong>Frischer Core</strong> aus dem Original, bei Docker in einem neuen, leeren Volume.</li>



<li><strong>Plugins und Themes neu von wordpress.org</strong> installieren, nicht aus dem Backup kopieren. Bei der Gelegenheit alles weglassen, was du nicht brauchst.</li>



<li><strong>Aus <code>uploads</code> nur Mediendateien</strong> übernehmen, per Whitelist nach Dateiendung.</li>



<li><strong>Eigene Themes und Plugins</strong> aus deiner eigenen Quelle (Git, ZIP) neu einspielen. Hast du keine saubere Kopie, jede Datei prüfen, die sich seit dem 17.07. geändert hat.</li>



<li><strong>Datenbank bereinigen</strong>, siehe unten.</li>



<li><strong>Alles neu setzen:</strong> WordPress-Passwörter, Salts, Datenbank-Passwort, API-Keys und Tokens aus den Plugin-Einstellungen, den Login-Pfad. Und prüfen, ob du das alte WordPress-Passwort irgendwo anders benutzt hast.</li>



<li><strong>Datenschutz prüfen:</strong> Hast du Kommentare oder Formulardaten gespeichert, waren die für die Angreifer lesbar. Ob eine Meldung an die Datenschutzbehörde nötig ist (Art. 33 DSGVO, 72 Stunden ab Kenntnis), lässt du am besten rechtlich klären.</li>
</ol>



<p class="wp-block-paragraph">Die Mediendateien habe ich so übernommen:</p>



<pre class="wp-block-code"><code>rsync -a --prune-empty-dirs --include='*/' \
  --include='*.'{jpg,jpeg,png,gif,webp,avif,pdf,mp4,webm,mp3,txt,csv,ps1,zip} \
  --exclude='*' \
  alt/wp-content/uploads/ neu/wp-content/uploads/
</code></pre>



<p class="wp-block-paragraph">SVG-Dateien stehen bewusst nicht auf der Liste, weil sie JavaScript enthalten können. Die habe ich einzeln angesehen.</p>



<p class="wp-block-paragraph">Für die Datenbank vorher einen Dump ziehen. Fremde Konten entfernst du mit WP-CLI <strong>ohne</strong> <code>--reassign</code>, dann verschwinden ihre Beiträge mit:</p>



<pre class="wp-block-code"><code>wp user delete &lt;ID&gt; &lt;ID&gt; &lt;ID&gt; --yes
</code></pre>



<p class="wp-block-paragraph">Den Rest per SQL:</p>



<pre class="wp-block-code"><code>-- alle Sitzungen und Application Passwords entfernen (auch bei deinem eigenen Konto!)
DELETE FROM wp_usermeta WHERE meta_key IN ('session_tokens', '_application_passwords');

-- Hilfsdatensätze des Exploits
DELETE FROM wp_posts
WHERE post_type = 'customize_changeset' AND post_status = 'publish'
  AND post_modified &gt;= '2026-07-17';
DELETE FROM wp_posts WHERE post_type = 'request' AND post_status = 'parse';

-- verwaiste Metadaten
DELETE pm FROM wp_postmeta pm
LEFT JOIN wp_posts p ON p.ID = pm.post_id
WHERE p.ID IS NULL;
</code></pre>



<p class="wp-block-paragraph">Danach noch einmal nach Beiträgen suchen, die seit dem 17.07. geändert wurden und nicht von dir stammen. Die neun „x“-Beiträge bei mir liefen auf mein eigenes Konto und wären beim Löschen nach Autor durchgerutscht.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Absichern</h2>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="529" src="https://abow.info/wp-content/uploads/2026/09/inlay_wp2shell_schutzschichten-1024x529.png" alt="" class="wp-image-892" srcset="https://abow.info/wp-content/uploads/2026/09/inlay_wp2shell_schutzschichten-1024x529.png 1024w, https://abow.info/wp-content/uploads/2026/09/inlay_wp2shell_schutzschichten-766x396.png 766w, https://abow.info/wp-content/uploads/2026/09/inlay_wp2shell_schutzschichten-300x155.png 300w, https://abow.info/wp-content/uploads/2026/09/inlay_wp2shell_schutzschichten.png 1200w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<h3 class="wp-block-heading">Auto-Updates, die wirklich laufen</h3>



<p class="wp-block-paragraph">Das hätte den Einbruch sehr wahrscheinlich verhindert. WordPress braucht Schreibrechte auf seine eigenen Dateien:</p>



<pre class="wp-block-code"><code>chown -R www-data:www-data /var/www/html
wp eval 'require_once ABSPATH."wp-admin/includes/admin.php"; require_once ABSPATH."wp-admin/includes/class-wp-upgrader.php"; var_dump((new WP_Automatic_Updater())-&gt;is_disabled());'
</code></pre>



<p class="wp-block-paragraph"><code>bool(false)</code> heißt: Auto-Updates sind nicht deaktiviert. Richte außerdem SMTP ein, sonst bekommst du die Mail über ein gescheitertes Update nie.</p>



<p class="wp-block-paragraph">Beim offiziellen Docker-Image liegt der Core im Volume. <code>docker pull wordpress:latest</code> aktualisiert eine bestehende Installation <strong>nicht</strong>, das Image füllt nur ein leeres Volume.</p>



<h3 class="wp-block-heading">Batch-API, XML-RPC und Benutzerliste zu</h3>



<p class="wp-block-paragraph">Ein kleines Must-Use-Plugin unter <code>wp-content/mu-plugins/abow-hardening.php</code>:</p>



<pre class="wp-block-code"><code>&lt;?php
/**
 * Plugin Name: abow Hardening
 * Description: Batch-API nur fuer angemeldete Nutzer, XML-RPC aus, keine User-Aufzaehlung fuer Gaeste.
 *
 * .NOTES
 *   Name:        abow-hardening
 *   Author:      Andreas Bowitz
 *   Version:     0.2
 *   LastUpdated: 2026-Sep-28
 */
defined( 'ABSPATH' ) || exit;

// Batch-Endpunkt nur fuer angemeldete Nutzer, egal ueber welchen Weg die Route kommt
add_filter( 'rest_pre_dispatch', function ( $result, $server, $request ) {
	if ( 0 === strpos( $request-&gt;get_route(), '/batch/v1' ) &amp;&amp; ! is_user_logged_in() ) {
		return new WP_Error( 'abow_batch_forbidden', 'Batch-API nur fuer angemeldete Nutzer.', array( 'status' =&gt; 401 ) );
	}
	return $result;
}, 0, 3 );

// XML-RPC abschalten
add_filter( 'xmlrpc_enabled', '__return_false' );
add_filter( 'xmlrpc_methods', '__return_empty_array' );

// Keine Benutzer-Aufzaehlung ueber die REST-API fuer Gaeste
add_filter( 'rest_endpoints', function ( $endpoints ) {
	if ( ! is_user_logged_in() ) {
		unset( $endpoints&#91;'/wp/v2/users'], $endpoints&#91;'/wp/v2/users/(?P&lt;id&gt;&#91;\d]+)'] );
	}
	return $endpoints;
} );

// Keine Benutzernamen ueber /?author=1 fuer Gaeste (vor redirect_canonical)
add_action( 'template_redirect', function () {
	if ( ! is_user_logged_in() &amp;&amp; isset( $_GET&#91;'author'] ) ) {
		wp_safe_redirect( home_url( '/' ), 301 );
		exit;
	}
}, 1 );
</code></pre>



<p class="wp-block-paragraph">Die Sperre sitzt absichtlich in WordPress selbst und nicht nur in einer Firewall-Regel vor dem Server (warum, steht unter Stolperfallen). Ergänzend in der <code>.htaccess</code> im WordPress-Verzeichnis:</p>



<pre class="wp-block-code"><code>&lt;Files "xmlrpc.php"&gt;
    Require all denied
&lt;/Files&gt;
</code></pre>



<p class="wp-block-paragraph">Und in <code>wp-content/uploads/.htaccess</code>, damit dort nie wieder PHP ausgeführt wird:</p>



<pre class="wp-block-code"><code>&lt;FilesMatch "\.(?i:php&#91;0-9]?|phtml|phar|pht|phps)$"&gt;
    Require all denied
&lt;/FilesMatch&gt;
</code></pre>



<h3 class="wp-block-heading">Gefährliche PHP-Funktionen sperren</h3>



<p class="wp-block-paragraph">Beide Webshells in meinem Theme brauchten <code>shell_exec</code>, <code>exec</code> oder <code>system</code>. WordPress und meine Plugins brauchen diese Funktionen nicht. Klick nach dem Sperren trotzdem einmal durch Frontend und Backend, manche Backup- oder Bild-Plugins rufen externe Programme auf. Als PHP-Konfiguration (bei Docker als Datei nach <code>/usr/local/etc/php/conf.d/</code> mounten):</p>



<pre class="wp-block-code"><code>disable_functions = exec,passthru,shell_exec,system,proc_open,popen,pcntl_exec
expose_php = Off
</code></pre>



<p class="wp-block-paragraph">Eine eingeschleuste Webshell läuft damit ins Leere. WP-CLI nutzt teils selbst <code>proc_open</code>, dort rufst du PHP mit <code>php -d disable_functions= wp-cli.phar …</code> auf. Die Webseite bleibt gesperrt.</p>



<h3 class="wp-block-heading">Überwachen und sichern</h3>



<p class="wp-block-paragraph">Zehn Wochen unbemerkt waren das eigentliche Problem. Auf dem Server laufen jetzt drei kleine Skripte, die sich per Discord-Webhook melden:</p>



<ul class="wp-block-list">
<li>ein <strong>Admin-Wächter</strong>, der alle 15 Minuten prüft, ob es außer mir einen Administrator gibt</li>



<li>ein täglicher <strong>Integritäts-Check</strong>: Core und Plugins gegen die Prüfsummen von wordpress.org, eigene Themes, <code>mu-plugins</code>, <code>.htaccess</code> und ausführbare Dateien in <code>uploads</code> gegen eine Baseline</li>



<li>ein tägliches <strong>Backup</strong> von Datenbank, <code>wp-content</code> und Stack-Konfiguration, mit GPG verschlüsselt und per rclone auf OneDrive</li>
</ul>



<p class="wp-block-paragraph">Die Skripte stelle ich <a href="https://github.com/bowitzandreas-prog/Scripts">auf GitHub</a> bereit. Ein Backup zählt übrigens erst, wenn du es einmal zurückgespielt hast, und zwar mit der Passphrase aus deinem Passwort-Manager, nicht mit der Datei auf dem Server.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Stolperfallen</h2>



<ul class="wp-block-list">
<li><strong>Eine Firewall-Regel nur für <code>/wp-json/batch/v1</code> reicht nicht.</strong> Der Endpunkt ist auch über <code>/?rest_route=/batch/v1</code> erreichbar, und WordPress liest <code>rest_route</code> sogar aus dem POST-Body. Dann steht im Log nur <code>POST /</code>. Laut Patchstack ließen sich fast alle WAF-Regeln aus den ersten Stunden nach der Veröffentlichung so umgehen. In meinem Log standen über 1.200 POST-Anfragen auf <code>/</code>. Welche davon Exploit-Versuche waren, lässt sich ohne den Request-Body nicht mehr sagen.</li>



<li><strong><code>docker pull</code> patcht dein WordPress nicht.</strong> Der Core liegt im Volume, nicht im Image.</li>



<li><strong>Dateien als root hochgeladen, Auto-Updates still kaputt.</strong> Plugins aktualisierten sich weiter, der Core nicht. Ohne Mailversand erfährst du davon nichts.</li>



<li><strong>Ein neues Passwort allein hilft nicht.</strong> Webshells, Application Passwords und offene Sitzungen bleiben davon unberührt.</li>



<li><strong>Aufräumen nach Autor verfehlt Artefakte.</strong> Die „x“-Beiträge und die Exploit-Datensätze liefen bei mir auf mein eigenes Konto.</li>



<li><strong>Eigene Themes vergisst man leicht.</strong> Beim Neuaufbau aus wordpress.org fehlt ein selbst gebautes Theme, und wer es einfach aus dem alten Verzeichnis kopiert, kopiert die Webshell in der <code>functions.php</code> mit.</li>



<li><strong>Container-Logs sind flüchtig.</strong> Mein Access-Log reichte nur bis zum 10. August zurück, vermutlich weil der Container damals neu erzeugt wurde. Den Anfang des Angriffs konnte ich deshalb nicht mehr nachvollziehen.</li>



<li><strong>„Die Seite sieht doch normal aus.“</strong> Das tat sie die ganze Zeit. Die Angreifer wollten offenbar den Server und nicht mein Layout.</li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Ergebnis</h2>



<p class="wp-block-paragraph">abow.info läuft wieder auf einem frischen Core 7.1.2 mit funktionierenden Auto-Updates. Plugins und Theme sind sauber, alle Fremdkonten und Exploit-Reste sind aus der Datenbank entfernt, alle Passwörter und Schlüssel neu gesetzt. Die Batch-API ist für Gäste gesperrt, XML-RPC ist aus, und neue Administratoren oder veränderter Code melden sich innerhalb von Minuten beziehungsweise am nächsten Morgen per Discord. Das verschlüsselte Backup liegt zusätzlich auf OneDrive, die Wiederherstellung ist getestet.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Bonus: Schnellcheck von außen mit PowerShell</h2>



<p class="wp-block-paragraph"><code>Test-WpExposure.ps1</code> prüft von deinem Windows-Rechner aus, ob deine Seite für wp2shell verwundbar ist und welche weiteren Angriffsflächen für Gäste offen sind: sichtbare WordPress-Version, Batch-API über beide Routen, XML-RPC, Benutzer-Aufzählung per REST-API und <code>/?author=1</code> sowie die PHP-Version im Header. Das Skript schickt nur harmlose Anfragen und ändert nichts. Setz es ausschließlich gegen eigene Seiten ein.</p>



<p class="wp-block-paragraph">Es läuft unter Windows PowerShell 5.1 und PowerShell 7, bringt eine vollständige Hilfe mit (<code>Get-Help .\Test-WpExposure.ps1 -Full</code>) und gibt einen Exitcode zurück, den du in einer geplanten Aufgabe auswerten kannst: <code>0</code> alles ok, <code>1</code> Warnung oder kritisch, <code>2</code> Seite nicht erreichbar.</p>



<pre class="wp-block-code"><code>&lt;#PSScriptInfo

.VERSION 0.2

.GUID 4279b966-262d-4b19-8f41-7c97b2d9d781

.AUTHOR Andreas Bowitz

.COMPANYNAME abow.info

.COPYRIGHT (c) 2026 Andreas Bowitz. Alle Rechte vorbehalten.

.TAGS WordPress Security wp2shell CVE-2026-63030 CVE-2026-60137 Hardening

.LICENSEURI

.PROJECTURI https://abow.info

.ICONURI

.EXTERNALMODULEDEPENDENCIES

.REQUIREDSCRIPTS

.EXTERNALSCRIPTDEPENDENCIES

.RELEASENOTES
0.2 (2026-Sep-28) Vollstaendige Hilfe, Script-Metadaten, Banner, Bewertungsstufen,
                  Exitcodes, -PassThru, -TimeoutSec, Autoren-Aufzaehlung, X-Powered-By.
0.1 (2026-Sep-28) Erste Version fuer den Beitrag auf abow.info.

.PRIVATEDATA

#&gt;

&lt;#
.SYNOPSIS
    Prueft von aussen, ob eine eigene WordPress-Seite fuer wp2shell
    (CVE-2026-63030 / CVE-2026-60137) angreifbar ist und welche weiteren
    Angriffsflaechen fuer Gaeste offen sind.

.DESCRIPTION
    Test-WpExposure schickt ausschliesslich harmlose Lese- bzw. Leeranfragen an
    eine WordPress-Seite und bewertet die Antworten. Auf dem Server wird nichts
    veraendert, es werden keine Exploits ausgefuehrt.

    Geprueft wird:
      1. Erreichbarkeit der Seite
      2. Oeffentlich sichtbare WordPress-Version (Meta-Generator, RSS-Feed) und
         Abgleich mit den von wp2shell betroffenen Versionen
         (6.9.0-6.9.4 und 7.0.0-7.0.1, Fix in 6.9.5 bzw. 7.0.2)
      3. REST-Batch-Endpunkt fuer Gaeste, ueber beide Routen
         (/wp-json/batch/v1 und /?rest_route=/batch/v1)
      4. XML-RPC (Angriffsflaeche fuer Passwort-Rateversuche)
      5. Benutzer-Aufzaehlung ueber die REST-API und ueber /?author=1
      6. PHP-Versionsangabe im Header X-Powered-By

    Bewertungsstufen: OK, Hinweis, Warnung, Kritisch.

    Nur gegen eigene Seiten oder mit ausdruecklicher Erlaubnis des Betreibers
    einsetzen.

.PARAMETER Url
    Basis-URL der WordPress-Seite inklusive https://, z. B. https://example.com

.PARAMETER TimeoutSec
    Zeitlimit pro Anfrage in Sekunden. Standard: 20.

.PARAMETER PassThru
    Gibt die Ergebnisse zusaetzlich als Objekte zurueck, z. B. fuer Export-Csv
    oder eigene Auswertungen.

.EXAMPLE
    .\Test-WpExposure.ps1 -Url https://example.com

    Prueft die Seite und zeigt eine farbige Uebersicht mit Zusammenfassung.

.EXAMPLE
    .\Test-WpExposure.ps1 -Url https://example.com -PassThru |
        Export-Csv -Path .\wp-check.csv -NoTypeInformation -Encoding UTF8

    Schreibt die Ergebnisse zusaetzlich in eine CSV-Datei.

.EXAMPLE
    .\Test-WpExposure.ps1 -Url https://example.com
    if ($LASTEXITCODE -eq 1) { Write-Warning 'Handlungsbedarf' }

    Nutzt den Exitcode, etwa in einer geplanten Aufgabe.

.INPUTS
    Keine. Die URL wird als Parameter uebergeben.

.OUTPUTS
    Mit -PassThru: PSCustomObject mit den Eigenschaften
    Pruefung, Ergebnis, Stufe und Bewertung.

.NOTES
    Name:        Test-WpExposure
    Author:      Andreas Bowitz
    Version:     0.2
    LastUpdated: 2026-Sep-28

    Voraussetzungen: Windows PowerShell 5.1 oder PowerShell 7.x
    Exitcodes:       0 = keine Warnung, 1 = Warnung oder Kritisch gefunden,
                     2 = Seite nicht erreichbar

    Downloadete Skripte ggf. vorher freigeben: Unblock-File .\Test-WpExposure.ps1

.LINK
    https:&#47;&#47;abow.info

.LINK
    <span class="embed-privacy-url"><a href="https://wordpress.org/news/2026/07/wordpress-7-0-2-release/">Eingebetteten Inhalt von wordpress.org öffnen</a></span>
#&gt;
&#91;CmdletBinding()]
param(
    &#91;Parameter(Mandatory, Position = 0, HelpMessage = 'Basis-URL der WordPress-Seite, z. B. https://example.com')]
    &#91;ValidatePattern('^https?://&#91;^\s/$.?#].&#91;^\s]*$')]
    &#91;string]$Url,

    &#91;ValidateRange(3, 120)]
    &#91;int]$TimeoutSec = 20,

    &#91;switch]$PassThru
)

#region Grundeinstellungen
$ScriptName    = 'Test-WpExposure'
$ScriptVersion = '0.2'
$ScriptAuthor  = 'Andreas Bowitz'
$UserAgent     = "$ScriptName/$ScriptVersion (+https://abow.info)"

if ($PSVersionTable.PSVersion.Major -lt 6) {
    &#91;Net.ServicePointManager]::SecurityProtocol = &#91;Net.SecurityProtocolType]::Tls12
}
$Url     = $Url.TrimEnd('/')
$results = New-Object System.Collections.Generic.List&#91;object]
#endregion

#region Hilfsfunktionen
function Get-HttpResult {
    &lt;#
    .SYNOPSIS
        Fuehrt eine HTTP-Anfrage aus und liefert Status, Inhalt, Header und End-URL,
        auch bei Fehlerstatus. Kompatibel mit PowerShell 5.1 und 7.x.
    #&gt;
    param(
        &#91;Parameter(Mandatory)]&#91;string]$Uri,
        &#91;string]$Method = 'GET',
        &#91;string]$Body,
        &#91;string]$ContentType = 'application/json'
    )
    $p = @{
        Uri             = $Uri
        Method          = $Method
        UseBasicParsing = $true
        ErrorAction     = 'Stop'
        TimeoutSec      = $TimeoutSec
        UserAgent       = $UserAgent
    }
    if ($Body) { $p.Body = $Body; $p.ContentType = $ContentType }

    try {
        $r       = Invoke-WebRequest @p
        $content = $r.Content
        if ($content -is &#91;byte&#91;]]) { $content = &#91;Text.Encoding]::UTF8.GetString($content) }
        $final = $null
        if ($r.BaseResponse.ResponseUri)    { $final = $r.BaseResponse.ResponseUri.AbsoluteUri }             # PS 5.1
        elseif ($r.BaseResponse.RequestMessage) { $final = $r.BaseResponse.RequestMessage.RequestUri.AbsoluteUri } # PS 7
        &#91;pscustomobject]@{ Status = &#91;int]$r.StatusCode; Content = &#91;string]$content; Headers = $r.Headers; FinalUri = $final }
    }
    catch {
        $resp = $_.Exception.Response
        if ($resp) {
            &#91;pscustomobject]@{ Status = &#91;int]$resp.StatusCode; Content = ''; Headers = $null; FinalUri = $null }
        }
        else {
            &#91;pscustomobject]@{ Status = -1; Content = $_.Exception.Message; Headers = $null; FinalUri = $null }
        }
    }
}

function Add-Result {
    param(
        &#91;string]$Pruefung,
        &#91;string]$Ergebnis,
        &#91;ValidateSet('OK', 'Hinweis', 'Warnung', 'Kritisch')]&#91;string]$Stufe,
        &#91;string]$Bewertung
    )
    $results.Add(&#91;pscustomobject]@{
        Pruefung  = $Pruefung
        Ergebnis  = $Ergebnis
        Stufe     = $Stufe
        Bewertung = $Bewertung
    })
}

function Test-Wp2shellVersion {
    param(&#91;string]$Version)
    $parts = @($Version.Split('.'))
    while ($parts.Count -lt 3) { $parts += '0' }
    $v = &#91;version]($parts&#91;0..2] -join '.')
    return (($v -ge &#91;version]'6.9.0' -and $v -le &#91;version]'6.9.4') -or
            ($v -ge &#91;version]'7.0.0' -and $v -le &#91;version]'7.0.1'))
}
#endregion

#region Banner
Write-Host ''
Write-Host "  $ScriptName v$ScriptVersion  |  $ScriptAuthor  |  abow.info" -ForegroundColor Cyan
Write-Host "  Ziel: $Url" -ForegroundColor Gray
Write-Host "  Nur gegen eigene Seiten einsetzen. Es werden keine Daten veraendert." -ForegroundColor DarkGray
Write-Host ''
#endregion

#region 1) Erreichbarkeit
$start = Get-HttpResult -Uri "$Url/"
if ($start.Status -lt 0) {
    Write-Host "  Seite nicht erreichbar: $($start.Content)" -ForegroundColor Red
    exit 2
}
Add-Result 'Erreichbarkeit' $start.Status 'OK' 'Seite antwortet'
#endregion

#region 2) WordPress-Version
$version = $null
$quelle  = $null
if ($start.Content -match '&lt;meta&#91;^&gt;]+name=&#91;"'']generator&#91;"'']&#91;^&gt;]+content=&#91;"'']WordPress\s+(&#91;0-9.]+)') {
    $version = $Matches&#91;1]; $quelle = 'Meta-Generator'
}
if (-not $version) {
    foreach ($feedPath in '/feed/', '/?feed=rss2') {
        $feed = Get-HttpResult -Uri "$Url$feedPath"
        if ($feed.Content -match 'wordpress\.org/\?v=(&#91;0-9.]+)') { $version = $Matches&#91;1]; $quelle = "Feed $feedPath"; break }
    }
}
if ($version) {
    if (Test-Wp2shellVersion $version) {
        Add-Result 'WordPress-Version' "$version ($quelle)" 'Kritisch' 'wp2shell-verwundbar: sofort updaten und auf Einbruch pruefen'
    }
    else {
        Add-Result 'WordPress-Version' "$version ($quelle)" 'Hinweis' 'nicht im betroffenen Bereich, Version aber oeffentlich sichtbar'
    }
}
else {
    Add-Result 'WordPress-Version' '-' 'OK' 'nicht oeffentlich sichtbar, bitte im Backend pruefen'
}
#endregion

#region 3) Batch-API (beide Routen)
foreach ($route in '/wp-json/batch/v1', '/?rest_route=/batch/v1') {
    $r = Get-HttpResult -Uri "$Url$route" -Method POST -Body '{"requests":&#91;]}'
    if ($r.Status -in 401, 403) {
        Add-Result "Batch-API $route" $r.Status 'OK' 'fuer Gaeste gesperrt'
    }
    elseif ($r.Status -eq 404) {
        Add-Result "Batch-API $route" $r.Status 'OK' 'nicht vorhanden'
    }
    elseif ($r.Status -lt 0) {
        Add-Result "Batch-API $route" 'keine Antwort' 'Hinweis' 'Anfrage lief ins Leere, ggf. Firewall'
    }
    else {
        Add-Result "Batch-API $route" $r.Status 'Warnung' 'fuer Gaeste erreichbar, nur mit gepatchtem Core vertretbar'
    }
}
#endregion

#region 4) XML-RPC
$xml = '&lt;?xml version="1.0"?&gt;&lt;methodCall&gt;&lt;methodName&gt;system.listMethods&lt;/methodName&gt;&lt;/methodCall&gt;'
$r   = Get-HttpResult -Uri "$Url/xmlrpc.php" -Method POST -Body $xml -ContentType 'text/xml'
if ($r.Status -eq 200 -and $r.Content -match '&lt;string&gt;') {
    Add-Result 'XML-RPC' $r.Status 'Warnung' 'offen, Ziel fuer Passwort-Rateversuche'
}
else {
    Add-Result 'XML-RPC' $r.Status 'OK' 'gesperrt oder ohne Methoden'
}
#endregion

#region 5) Benutzer-Aufzaehlung
foreach ($route in '/wp-json/wp/v2/users', '/?rest_route=/wp/v2/users') {
    $r = Get-HttpResult -Uri "$Url$route"
    if ($r.Status -eq 200 -and $r.Content -match '"slug"\s*:\s*"(&#91;^"]+)"') {
        Add-Result "Benutzerliste $route" $r.Status 'Warnung' "Benutzernamen oeffentlich, z. B. '$($Matches&#91;1])'"
    }
    else {
        Add-Result "Benutzerliste $route" $r.Status 'OK' 'nicht auslesbar'
    }
}
$r = Get-HttpResult -Uri "$Url/?author=1"
if ($r.FinalUri -match '/author/(&#91;^/?#]+)') {
    Add-Result 'Autoren-Weiterleitung /?author=1' $r.Status 'Hinweis' "verraet Benutzernamen '$($Matches&#91;1])'"
}
else {
    Add-Result 'Autoren-Weiterleitung /?author=1' $r.Status 'OK' 'kein Benutzername erkennbar'
}
#endregion

#region 6) PHP-Version im Header
$powered = $null
if ($start.Headers) { $powered = $start.Headers&#91;'X-Powered-By'] }
if ($powered) {
    Add-Result 'Header X-Powered-By' (&#91;string]$powered) 'Hinweis' 'PHP-Version sichtbar, expose_php = Off setzen'
}
else {
    Add-Result 'Header X-Powered-By' '-' 'OK' 'keine PHP-Version sichtbar'
}
#endregion

#region Ausgabe
$farbe = @{ OK = 'Green'; Hinweis = 'Cyan'; Warnung = 'Yellow'; Kritisch = 'Red' }
$w1 = ($results | ForEach-Object { $_.Pruefung.Length } | Measure-Object -Maximum).Maximum
$w2 = ($results | ForEach-Object { (&#91;string]$_.Ergebnis).Length } | Measure-Object -Maximum).Maximum

foreach ($e in $results) {
    Write-Host ('  {0,-10}' -f "&#91;$($e.Stufe)]") -ForegroundColor $farbe&#91;$e.Stufe] -NoNewline
    Write-Host (" {0}  {1}  " -f $e.Pruefung.PadRight($w1), (&#91;string]$e.Ergebnis).PadRight($w2)) -NoNewline
    Write-Host $e.Bewertung -ForegroundColor Gray
}

$kritisch = @($results | Where-Object Stufe -eq 'Kritisch').Count
$warnung  = @($results | Where-Object Stufe -eq 'Warnung').Count
$hinweis  = @($results | Where-Object Stufe -eq 'Hinweis').Count

Write-Host ''
if ($kritisch + $warnung -eq 0) {
    Write-Host "  Ergebnis: keine Warnung, $hinweis Hinweis(e)." -ForegroundColor Green
    $exitCode = 0
}
else {
    Write-Host "  Ergebnis: $kritisch kritisch, $warnung Warnung(en), $hinweis Hinweis(e)." -ForegroundColor Yellow
    $exitCode = 1
}
Write-Host ''

if ($PassThru) { $results }
exit $exitCode
#endregion
</code></pre>



<p class="wp-block-paragraph">Aufruf:</p>



<pre class="wp-block-code"><code>Unblock-File .\Test-WpExposure.ps1
.\Test-WpExposure.ps1 -Url https://example.com

# Ergebnisse zusaetzlich als CSV
.\Test-WpExposure.ps1 -Url https://example.com -PassThru |
    Export-Csv -Path .\wp-check.csv -NoTypeInformation -Encoding UTF8
</code></pre>



<p class="wp-block-paragraph">So sieht die Ausgabe gegen eine ungehärtete Testinstanz mit WordPress 7.0.1 aus:</p>



<pre class="wp-block-preformatted"> <code> Test-WpExposure v0.2  |  Andreas Bowitz  |  abow.info
  Ziel: https://test.example

  [OK]       Erreichbarkeit                           200                     Seite antwortet
  [Kritisch] WordPress-Version                        7.0.1 (Meta-Generator)  wp2shell-verwundbar: sofort updaten und auf Einbruch pruefen
  [Warnung]  Batch-API /wp-json/batch/v1              207                     fuer Gaeste erreichbar, nur mit gepatchtem Core vertretbar
  [Warnung]  Batch-API /?rest_route=/batch/v1         207                     fuer Gaeste erreichbar, nur mit gepatchtem Core vertretbar
  [Warnung]  XML-RPC                                  200                     offen, Ziel fuer Passwort-Rateversuche
  [Warnung]  Benutzerliste /wp-json/wp/v2/users       200                     Benutzernamen oeffentlich, z. B. 'admin'
  [Warnung]  Benutzerliste /?rest_route=/wp/v2/users  200                     Benutzernamen oeffentlich, z. B. 'admin'
  [Hinweis]  Autoren-Weiterleitung /?author=1         200                     verraet Benutzernamen 'admin'
  [Hinweis]  Header X-Powered-By                      PHP/8.3.9               PHP-Version sichtbar, expose_php = Off setzen

  Ergebnis: 1 kritisch, 5 Warnung(en), 2 Hinweis(e).
</code></pre>



<p class="wp-block-paragraph">Nach der Härtung aus diesem Beitrag stehen alle Zeilen auf <code>[OK]</code>: Batch-API <code>401</code>, XML-RPC <code>403</code>, Benutzerlisten <code>404</code>, keine Version und keine PHP-Angabe sichtbar. Eine Warnung bei der Batch-API heißt bei gepatchtem Core noch nicht, dass jemand eingebrochen ist. Es bleibt aber Angriffsfläche für die nächste Lücke in diesem Endpunkt. Die installierte Version prüfst du dann im Backend unter <code>Dashboard → Aktualisierungen</code>.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph"><strong>Fazit:</strong> Der Fix lag zwei Tage bereit, bevor es mich erwischt hat. Gescheitert ist es an einem Rechteproblem nach dem Umzug und daran, dass zehn Wochen lang niemand hingeschaut hat. Prüf also heute, ob sich dein WordPress wirklich selbst aktualisiert, und richte dir irgendeine Meldung ein, wenn ein neuer Administrator auftaucht. Beides kostet eine halbe Stunde.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<h2 class="wp-block-heading">Quellen</h2>



<ul class="wp-block-list">
<li>WordPress: <a href="https://wordpress.org/news/2026/07/wordpress-7-0-2-release/">WordPress 7.0.2 Release</a></li>



<li>Searchlight Cyber: <a href="https://slcyber.io/research-center/wp2shell-pre-authentication-rce-in-wordpress-core/">wp2shell: Pre Authentication RCE in WordPress Core</a></li>



<li>GitHub Security Advisories: <a href="https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-ff9f-jf42-662q">GHSA-ff9f-jf42-662q</a>, <a href="https://github.com/WordPress/wordpress-develop/security/advisories/GHSA-fpp7-x2x2-2mjf">GHSA-fpp7-x2x2-2mjf</a></li>



<li>Bitdefender: <a href="https://businessinsights.bitdefender.com/technical-advisory-wp2shell-unauthenticated-remote-code-execution-full-site-takeover-wordpress-core">Technical Advisory: wp2shell</a></li>



<li>Wiz: <a href="https://www.wiz.io/blog/wp2shell-cve-2026-63030-cve-2026-60137">Exploitation in the Wild of wp2shell</a></li>



<li>Cyber Kendra: <a href="https://www.cyberkendra.com/2026/07/wp2shell-guide.html">WP2Shell: Checker, Patch &amp; Detection Guide</a> (Hinweis auf umgehbare WAF-Regeln laut Patchstack)</li>



<li>Elastic Security Labs: <a href="https://www.elastic.co/security-labs/blog/wp2shell-wordpress-rce-detection-elastic-defend">wp2shell: detecting WordPress pre-auth RCE</a></li>
</ul>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://abow.info/persoenlich/wordpress-wp2shell-wie-mein-blog-uebernommen-wurde-und-wie-ich-ihn-zurueckgeholt-habe/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
