VulnHub - Safeharbor CTF Walkthrough

Safeharbor
Una máquina virtual más compleja, diseñada para entrenar tanto para pruebas de penetración con nuevas metodologías de infraestructura de TI como para prácticas de pivoteo de red. Necesitará estar familiarizado con técnicas de pivoteo, vulnerabilidades de aplicaciones web, Metasploit y Meterpreter, así como con metodologías de enumeración y mucha paciencia. Cabe destacar que hay dos indicadores adicionales que aparecerán en el directorio /root, según las acciones predefinidas realizadas durante el rooteo de la máquina virtual.

Como primer paso con la herramienta Netdiscover realizaré un reconocimiento red para identificar la máquina objetivo.
netdiscover -r 192.168.50.0/24
sudo netdiscover -r 192.168.50.0/24
Nuestra máquina objetivo tiene la dirección IP 192.168.50.155. Ahora ejecutaré la herramienta Nmap para enumerar puertos y servicios que estén ejecutándose en la máquina objetivo.
sudo nmap -n -Pn -p- --open --min-rate 5000 -sS 192.168.50.155
sudo nmap -n -Pn -p- --open --rate-min 5000 -sS 192.168.50.155
Como se muestra en la imagen anterior solo dos servicios se están ejecutando en la máquina. SSH en el puerto 22 y HTTP en puerto 80.
sudo nmap -n -Pn -p 22,80 -sV 192.168.50.155
sudo nmap -n -Pn -p 22,80 -sV 192.168.50.155
En esta imagen se muestra la versión de los servicios que están en ejecución OpenSSH 7.6p1 y nginx 1.17.4 puertos 22 y 80 respectivamente.

Por último, ejecutaré la opción -sC de Nmap, con esto Nmap ejecuta un conjunto de scripts básicos de reconocimientos.
sudo nmap -n -Pn -p 22,80 -sC 192.168.50.155
sudo nmap -n -Pn -p 22,80 -sC 192.168.50.155
Como se muestra en la imagen se está ejecutando PHP en el servicio HTTP.

Veamos que despliega el navegador web al visitar la web que se está ejecutando en el servicio nginx (Puerto 80).
login webpage
Login Page
Como se muestra en la imagen anterior se despliega un sitio web con la tematica de un banco online, también se muestra un formulario web de login. Ahora veamos si el sistema de autenticación es vulnerable a inyección SQL. Para esto utilizaré algunas payload básicos. El primero que utilizaré es el siguiente.
Payload ' OR 1=1-- - 
Home Banking
Página de inicio de Habor Bank Online
Nuestro primer payload dio buenos resultados ya estamos dentro del sistema.
Local File Inclusio
Como vemos en la imagen anterior la URL procesa un parámetro llamado 'p' se pueden probar varias vulnerabilidades. La primera que probaré será la vulnerabilidad LFI (Local File Inclusion). probaré la siguiente solicitud index.php?p=/etc/passwd.
LFI (Local File Inclusion)
Prueba: LFI (Local File Inclusion)
Como se muestra en la imagen, la página web no muestra el contenido del archivo passwd. En este punto puede ser que se este concatenando la la extensión .php o se este implementando una lista blanca de los argumentos que pueden ser procesadas por la variable 'p'

Ahora probaré la vulnerabilidad de inyección de byte null, esto consiste en agregar el carácter %00 (caracter byte null) al final de la URL en este caso index.php?p=/etc/passwd%00Esta vulnerabilidad consiste en marcar el final de una cadena con el caracter %00. Por lo tanto, cuando el sistema procesa una URL que contiene %00, lo interpreta como si la URL terminara ahí mismo, ignorando cualquier cosa que venga después. Con esta prueba comprobaré si la URL esta concatenando la extensión .php o si la aplicación gestiona correctamente los byte null
LFI Byte Null
Prueba: LFI (Local File Incluso) con Byte Null
La aplicación al parecer está gestionando correctamente la vulnerabilidad Byte Null.

Hasta el momento sabemos que la URL a través del parámetro 'p':
  • Procesa las diferentes vista (página web) como un único punto de entrada a la aplicación web.
  • Sabemos que la aplicación web está programada en PHP.
  • Sabemos que la aplicación web no es vulnerable a LFI (Local File inclusion).
  • Sabemos que la aplicación web no es vulnerable a inyección Byte Null.
Ahora solo queda probar si la aplicación puede procesar instrucciones PHP y utilizar PHP wrapper. Un wrapper es una especie de envoltura que le dice a la entrada / salida de datos como debe comportarse.

