Canario DockerLabs (Hard)
Instalación
Cuando obtenemos el .zip
nos lo pasamos al entorno en el que vamos a empezar a hackear la maquina y haremos lo siguiente.
Nos lo descomprimira y despues montamos la maquina de la siguiente forma.
Info:
Por lo que cuando terminemos de hackearla, le damos a Ctrl+C
y nos eliminara la maquina para que no se queden archivos basura.
Escaneo de puertos
Info:
Vemos que solo tenemos un puerto que es una pagina web en la que pone Sube tu archivo
, si le damos al boton Subir archivo
veremos que podremos subir un archivo, por lo que intentaremos generarnos una reverse shell
con un archivo PHP
:
shell.php
Si subimos el archivo con la extension .php
nos lo bloqueara, pero si probamos a Bypassear
la extension con un .phar
y veremos que si nos deja.
Y ahora si lo subimos, nos pondra lo siguiente:
Vamos a realizar un poco de fuzzing
para ver donde puede estar nuestro archivo.
Escalate user www-data
Gobuster
Info:
Vemos que tendremos 2
carpetas llamadas /uploads
y /upload
, probemos a entrar a la primera carpeta y veremos que esta nuestro archivo, por lo que antes de ejecutarlo nos pondremos a la escucha:
Ahora si ejecutaremos el archivo desde la web y si vamos a donde tenemos la escucha veremos lo siguiente:
Veremos que somos el usuario www-data
, por lo que santizaremos la shell.
Sanitización de shell (TTY)
Escalate user jerry
Si hacemos sudo -l
veremos lo siguiente:
Veremos que podemos ejecutar el binario vim
como el usuario jerry
, por lo que haremos lo siguiente:
Info:
Y con esto veremos que seremos el usuario jerry
.
Escalate Privileges
Si hacemos sudo -l
veremos lo siguiente:
Vemos que podemos ejecutar el script suma
y con la herramienta python3
el script command_exec.py
como el usuario root
, por lo que haremos lo siguiente:
Si leemos el siguiente archivo flag.txt
que se encuentra en la carpeta command_exec
veremos lo siguiente:
Info:
Es interesante que ponga esa palabra, pero vamsos a seguir investigando, si ejecutamos lo siguiente:
Info:
No podremos hacer gran cosa, vamos a ver que hace el script por dentro:
Por lo que vemos si conseguimos que el .txt
consiga poner ACTIVE
podremos ejecutar el script y podremos ejecutar un comando, por lo que vamos a ejecutar el script de suma
a ver que hace.
Info:
Vamos a probar si pudieramos desbordar el buffer
de este binario.
Info:
Vemos alguna funcion rara, por lo que vamos a investigarlo de mejor forma en nuestro host
, nos vamos abrir un servidor de python3
para pasarnos el archivo suma
al host
.
Y ahora en nuestro host
nos lo descargaremos de la siguiente manera:
Vamos a ver un poco el codigo a pelo con la herramienta strings
.
Info:
Vemos varias cosas interesantes, entre ellas una palabra que parece ser la contraseña del software
:
Si lo probamos en la maquina victima:
Info:
Vemos que hace una suma de los numeros que metamos, pero no es interesante, vamos analizar las funciones que llama y que tiene, abriremos ghidra
, importaremos el binario y lo analizaremos, vemos que tiene un main
y un set_flag
que parece bastante interesante:
main.c
set_flag.c
Vemos que la funcion set_flag
esta cambiando la flag.txt
y poniendo ACTIVE
justo lo que buscamos, pero en ningun momento el programa llama a dicha funcion, por lo que tendremos que encontrar alguna vulnerabilidad como un Buffer Overflow
para poder llamar a dicha funcion, si investigamos un poco en el codigo vemos que puede haber una vulnerabilidad llamada Format String Vulnerability
en la siguiente linea:
El problema principal en el código es que se usa printf()
de manera incorrecta.
🔍 Qué está pasando en el código
La primera línea está bien:
printf("%s", &local_15f);
usa un formato seguro ("%s"
) y una variable que contiene un string.La segunda línea es el problema:
printf((char *)((long)&uStack_15b + 3));
usa la entrada del usuario directamente sin especificar un formato seguro.
Cuando ingresamos nuestro nombre en el programa, se usa nuestra entrada como formato de printf
, lo que significa que si escribimos %p
, %x
, %s
, etc., printf
intentará interpretarlo como un código especial en lugar de solo mostrar el texto.
🛠️ ¿Cómo podemos aprovechar esto?
Dado que printf()
está usando nuestra entrada directamente, podemos hacer cosas interesantes, como:
Filtrar información de la memoria (leak de direcciones)
Si ingresamos
%p
,%x
,%08x
, etc., veremos direcciones de memoria o datos internos del programa.
Modificar valores en memoria (usando
%n
)%n
le dice aprintf
que escriba el número de caracteres impresos en una dirección de memoria. Esto puede permitirnos sobrescribir valores importantes, como direcciones de retorno.
Vamos a ver que informacion nos muestra si ponemos varios %p
de la siguiente forma:
Info:
Vemos que nos esta mostrando varias direcciones de memoria.
Explorando el stack:
En un stack, los datos se almacenan de forma ordenada. Primero se guardan algunas variables locales, luego la dirección de retorno de las funciones (que es a dónde el programa vuelve después de ejecutar una función), y otros datos. Cada vez que llamamos a printf
con un %p
, le estamos diciendo a printf
que imprima una dirección que está en el stack.
Entonces, al enviar varios %p
como entrada, podemos leer las direcciones de memoria del stack, una por una. Esto es como leer las páginas de un libro para entender cómo está estructurado el programa.
Fuzzing con Bash:
Para hacer todo esto de forma automatizada, creamos un pequeño script en Python que envía muchas veces el formato %p
al programa y lee las direcciones de memoria una a una.
Este script puede ser como un explorador, leyendo diferentes partes de la memoria:
detect.sh
¿Qué hace el script?
Abre el programa vulnerable y le envía varios
%p
(uno por vez).printf
devuelve la dirección de memoria de cada%p
, y nosotros podemos leer esas direcciones.Imprime esas direcciones, que pueden ser valores como
0x7f...
o0x402051
, que nos dicen en qué parte de la memoria se encuentran ciertos datos.
Info:
Buscando el canario:
Ahora, cuando leemos estas direcciones de memoria, debemos buscar algo llamado canario. Los canarios son valores especiales que se colocan en el stack
para evitar que un ataque de buffer overflow sobrescriba cosas importantes, como la dirección de retorno de una función.
¿Cómo identificamos el canario? Los canarios tienen dos características muy específicas:
Son valores aleatorios (no son direcciones comunes).
Siempre terminan en
00
, lo que los hace fáciles de identificar.
¿Cómo los buscamos? Usamos el comando
grep
para filtrar las direcciones que terminan en00
. Esto nos ayuda a encontrar el canario entre las direcciones que estamos leyendo.
Info:
Esto filtra las direcciones que tienen la forma de un canario, y una vez que lo encontramos, sabemos que está cerca de la dirección de retorno en el stack
.
Si vamos al programa en C#
que obtuvimos anteriormente, podremos ver la longitud de buffer
que tiene el programa en la siguiente linea:
Por lo que vemos es una cantidad fija, ya que esta con char
, por lo que sabemos que el offset
del programa esta despues del numero 264
, por lo que vamos a montarnos un script en python3
para poder aprovechar todo esto.
¿Cómo explotamos la vulnerabilidad?
Para llevar a cabo un buffer overflow, necesitamos rellenar el buffer con suficientes bytes hasta que sobrescribamos el canario y la dirección de retorno (RIP).
264 bytes llenan el buffer.
8 bytes sobrescriben el canario.
8 bytes adicionales sobrescriben la dirección de retorno (RIP).
En total, necesitamos escribir 280 bytes para sobrescribir el canario y la dirección de retorno.
Lo que necesitamos para el ataque
Lo que queremos hacer es:
Sobrescribir el canario con el valor correcto para que el programa no detecte que ha sido modificado.
Sobrescribir la dirección de retorno (RIP) para que, en lugar de regresar a la función anterior, se ejecute la función
set_flag
.
Para hacerlo, necesitamos conocer el valor del canario, el cual hemos descubierto anteriormente que nos salen 2
por lo que tendremos que coger uno de los 2
, por ejemplo elegiremos el que esta en la posicion %69$p
.
Construcción del payload
Una vez que tenemos el canario, podemos construir el payload que enviamos al programa. El payload
se construye con una secuencia específica de bytes:
264 bytes de relleno (
'A' * 264
) para llenar el buffer.El valor del canario (que hemos obtenido previamente). Este es el valor correcto que debe ir en el lugar del canario para evitar que el programa lo detecte.
8 bytes de relleno (
'A' * 8
) hasta llegar a la dirección de retorno.La dirección de la función
set_flag
. Esta es la función que queremos ejecutar al sobrescribir la dirección de retorno.
Ejecución del payload
El siguiente paso es enviar el payload al programa vulnerable. Cuando el programa recibe los 264 bytes de relleno, sobrescribe el buffer sin que se active la protección del canario. Al añadir el valor del canario y sobrescribir la dirección de retorno con la dirección de set_flag
, logramos redirigir la ejecución del programa a esa función.
El exploit en Python con Pwntools
Usamos la librería Pwntools para facilitar la creación del payload y la interacción con el programa. Aquí está el código que construimos:
exploit.py
Explicación del código
Definir el binario: El binario vulnerable es
./suma
. UsamosELF()
depwn
para acceder a este binario y manipularlo (por ejemplo, obtener direcciones de funciones comoset_flag
).Obtener el canario: Usamos un formato
%69$p
para leer la dirección de memoria de la pila. Esto nos permite obtener el canario, que es un valor colocado para proteger la pila. Extraemos esta dirección del stack y la guardamos.Construir el payload:
Rellenamos hasta el canario: Usamos
'A' * 264
(tamaño del buffer) para llenar la memoria hasta el canario.Sobrescribimos el canario: Insertamos el canario extraído en el lugar correspondiente.
Sobrescribimos la dirección de retorno (RIP): Después de sobrescribir el canario, rellenamos hasta la dirección de retorno.
Redirigir la ejecución: Usamos la dirección de la función
set_flag
(obtenida desde el binario) para redirigir la ejecución del programa a esa función y obtener la flag.
Ejecutar el exploit: Enviamos el payload al binario vulnerable y, al ejecutar la función
set_flag
, logramos obtener la finalidad del ataque.
Ahora si nosotros ejecutamos esto en nuestro host
veremos que funciona y llama a la funcion:
Info:
Vemos que nos pone Flag activada
por lo que lo hemos echo de forma correcta, ahora vamos a copiar el codigo del script y pasarnoslo a la carpeta de /tmp
de la maquina victima y lo vamos a ejecutar de nuevo, tendremos que cambiar la ruta del binario por /opt/suma
:
Como necesitamos el modulo de pwn
y vemos que tenemos pip3
instalado, podremos instalarlo de la siguiente forma:
Y ahora si ejecutaremos el script.
Info:
Vemos que nos ha funcionado, ahora si leemos la flag.txt
:
Info:
Vemos que efectivamente a funcionado, por lo que habremos lo siguiente:
Info:
Ponemos bash
cuando nos ponga el ejecutar un comando y ya seremos root
, por lo que habremos terminado la maquina.
Last updated