Skip to content

WPScan - Escáner de Vulnerabilidades para WordPress

WPScan - Escáner de Vulnerabilidades para WordPress

Section titled “WPScan - Escáner de Vulnerabilidades para WordPress”

WPScan es la herramienta de seguridad más popular y completa para auditorías de sitios WordPress. Desarrollada por el equipo de WPScan, esta herramienta de código abierto automatiza la detección de vulnerabilidades, enumeración de plugins, temas, usuarios y configuraciones inseguras en instalaciones de WordPress.

  • Base de datos actualizada: Más de 29,000 vulnerabilidades conocidas
  • Enumeración avanzada: Plugins, temas, usuarios, medios
  • Detección pasiva y agresiva: Múltiples modos de escaneo
  • API integrada: Acceso a la base de datos de vulnerabilidades WPVulnDB
  • Ataques de fuerza bruta: Integrado para credenciales
  • Salida estructurada: JSON, CLI-friendly
Terminal window
# WPScan viene preinstalado en Kali Linux
wpscan --version
# Actualizar si es necesario
sudo apt update && sudo apt upgrade wpscan
Terminal window
# Instalar Ruby y dependencias
sudo apt update
sudo apt install ruby ruby-dev build-essential libcurl4-openssl-dev libxml2 libxml2-dev libxslt1-dev ruby-dev libgmp-dev zlib1g-dev
# Instalar WPScan como gem
sudo gem install wpscan
# Verificar instalación
wpscan --version
Terminal window
# Usar imagen oficial de Docker
docker pull wpscanteam/wpscan
# Ejecutar con Docker
docker run -it --rm wpscanteam/wpscan --url https://ejemplo.com
Terminal window
# Clonar repositorio
git clone https://github.com/wpscanteam/wpscan.git
cd wpscan
# Instalar dependencias
bundle install
# Ejecutar
ruby wpscan.rb --url https://ejemplo.com
Terminal window
# Registrarse en https://wpscan.com/api
# Obtener token gratuito (25 requests/día) o premium
# Configurar token
wpscan --api-token TU_TOKEN_AQUI --url https://ejemplo.com
# Guardar token permanentemente
echo "api_token: TU_TOKEN_AQUI" > ~/.wpscan/scan.yml
Terminal window
# Sintaxis general
wpscan [opciones] --url <URL>
# Escaneo básico
wpscan --url https://ejemplo.com
# Escaneo con enumeración
wpscan --url https://ejemplo.com --enumerate p,t,u
# Con API token
wpscan --url https://ejemplo.com --api-token TOKEN
ParámetroDescripciónEjemplo
-e, --enumerateEnumerar componentes-e p,t,u,m
pPlugins populares-e p
apTodos los plugins-e ap
vpPlugins vulnerables-e vp
tTemas populares-e t
atTodos los temas-e at
vtTemas vulnerables-e vt
uUsuarios-e u
mArchivos multimedia-e m
ParámetroDescripciónEjemplo
--detection-modeModo de detección--detection-mode aggressive
--plugins-detectionDetección de plugins--plugins-detection aggressive
--plugins-version-detectionDetección de versiones--plugins-version-detection aggressive
ParámetroDescripciónEjemplo
-f, --formatFormato de salida-f json
-o, --outputArchivo de salida-o reporte.json
--no-bannerSin banner--no-banner
-v, --verboseModo verbose-v
Terminal window
# Escaneo básico con información general
wpscan --url https://ejemplo.com
# Ejemplo de salida:
# [+] URL: https://ejemplo.com/
# [+] Started: Mon Jan 01 12:00:00 2024
# [+] Interesting Finding(s):
# [+] WordPress version: 6.1.1 - Identified By: Rss Generator
# [+] WordPress theme in use: twentytwentythree
Terminal window
# Enumerar plugins populares
wpscan --url https://ejemplo.com --enumerate p
# Enumerar usuarios
wpscan --url https://ejemplo.com --enumerate u
# Enumeración completa
wpscan --url https://ejemplo.com --enumerate ap,at,u,m --api-token TOKEN
Terminal window
# Modo agresivo (más detecciones, más requests)
wpscan --url https://ejemplo.com --detection-mode aggressive --enumerate ap,at,u
# Solo plugins vulnerables con API
wpscan --url https://ejemplo.com --enumerate vp --api-token TOKEN
#!/bin/bash
# Script de auditoría completa de WordPress con WPScan
# Uso: ./wordpress_audit.sh <URL> [API_TOKEN]
URL=$1
API_TOKEN=$2
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
OUTPUT_DIR="wpscan_audit_${TIMESTAMP}"
if [ -z "$URL" ]; then
echo "Uso: $0 <URL> [API_TOKEN]"
exit 1
fi
echo "[+] Iniciando auditoría completa de WordPress: $URL"
mkdir -p $OUTPUT_DIR
# Función para ejecutar WPScan con parámetros comunes
run_wpscan() {
local additional_params="$1"
local output_file="$2"
if [ ! -z "$API_TOKEN" ]; then
wpscan --url $URL --api-token $API_TOKEN $additional_params -f json -o $OUTPUT_DIR/$output_file
else
wpscan --url $URL $additional_params -f json -o $OUTPUT_DIR/$output_file
fi
}
# 1. Escaneo básico
echo "[+] Fase 1: Escaneo básico"
run_wpscan "" "01_basic_scan.json"
# 2. Enumeración de plugins populares
echo "[+] Fase 2: Enumeración de plugins populares"
run_wpscan "--enumerate p" "02_popular_plugins.json"
# 3. Enumeración de todos los plugins (si hay API token)
if [ ! -z "$API_TOKEN" ]; then
echo "[+] Fase 3: Enumeración completa de plugins"
run_wpscan "--enumerate ap --plugins-detection aggressive" "03_all_plugins.json"
fi
# 4. Enumeración de temas
echo "[+] Fase 4: Enumeración de temas"
run_wpscan "--enumerate t" "04_themes.json"
# 5. Enumeración de usuarios
echo "[+] Fase 5: Enumeración de usuarios"
run_wpscan "--enumerate u" "05_users.json"
# 6. Archivos multimedia
echo "[+] Fase 6: Archivos multimedia"
run_wpscan "--enumerate m" "06_media.json"
# 7. Detección agresiva
echo "[+] Fase 7: Detección agresiva"
run_wpscan "--detection-mode aggressive" "07_aggressive.json"
# 8. Solo vulnerabilidades (con API)
if [ ! -z "$API_TOKEN" ]; then
echo "[+] Fase 8: Solo vulnerabilidades"
run_wpscan "--enumerate vp,vt" "08_vulnerabilities.json"
fi
echo "[+] Auditoría completada. Resultados en: $OUTPUT_DIR"
# Generar resumen
generate_summary $OUTPUT_DIR
Terminal window
generate_summary() {
local output_dir=$1
local summary_file="$output_dir/RESUMEN_EJECUTIVO.txt"
echo "=== RESUMEN EJECUTIVO - AUDITORÍA WORDPRESS ===" > $summary_file
echo "Fecha: $(date)" >> $summary_file
echo "URL: $URL" >> $summary_file
echo "" >> $summary_file
# Extraer información clave usando jq
if [ -f "$output_dir/01_basic_scan.json" ]; then
echo "=== INFORMACIÓN BÁSICA ===" >> $summary_file
jq -r '.version.number // "No detectada"' $output_dir/01_basic_scan.json | sed 's/^/Versión WordPress: /' >> $summary_file
jq -r '.main_theme.slug // "No detectado"' $output_dir/01_basic_scan.json | sed 's/^/Tema activo: /' >> $summary_file
echo "" >> $summary_file
fi
# Plugins encontrados
if [ -f "$output_dir/02_popular_plugins.json" ]; then
echo "=== PLUGINS DETECTADOS ===" >> $summary_file
jq -r '.plugins | keys[]' $output_dir/02_popular_plugins.json >> $summary_file
echo "" >> $summary_file
fi
# Usuarios encontrados
if [ -f "$output_dir/05_users.json" ]; then
echo "=== USUARIOS ENCONTRADOS ===" >> $summary_file
jq -r '.users | keys[]' $output_dir/05_users.json >> $summary_file
echo "" >> $summary_file
fi
# Vulnerabilidades (si hay API)
if [ -f "$output_dir/08_vulnerabilities.json" ]; then
echo "=== VULNERABILIDADES CRÍTICAS ===" >> $summary_file
jq -r '.plugins[]?.vulnerabilities[]? | select(.fixed_in == null) | .title' $output_dir/08_vulnerabilities.json >> $summary_file
echo "" >> $summary_file
fi
echo "[+] Resumen ejecutivo generado: $summary_file"
}
#!/bin/bash
# Ataque de fuerza bruta con WPScan
wordpress_bruteforce() {
local url=$1
local userlist=$2
local wordlist=$3
local threads=${4:-10}
echo "[+] Iniciando ataque de fuerza bruta"
echo "URL: $url"
echo "Usuarios: $userlist"
echo "Wordlist: $wordlist"
echo "Threads: $threads"
# Ejecutar ataque de fuerza bruta
wpscan --url $url \
--usernames $userlist \
--passwords $wordlist \
--threads $threads \
--max-threads $threads \
-f json \
-o bruteforce_results.json
# Verificar resultados
if grep -q "Valid Combinations Found" bruteforce_results.json; then
echo "[!] CREDENCIALES ENCONTRADAS:"
jq -r '.password_attack[].username + ":" + .password_attack[].password' bruteforce_results.json
else
echo "[-] No se encontraron credenciales válidas"
fi
}
# Crear lista de usuarios común
create_common_userlist() {
cat > common_users.txt << EOF
admin
administrator
wp-admin
test
demo
user
root
guest
www
web
blog
site
EOF
}
# Uso del ataque de fuerza bruta
# create_common_userlist
# wordpress_bruteforce "https://ejemplo.com" "common_users.txt" "/usr/share/wordlists/rockyou.txt" 5
{
"version": {
"number": "6.1.1",
"status": "latest",
"found_by": "Rss Generator"
},
"main_theme": {
"slug": "twentytwentythree",
"location": "https://ejemplo.com/wp-content/themes/twentytwentythree/",
"style_uri": "https://ejemplo.com/wp-content/themes/twentytwentythree/style.css"
}
}
{
"plugins": {
"akismet": {
"slug": "akismet",
"location": "https://ejemplo.com/wp-content/plugins/akismet/",
"version": {
"number": "4.2.1",
"confidence": 100,
"found_by": "Query Parameter"
},
"vulnerabilities": []
}
}
}
{
"users": {
"admin": {
"id": 1,
"username": "admin",
"found_by": "Author Id Brute Forcing"
},
"editor": {
"id": 2,
"username": "editor",
"found_by": "Wp Json Api"
}
}
}
#!/bin/bash
post_wpscan_verification() {
local url=$1
local wpscan_output=$2
echo "[+] Verificación manual post-WPScan"
# Extraer plugins de resultados WPScan
plugins=$(jq -r '.plugins | keys[]' $wpscan_output)
for plugin in $plugins; do
echo "[+] Verificando plugin: $plugin"
# Verificar archivos readme
readme_status=$(curl -s -o /dev/null -w "%{http_code}" "$url/wp-content/plugins/$plugin/readme.txt")
if [ "$readme_status" = "200" ]; then
echo "[!] README accesible para $plugin"
curl -s "$url/wp-content/plugins/$plugin/readme.txt" | head -10
fi
# Verificar changelog
changelog_status=$(curl -s -o /dev/null -w "%{http_code}" "$url/wp-content/plugins/$plugin/changelog.txt")
if [ "$changelog_status" = "200" ]; then
echo "[!] CHANGELOG accesible para $plugin"
fi
done
# Verificar archivos sensibles adicionales
sensitive_files=(
"wp-config.php.bak"
"wp-config.php.old"
".wp-config.php.swp"
"wp-config.php~"
"backup-wp-config.php"
"wp-content/debug.log"
"wp-content/uploads/wp-config.php"
"error_log"
".htaccess.bak"
"wp-admin/install.php"
)
echo "[+] Verificando archivos sensibles adicionales"
for file in "${sensitive_files[@]}"; do
status=$(curl -s -o /dev/null -w "%{http_code}" "$url/$file")
if [ "$status" = "200" ]; then
echo "[!] CRÍTICO: $file accesible"
elif [ "$status" = "403" ]; then
echo "[?] PROTEGIDO: $file (existe pero inaccesible)"
fi
done
}
#!/bin/bash
analyze_wp_security_config() {
local url=$1
echo "[+] Analizando configuración de seguridad de WordPress"
# Verificar XML-RPC
xmlrpc_status=$(curl -s -o /dev/null -w "%{http_code}" "$url/xmlrpc.php")
if [ "$xmlrpc_status" = "200" ]; then
echo "[!] RIESGO: XML-RPC habilitado"
# Verificar métodos disponibles
methods=$(curl -s -X POST "$url/xmlrpc.php" -d '<methodCall><methodName>system.listMethods</methodName></methodCall>')
if [[ $methods == *"wp.getUsersBlogs"* ]]; then
echo "[!] CRÍTICO: Método wp.getUsersBlogs disponible (fuerza bruta)"
fi
else
echo "[+] XML-RPC deshabilitado"
fi
# Verificar API REST
api_status=$(curl -s -o /dev/null -w "%{http_code}" "$url/wp-json/wp/v2/users")
if [ "$api_status" = "200" ]; then
echo "[!] RIESGO: API REST expone usuarios"
users=$(curl -s "$url/wp-json/wp/v2/users" | jq -r '.[].name' | head -5)
echo "Usuarios expuestos: $users"
else
echo "[+] API REST protegida"
fi
# Verificar directory listing
uploads_listing=$(curl -s "$url/wp-content/uploads/" | grep -i "index of")
if [ ! -z "$uploads_listing" ]; then
echo "[!] RIESGO: Directory listing habilitado en uploads"
else
echo "[+] Directory listing deshabilitado"
fi
# Verificar versión en generator
generator=$(curl -s "$url" | grep -i "generator.*wordpress" | head -1)
if [ ! -z "$generator" ]; then
echo "[!] INFORMACIÓN: Versión WordPress expuesta en meta generator"
echo "$generator"
else
echo "[+] Meta generator WordPress oculto"
fi
# Verificar readme.html
readme_status=$(curl -s -o /dev/null -w "%{http_code}" "$url/readme.html")
if [ "$readme_status" = "200" ]; then
echo "[!] INFORMACIÓN: readme.html accesible"
else
echo "[+] readme.html no accesible"
fi
}
Terminal window
# Usar templates de WordPress en Nuclei después de WPScan
nuclei -u https://ejemplo.com -t ~/nuclei-templates/technologies/wordpress/
# Templates específicos basados en hallazgos de WPScan
nuclei -u https://ejemplo.com -t ~/nuclei-templates/vulnerabilities/wordpress/
Terminal window
# Usar módulos de Metasploit basados en hallazgos
msfconsole -q -x "
use auxiliary/scanner/http/wordpress_scanner;
set RHOSTS ejemplo.com;
run;
exit"
Terminal window
# Configurar proxy para capturar tráfico de WPScan
export http_proxy=http://127.0.0.1:8080
export https_proxy=http://127.0.0.1:8080
wpscan --url https://ejemplo.com --enumerate p
#!/bin/bash
multi_site_wordpress_audit() {
local sites_file=$1
local api_token=$2
local output_base="multi_audit_$(date +%Y%m%d_%H%M%S)"
mkdir -p $output_base
echo "[+] Iniciando auditoría de múltiples sitios WordPress"
while IFS= read -r url; do
site_name=$(echo $url | sed 's/https\?:\/\///g' | sed 's/\/.*//g' | sed 's/\./_/g')
echo "[+] Auditando: $site_name ($url)"
mkdir -p "$output_base/$site_name"
# WPScan básico
if [ ! -z "$api_token" ]; then
wpscan --url $url --api-token $api_token --enumerate vp,vt,u -f json -o "$output_base/$site_name/wpscan.json"
else
wpscan --url $url --enumerate p,t,u -f json -o "$output_base/$site_name/wpscan.json"
fi
# Análisis de seguridad
analyze_wp_security_config $url > "$output_base/$site_name/security_analysis.txt"
# Resumen por sitio
echo "=== RESUMEN DE $site_name ===" >> "$output_base/resumen_general.txt"
jq -r '.version.number // "No detectada"' "$output_base/$site_name/wpscan.json" | sed 's/^/Versión: /' >> "$output_base/resumen_general.txt"
jq -r '.plugins | length' "$output_base/$site_name/wpscan.json" | sed 's/^/Plugins: /' >> "$output_base/resumen_general.txt"
jq -r '.users | length' "$output_base/$site_name/wpscan.json" | sed 's/^/Usuarios: /' >> "$output_base/resumen_general.txt"
echo "" >> "$output_base/resumen_general.txt"
sleep 10 # Delay entre sitios
done < $sites_file
echo "[+] Auditoría multi-sitio completada: $output_base"
}
# Uso:
# echo "https://sitio1.com" > sitios.txt
# echo "https://sitio2.com" >> sitios.txt
# multi_site_wordpress_audit "sitios.txt" "TU_API_TOKEN"
#!/bin/bash
wordpress_continuous_monitoring() {
local url=$1
local api_token=$2
local baseline_file="baseline_$(echo $url | sed 's/https\?:\/\///g' | sed 's/\//_/g').json"
local current_file="current_$(date +%Y%m%d_%H%M%S).json"
echo "[+] Monitoreo continuo de WordPress: $url"
# Generar escaneo actual
if [ ! -z "$api_token" ]; then
wpscan --url $url --api-token $api_token --enumerate ap,at,u -f json -o $current_file
else
wpscan --url $url --enumerate p,t,u -f json -o $current_file
fi
if [ -f "$baseline_file" ]; then
echo "[+] Comparando con baseline..."
# Comparar plugins
baseline_plugins=$(jq -r '.plugins | keys[]' $baseline_file | sort)
current_plugins=$(jq -r '.plugins | keys[]' $current_file | sort)
new_plugins=$(comm -13 <(echo "$baseline_plugins") <(echo "$current_plugins"))
removed_plugins=$(comm -23 <(echo "$baseline_plugins") <(echo "$current_plugins"))
if [ ! -z "$new_plugins" ]; then
echo "[!] NUEVOS PLUGINS DETECTADOS:"
echo "$new_plugins"
fi
if [ ! -z "$removed_plugins" ]; then
echo "[!] PLUGINS REMOVIDOS:"
echo "$removed_plugins"
fi
# Comparar versión de WordPress
baseline_version=$(jq -r '.version.number // "unknown"' $baseline_file)
current_version=$(jq -r '.version.number // "unknown"' $current_file)
if [ "$baseline_version" != "$current_version" ]; then
echo "[!] CAMBIO DE VERSIÓN WORDPRESS: $baseline_version -> $current_version"
fi
# Actualizar baseline
cp $current_file $baseline_file
else
echo "[+] Creando baseline inicial..."
cp $current_file $baseline_file
fi
}
# Ejecutar con cron cada 24 horas:
# 0 2 * * * /path/to/wordpress_continuous_monitoring.sh https://ejemplo.com API_TOKEN
  1. Rate limiting: API gratuita limitada a 25 requests/día
  2. Detección pasiva: Puede no detectar todos los plugins/temas
  3. Falsos positivos: Especialmente en modo agresivo
  4. Sitios protegidos: WAF puede bloquear escaneos
  1. Usar API token: Para mejores resultados y detección de vulnerabilidades
  2. Combinar modos: Pasivo para reconocimiento, agresivo para detalles
  3. Verificación manual: Confirmar hallazgos importantes
  4. Documentar todo: Mantener registros de auditorías
  5. Actualizar regularmente: Mantener WPScan y base de datos actualizados
  • WP-CLI: Interfaz de línea de comandos oficial de WordPress
  • WordPress Security Scanner: Herramientas online
  • Nuclei: Templates específicos para WordPress
  • CMSmap: Scanner multi-CMS

⚠️ IMPORTANTE: Esta documentación es únicamente para fines educativos y de investigación en ciberseguridad. El uso de WPScan debe realizarse exclusivamente en:

  • Sitios web propios
  • Entornos de laboratorio
  • Sitios con autorización explícita y por escrito

El uso no autorizado puede constituir un delito. Los autores no se hacen responsables del mal uso de esta información.