Uno de los PHP wrapper que podemos probar es php://filter/convert.base64-encode/resource=[recurso php].
  • php://filter: Es un wrapper especial en PHP que permite aplicar filtros a recursos como archivos.
  • convert.base64-encode: Es el filtro que se aplica, en este caso para codificar en Base64.
  • resource=...: Especifica el recurso (archivo) al cual se le aplicará el filtro.
PHP Wrapper
Prueba: PHP Wrapper.
La aplicación ejecuta código PHP y nos devuelve el contenido del recurso solicitado, en este caso el recurso welcome en formato base64. Ahora queda descodificar la cadena en base64.

Lo que haré es copiar la cadena en base64 y la decodificaré con la función base64 -d  de Linux como se muestra en la siguiente imagen.
base64 -d Linux
Decode base 64
Los wrapper de PHP nos dio buenos resultados. Ahora solo resta decodificar los resto de recursos de la aplicación web y analizar si encontramos algo interesante.
decode-wrapper-base64-balance
DEcode-base64-balance
En el recurso balance encontramos las credenciales de conexión a base de datos (root:TestPass123!), el gestor base de datos es Mysql y el nombre de la base de datos es HarborBankUsers.

Ahora probaré si la aplicación web es vulnerable a SSRF (Server-Site Request Forgery). Sabemos que la aplicación tiene un único punto de entrada para cargar las diferentes vista (página web). Entonces lo que haré es servir un recurso web y solicitarlo desde la aplicación web de la siguiente manera.

Primero, crearé un archivo en mi máquina atacante llamado balance.php.
SSRF test
Ahora serviré el archivo balance.php de la siguiente manera.
Python -m http.server 80
El servicio web lo debemos ejecutar en el mismo directorio dónde este almacenado el archivo balance.php.

Ahora solicitaré el recurso balance.php desde la aplicación web si se muestra la frase 'Hola Mundo!' indica que la web es vulnerable a la vulnerabilidad SSRF.
Test - SSRF
La aplicación web es vulnerable a SSRF, ahora realizaré una modificación en el archivo balance.php para ejecutar comandos de forma remota.

Modificaré nuevamente el recurso balance.php para listar las interfaces de red configurada en la máquina objetivo.
ipconfig
Ahora solicitaré el recurso balance.php si todo va bien debería de mostrar las interfaces de red.
Network interface
Recordemos que cuando realizamos el reconocimiento de red la máquina objetivo tenía la dirección IP 192.168.50.155 y como se muestra en la imagen anterior la interfaz de red que ejecuta la aplicación web es  172.20.0.7. Esto indica que la aplicación se está ejecutando en un entorno virtualizado.

Ahora debemos averiguar en que entorno se está ejecutando la aplicación web. Para esto listaremos los archivos de la raíz del sistema. Para eso modificaremos nuevamente nuestro archivo balance.php.
ls -la /
file list /root
Al parecer el entorno de virtualización es Docker. Ahora intentaré de obtener una reverse-shell. El objetivo en este punto es acceder remotamente a la máquina virtualizada, para poder maniobrar de una manera más cómoda.

Para obtener una reverse-shell utilizaré un script PHP creado por pentestmonkey.
reverse-shell.php
Los únicos cambios que debemos hacer son lo indicados en la imagen anterior. Recuerda cambiar el nombre del archivo por balance.php.

Luego debemos servir este recurso de la siguiente manera.
python-server-reverse-shell
En nuestra máquina atacante pondremos a la escucha el puerto número 1234 en mi caso.
Por último, realizamos la solicitud a nuestro recurso balance.php.
solicitud-reverse-shell
Al solicitar el recurso deberíamos de recibir una conexión desde la máquina virtual a nuestra máquina atacante.
conexión reversa
Ahora que tenemos acceso a la máquina virtualizada desde la máquina atacante y sabiendo que se está ejecutando la aplicación web sobre un contenedor Docker, revisaremos si la máquina tiene acceso a otras interfaces de red. Para averiguar esto realizaré un volcado de la tabla ARP de la máquina virtual.
volcado ARP máquina objetivo
Como se ve en la imagen anterior nuestra máquina virtual tiene acceso a otros dispositivos. Por otro lado, nuestra máquina atacante no tiene directamente acceso a estos otros dispositivo, por lo tanto, debemos de tunelizar las conexiones para lograr tener acceso a los otros dispositivos desde nuestra máquina atacante.

Para tunelizar las conexiones desde nuestra máquina atacante y a la máquina virtual y al resto de los dispositivos utilizaremos la herramienta chisel.

Para tunelizar las conexiones necesitamos ejecutar chisel en nuestra máquina atacante como servidor y en nuestra máquina virtual la ejecutaremos como cliente. Cabe mencionar que, una vez tunelizadá las conexiones, debemos utilizar una segunda herramienta proxychains. Proxychains nos permite ejecutar nuestra distintas herramientas de hacking a través del túnel creado con chisel.
graphic-chisel
Gráfico: Uso Chisel y proxychains

Antes de configurar nuestro túnel con chisel, debemos generar una nueva conexión desde nuestra maquina virtual a nuestra maquina atacante. Lo haremos de la siguiente manera.

Primero modificaremos nuestro balance.php (que es nuestro reverse-shell.php, que lo renombramos a balance.php) los cambiamos que haremos serán los siguientes.
modificación-reverse-shell.php
Una vez modificado el archivo balance.php debemos enviarlo a nuestra máquina virtual. Lo haremos de la siguiente manera.

En nuestra máquina atacante ejecutaremos un servidor web con Python en el mismo directorio donde guardamos nuestro balance.php modificado.
Servidor Python
Ahora desde la máquina virtual descargaremos el recurso balance.php (modificado), de la siguiente manera.
wget
Como se muestra en la imagen lo primero que haremos es cambiar al directorio /tmp y luego con la utilidad wget solicitaremos el recurso balance.php de nuestra máquina atacante.

Ahora desde nuestra máquina atacante pondremos a la escucha el puerto 8080 el mismo que configuramos en el archivo balance.php.
nc -l -p 8080
Por último, desde nuestra máquina objetivo ejecutamos el archivo balance.php, de la siguiente manera.
nohup php balance.php &
En este punto me detendré a explicar algunas cosas.
  • La instrucción nohup de Linux, permite ejecutar scripts o procesos sin que se interrumpa si cierras la terminal. El & (ampersand) se utiliza para enviar el proceso a segundo plano.
Una vez ejecutado el script balance.php recibiremos una conexión reversa desde la máquina virtual a nuestra máquina atacante.
reverse-shell-php
Ahora toca el turno de chisel, es decir, crear nuestro túnel. Recuerden que chisel es un script que puede funcionar como servidor (para recibir conexiones) y también puede funcionar como cliente (para generar conexiones a nuestro chisel servidor) esta funcionalidad de chisel permite crear nuestro túnel.

Ahora configuraremos chisel en modo servidor en nuestra máquina atacante.
chisel-server
Ahora ejecutaremos chisel en la máquina objetivo como cliente. Primero debemos enviarnos el archivo chisel desde nuestra máquina atacante a la máquina virtual.

Ejecutaremos nuevamente un servicio web en el mismo directorio donde almacenamos el archivo chisel.
servidor python
Desde nuestra máquina objetivo solicitaremos el recurso chisel.
chisel-client
Ahora debemos darle permiso de ejecución al archivo chisel.
chmod +x chisel
Por último, ejecutamos chisel modo cliente en nuestra máquina objetivo.
chisel ejecutado modo cliente
Si el túnel se creo con éxito en nuestra máquina atacante debemos ver una sesión activa.
chisel-sesion-activa
Una vez establecido el túnel debemos configurar proxychains para que utilicé nuestro túnel de conexión. El archivo de configuración se encuentra en el directorio /etc/proxychains4.conf.
configuración-proxychains
Ahora ejecutaré nmap para descubrir otros hosts y servicios que se estén ejecutando.
proxychains-nmap
Algo importante a mencionar es que, debemos ejecutar la herramienta como usuario root, y además, para que nmap nos de resultado fiables debemos ejecutar el tipo de escaneo -sT (TCP connect). 
Como se muestra en la imagen anterior hice un barrido de IP en el segmento de red 172.20.0.1 a 172.20.0.254 al puerto 80. La idea con este escaneo es generar tráfico para que quede cachea en la tabla ARP de la máquina virtual.      
Como se muestra en la imagen, la tabla ARP de nuestra máquina objetivo muestra más información. Esto se debe a que hemos tunelizado la máquina donde se ejecuta la aplicación web vulnerable. Por lo tanto, todo el tráfico de red que se genere desde nuestra máquina atacante hacia la máquina virtual y hacia el resto de las máquinas en el segmento de red quedará cacheado en la tabla ARP de la máquina virtual.

En la máquina con dirección IP 172.20.0.124 se está ejecutando Elasticsearch, por defecto elasticsearch escucha por los puertos 9200-9300. La máquina con dirección IP 172.20.0.2 se está ejecutando Kibana, por defecto kibana escucha el puerto 5601.

Ahora veremos los puertos de Elasticsearch y kibana están abierto.
Elasticsearch
Escaneo de puertos servicio ElasticSearch.

Kibana
Escaneo de puertos servicio Kibana.
Como se muestra en las imágenes anteriores, Kibana tiene el puerto 5601 cerrado. Por otro lado, sabemos que Elasticsearch se está ejecutando en el puerto 9200, que es utilizado para servir su API REST. Además, el puerto 9300 es el puerto de transporte predeterminado que usan los nodos de Elasticsearch para comunicarse entre sí dentro de un clúster.

Ahora configuraré mi navegador para probar e interactuar con la API REST de Elasticsearch. Para configurar nuestro navegador web desde el menú hacemos click en Setting->Network Settings.
configuracion chisel en firefox
Recuerden que nuestro túnel se está ejecutando en la IP 127.0.0.1 1080.

Una vez configurado nuestro navegador web solicitaremos la dirección IP 172.20.0.124:9200.
API-Elasticsearch
Como se muestra en la imagen pudimos acceder al servicio de API de Elasticsearch, en la imagen se muestra la versión de Elasticsearch 1.4.2. Por lo tanto, buscaré si hay disponible algún exploit para esta versión de ElasticSearch.
exploit Elasticsearch
view exploit elasticsearch
Utilizaremos el primer exploit, este exploit nos permite obtener una consola interactiva. Para ejecutar el exploit necesitamos tener instalado Python 2. Ahora descargaré el exploit de la siguientes manera.
Ejecutaré el exploit para ver las opciones que nos pide el exploit para su ejecución.
ejecucion-exploit-elasticsearch
El exploit solo nos pide la dirección IP de la máquina objetivo. entonces lo ejecutaré nuevamente proporcionando la dirección de la máquina virtual.
Proxychains exploit elasticsearch
Recordar que el exploit debemos ejecutarlo a través de proxychains: proxychains python2 36337.py 172.20.0.124. Como se muestra en la imagen, el exploit nos devuelve una consola interactiva.
Exploit elasticsearch
Nuestra consola interactiva es root y la dirección IP 172.20.0.124. Esta no es la máquina objetivo, nuestra máquina objetivo tiene la dirección IP 192.168.50.155, en mi caso. Lo que hicimos fue pivotear (saltar) a otro contenedor que se están ejecutando en nuestra máquina objetivo.

Al revisar el archivo /root/.bash_history, se observa que desde está máquina (Elasticsearch) se realizan peticiones a través de CURL al contenedor 172.0.0.1:2375.
Curl 172.20.0.1:2375
El puerto 2375 es utilizado por Docker Engine API que permite a los administradores gestionar y administrar la diferentes imágenes que se estén ejecutando en Docker.

Como no tenemos conectividad directa a este contenedor debemos enrutar la conexión de este contenedor a nuestra máquina atacante. Para relaizar está operación utilizaremos la herramienta socat. Socat, es una herramienta que permite redirigir, conectar y manipular flujos de datos entre dos máquinas.
socat
Para ejecutar socat desbemos enviarnos el archivo socat contenedor docker con dirección IP 172.20.0.7 donde se esta ejecutando la aplicación web online Banking.
socat 172.20.0.6
Luego debemos darles permiso de ejecución.
chmod +x socat
Por último, debemos ejecutarlo de la siguiente manera.
ejecución socat
Ahora me detendré a explicar las opciones de ejecución de socat. 
  • TCP-LISTEN:6565: Escucha conexiones entrantes en el puerto 6565 en la máquina local usando el protocolo TCP.
  • fork: Indica que por cada conexión entrante, socat creará un proceso hijo separado, permitiendo manejar múltiples conexiones al mismo tiempo.
  • TCP:192.168.50.197:2234Cuando llega una conexión al puerto local 6565, socat la redirige (forwardea) al host 192.168.50.197, puerto 2234, usando TCP. esta última instrucción redirige la conexión a nuestra maquina atacante donde se está ejecutando Chisel por el puerto 2234.
chisel-socat
Ahora en el contenedor donde se está ejecutando Elasticsearc con IP 172.20.0.124. Debemos ejecutar la herramienta Chisel de la siguiente manera.
Chisel- Elasticsearch
  • Se está ejecutando Chisel en modo cliente 172.20.0.7:6565, es la dirección IP y puerto donde está corriendo el servidor Chisel, en este caso socat. Esto significa que el cliente intentará conectarse al servidor 172.20.0.7 por el puerto 6565.
  • R:8080:socksREspecifica un remote port forward. Significa que el puerto se abrirá en el lado del servidor (no del cliente). 8080, Es el puerto en el servidor (172.20.0.7) que quedará expuesto, socks indica que ese puerto 8080 actuará como un proxy SOCKS5.
Si todo está bien configurado, en nuestra máquina atacante deberíamos ver las siguientes conexiones.
conexiones chisel activas
Por último debemos configurar nuestro proxychains.
proxychains-dynamic
proxychains túneles
Es muy importante el orden en que se configuran los túneles en proxychains, como se muestran en la imagen las conexiones (túneles) se deben apilar.

Ahora teniendo acceso desde nuestra máquina atacante al contenedor con IP 172.20.0.1 API Docker. listaré las imágenes (contenedores) que están desplegados.
Listar-imagenes-docker-172.20.0.1
Como se muestra en la imagen anterior se pueden observar todas las imágenes (contenedores) que se están ejecutando. En este punto aún no tenemos acceso a la máquina objetivo. Por lotanto, lo que podríamos probar es montar una imagen que copie la raíz de la de la máquina objetivo que sabemos que tiene la dirección IP 192.168.50.155. Como no me manejo muy bien en Docker buscaré información en Hacktricks.
HackTricks Docker
Debemos ejecutar cada una de estas líneas que se muestran en la imagen con algunas modificaciones.
create container docker
Debemos modificar las siguientes partes de la instrucción.
  • curl –insecure -X POST -H "Content-Type: application/json" por curl -X POST -H "Content-Type: application/json". debemos eliminar la flag -insecure ya que no estamos utilizando el protocolo HTTPS.
  • https://tls-opendocker.socket2376/containers/create?name=test por http://172.20.0.1:2375/containers/create?name=test.Debemos modificar el protolos HTTPS por HTTP y apuntar a la IP 172.20.0.1:2375, es la dirección IP y puerto donde se está ejecutando la API REST de Docker.
  • -d '{"Image":"alpine", "Cmd":["/usr/bin/tail", "-f", "1234", "/dev/null"], "Binds": [ "/:/mnt" ], "Privileged": true}' por -d '{"Image":"alpine:3.2", "Cmd":["/usr/bin/tail", "-f", "1234", "/dev/null"], "Binds": [ "/:/mnt" ], "Privileged": true}'. Debemos cambiar la propiedad image a alpine:3.2, esto se debe que nos aprovecharemos de esta imagen para montar el directorio raíz de la máquina objetivo (IP 192.168.50.155).
Como resultado de ejecutar la instrucción anterior la API Docker nos devolverá un identificador.
id-imagen docker

start container docker
Luego, ejecutamos la instrucción que se muestra en la imagen anterior. Esta instrucción inicializa el contenedor.
exec command docker
Como se muestra en la imagen anterior se ejecuta el comando cat /mnt/etc/shadow/. La ejecución del comando nos devuelve un nuevo identificador, este identificado representa el resultado de ejecutar la salida del comando  cat /mnt/etc/shadow/. Para ver el resultado de ejecutar el comando cat/mnt/etc/shado/, debemos ejecutar la siguiente instrucción.
result cat /mnt/etc/shadow
Ahora estar trabajando de esta forma es muy difícil y conduce a errores. Ya que tenemos acceso a la máquina objetivo y sabemos que la máquina objetivo está ejecutando el servicio SSH. podríamos crear una clave pública SSH para conectarnos a través de SSH. Luego enviarla al directorio SSH.

Vamos a crear nuestra clave pública ssh de la siguiente manera.
ssh-keygen
Ahora que ya creamos nuestra clave pública SSH. Lo que haré será enviarla a nuestra máquina objetivo a través de la imagen Docker que creamos anteriormente.
public key ssh
 
send public key ssh
Ahora solo debemos conectarnos a través de SSH a nuestra máquina objetivo (IP 192.168.50.155).
conecction ssh
Ahora estamos conectado como root a nuestra máquina objetivo solo falta encontrar las flags.

Nota: Si se fijan en la imagen imagen me conecto como root@192.168.50.124 que no es la dirección IP que se muestra en la fase de reconocimiento de nuestra máquina objetivo que era 192.168.50.155. El motivo de este cambio de dirección IP es que tuve que reiniciar mis máquinas virtuales, por alguna razón estas no respondían.
flags

Flag.

Bonus flag
Bonus flags.

Esta máquina fue muy desafiante para mi e intente de explicar el proceso paso a paso lo más comprensible que fuese posible.

Happy Hack!!!

Comentarios