Logo GR58

LabSoftware GR58

🚀 Plataforma Interactiva v3.1

LabSoftware GR58

Bienvenido al laboratorio interactivo de pruebas de software. Diseñado para entrenar y evaluar tus habilidades en fuzzing guiado por cobertura, análisis forense de corrupción de memoria y gestión de crisis regulatorias de ciberseguridad.

🛡️ Explorar Sandbox
Ilustración LabSoftware GR58

El Laboratorio de Fuzzing en Vivo

Experimenta en tiempo real cómo funciona un fuzzer guiado por cobertura sobre código Java. Controla CMPLOG, ajusta estrategias y observa cómo los sanitizers revelan corrupciones que de otro modo serían invisibles.

Concepto ¿Qué es un Fuzzer Guiado por Cobertura?

Es una herramienta de pruebas de caja gris automatizada que inyecta entradas mutadas al programa objetivo. Al registrar las rutas de código alcanzadas (cobertura), decide si una mutación es útil: si descubre una nueva rama o bloque de ejecución, esa entrada se guarda como semilla en el Corpus para seguir mutando a partir de ella. Esto permite resolver ramas complejas automáticamente sin conocer de antemano el código fuente.

Código Objetivo (Java) y Cobertura

PacketParser.java
1public class PacketParser {
2    // Estructura del protocolo binario:
3    // [Bytes 0-1]: declaredLength | [Byte 2]: divisor | [Bytes 3-6]: Magic Signature (0xCAFEBABE) | [Bytes 7+]: Payload
4    public void parsePacket(byte[] data) {
5        // Validación 1: Verificar si el buffer de entrada es nulo (CWE-476)
6        if (data == null) {
7            throw new NullPointerException("El buffer de datos de entrada es nulo");
8        }
9        
10        // Validación 2: El paquete debe contener al menos el encabezado completo (8 bytes)
11        if (data.length < 8) {
12            return; // Retorno temprano si el paquete es demasiado pequeño
13        }
14        
15        // Extracción de Campos del Encabezado:
16        // declaredLength: Indica cuántos bytes de payload se supone que vienen a continuación
17        int declaredLength = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
18        
19        // divisor: Valor utilizado para calcular la tasa de procesamiento
20        int divisor = data[2] & 0xFF;
21        
22        // Simulación de cálculo aritmético vulnerable a división por cero (CWE-369)
23        int ratio = 100 / divisor; // Arroja ArithmeticException si divisor == 0
24        
25        // signature: Firma mágica de control para validar el origen del paquete
26        int signature = ((data[3] & 0xFF) << 24) | ((data[4] & 0xFF) << 16)
27                      | ((data[5] & 0xFF) << 8) | (data[6] & 0xFF);
28                      
29        // Validación 3: Comprobación de la Firma Mágica (Fase crítica para CMPLOG)
30        if (signature != 0xCAFEBABE) {
31            return; // Firma incorrecta, abortar procesamiento silenciosamente
32        }
33        
34        // Validación de consistencia de memoria (CWE-1284 / CWE-190):
35        if (declaredLength < 0) {
36            throw new NegativeArraySizeException("Longitud declarada negativa: " + declaredLength);
37        }
38        
39        // Reserva de memoria en el Heap para almacenar el payload del paquete
40        byte[] payload = new byte[declaredLength];
41        
42        // Copia de bytes desde el buffer físico al payload reservado
43        // Vulnerabilidad: Lectura fuera de límites (CWE-125 / OOB Read) si declaredLength > (data.length - 7)
44        System.arraycopy(data, 7, payload, 0, declaredLength); // Crash ASan
45    }
46}
Grafo de Control de Flujo (Cobertura de Bloques)

💡 Haz clic en cualquier bloque (B1-B4) para ver detalles técnicos de la fase.

B1
B2
B3
B4
El fuzzer comienza ejecutando la semilla base y alcanzando solo el bloque inicial **B1** (Validación de longitud de entrada).

🛠️ Tres Formas de Uso de Fuzzing en Pruebas de Software

1. Pruebas de Regresión de Seguridad en Integración Continua (CI/CD)

Se configuran herramientas como CIFuzz o AFL para que ejecuten automáticamente en cada commit un corpus de prueba previamente minimizado. Esto asegura de forma instantánea que ningún parche o refactorización reintroduzca una vulnerabilidad conocida del pasado.

2. Auditorías de Robustez de Protocolos de Red (Parsers)

El fuzzer envía ráfagas de paquetes malformados con longitudes incorrectas, campos de opción corruptos o firmas inválidas a los sockets de un servicio activo. Se utiliza para descartar desbordamientos lógicos y fallos de denegación de servicio (DoS) en pasarelas críticas antes del despliegue.

3. Validación de Parsers de Archivos Propietarios y Binarios

Se fuzzear motores que procesan archivos complejos (como PDF, JSON, XML o imágenes) mutando bytes estructurales. Su objetivo es detectar punteros nulos, divisiones por cero y corrupción de heap antes de que un archivo malicioso pueda evadir la seguridad sandbox.

Teoría: Fuzzing guiado por Cobertura

¿Por qué la cobertura guía la búsqueda? El fuzzer registra qué bloques de código se ejecutan con cada entrada. Si una mutación descubre un bloque nuevo (cobertura incrementada), guarda esa entrada como una nueva "semilla" para mutarla en el futuro. Esto le permite resolver ramas complejas.

El papel de CMPLOG y los Sanitizers: CMPLOG analiza las operaciones de comparación de datos de manera dinámica y extrae los valores que fallan en los condicionales (como 0xCAFEBABE), añadiéndolos directamente al corpus de mutación para abrir ramas nuevas en segundos. Los Sanitizers son fundamentales porque interceptan accesos ilegales a memoria (desbordamientos lógicos, fugas) en el momento exacto en que ocurren. Si desactivas los sanitizers, la JVM o el sistema operativo podrían continuar la ejecución con datos corruptos y el bug ocurriría silenciosamente (sin crash visible en el fuzzer), haciendo imposible su detección automática.

Selector de Técnica de Pruebas

Entrena tu criterio de selección. Arrastra los diferentes tipos de fallas de seguridad a la herramienta o técnica idónea para detectarla. Las técnicas no compiten: se complementan.

Vulnerabilidades y Escenarios de Fallo

Analiza cada uno de los siguientes casos y arrástralos a la zona de la herramienta técnica adecuada para su detección.

Desbordamiento lógico y lectura fuera de límites (OOB Read)
Se copian bytes basándose en el parámetro de longitud de una cabecera de red sin validar el tamaño físico de los bytes.
Bug Dinámico
Contraseñas hardcodeadas y secretos en el código fuente
Un desarrollador dejó la clave privada de producción de AWS hardcodeada directamente en la configuración del conector.
Estático
Vulnerabilidad conocida en librería de parseo JSON (Log4j / Gson)
El sistema utiliza una versión obsoleta de la librería de serialización que tiene asignada una vulnerabilidad crítica CVE-2023-XXXX.
Terceros
Fallo en la lógica de Autorización y Broken Access Control
Al modificar el parámetro userId=123 a userId=124 en la URL HTTP, el servidor devuelve datos del usuario 124 sin estar logueado.
Web / API
Corrupción de memoria por Use-After-Free (UAF) en C/C++
Un objeto del sistema de gráficos de red es liberado de memoria pero un callback activo intenta llamarlo milisegundos después.
Memoria
Inyección SQL por concatenación directa de parámetros
Un Query SQL concatena directamente un string de entrada: "SELECT * FROM users WHERE name = '" + name + "'".
Estático
Reflected Cross-Site Scripting (XSS) en buscador web
Un buscador web renderiza de inmediato el texto ingresado en el input de búsqueda sin sanitizarlo ni escapar caracteres HTML.
Web / API
Violación de Licencias GPLv3 (Non-compliance legal)
El equipo incluye una dependencia sujeta a licencia copyleft recíproca en un producto propietario cerrado y comercializable.
Terceros

Matriz de Técnicas de Seguridad

SAST
Static Application Security Testing (Escaneo de código fuente, reglas fijas)
DAST
Dynamic Application Security Testing (Pruebas externas sobre apps activas/HTTP)
Fuzzing + Sanitizer
Pruebas Dinámicas por Mutación de Entradas e Instrumentación de memoria
SCA
Software Composition Analysis (Chequeo de dependencias de código abierto)
El Criterio Integrador de Pruebas

Ninguna herramienta de seguridad detecta todo. La defensa en profundidad requiere entender las fortalezas y puntos ciegos de cada técnica:

  • SAST: Excelente para encontrar patrones en reposo (contraseñas en código, APIs deprecadas), pero genera muchos falsos positivos y no entiende la lógica dinámica real del flujo ni la interacción con memoria física.
  • DAST: Examina el software en ejecución desde fuera (enfoque de caja negra). Ideal para fallos de sesión y control de acceso (APIs expuestas), pero no cubre código interno ni desbordamientos de buffers internos no visibles externamente en la API.
  • Fuzzing: Genera miles de entradas estructuradas para forzar fallos profundos en parsers y capas de bajo nivel, siendo imbatible ante corrupciones de memoria y lógica del parser, pero inútil para lógica de negocio de alto nivel (como problemas de facturación).
  • SCA: No detecta vulnerabilidades propietarias. Simplemente mapea el inventario de dependencias (npm, maven, pip) contra bases de datos públicas de vulnerabilidades (CVE/NVD).

El Forense de Crashes (Triage y Causa Raíz)

El fuzzer ha generado una pila de ejecuciones fallidas. Tu trabajo es realizar el triage: agrupar por stack hash para deduplicar, minimizar el caso a su mínima expresión (estilo afl-tmin) y clasificar el tipo de fallo de acuerdo con el sanitizer.

El Triage de Crashes en el SSDF

Encontrar un crash con fuzzing es solo la mitad del trabajo. Para dar valor de negocio y cumplir con marcos de seguridad como el SSDF (Secure Software Development Framework - Grupo Respond), debes ser capaz de responder a un incidente de manera organizada:

  • Deduplicación: Un fuzzer puede generar 10,000 crashes en una noche, pero la mayoría son causados por la misma línea exacta de código vulnerable. Agruparlos por el hash de la traza de pila (stack hash) nos permite enfocarnos en los bugs únicos.
  • Minimización (afl-tmin): Los payloads de crash suelen venir con bytes inútiles que el fuzzer mutó aleatoriamente pero que no influyen en el fallo. Reducirlos al tamaño mínimo que reproduce el crash aisla el fallo exacto del parser.
  • Mapeo CWE & Severidad: Identificar el CWE correcto y calcular la métrica CVSS permite priorizar qué arreglar primero de acuerdo con el impacto corporativo.
  • Pruebas de Regresión: Guardar el caso minimizado en el corpus asegura que en cada integración continua (CI/CD) se vuelva a ejecutar esta prueba de regresión para garantizar que el bug no vuelva a ser introducido por accidente.

Análisis de Causa Raíz

Crash #001
Sanitizer Report Trace Hash: c1b52a
==10245==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300001fc40
READ of size 96 at 0x60300001fc40 thread T0
    #0 0x4012ab in parsePacket PacketParser.java:12
    #1 0x4018bc in main PacketFuzzerRunner.java:45
    #2 0x7f4b82 in libc_start_main.java:120
    
Payload raw content (Hex):
43 41 46 45 42 41 42 45 03 E8 41 41 41 41 41 41 41... [1024 bytes]
Minimización de Caso de Prueba (afl-tmin style) 1024 bytes

¿Qué es la minimización? El fuzzer inyecta bytes de relleno (como letras 'A') que no influyen en el crash. Desliza el control a la Zona Verde para limpiar el payload de bytes redundantes, aislando el fallo.

🔴 < 12B (Inválido) 🟢 12B - 32B (Óptimo / tmin) 🟡 > 32B (Ruido / Relleno)
Payload actual: "CAFEBABE..." Crash Activo
Vector de Ataque
Complejidad
Impacto Confidencialidad
Impacto Disponibilidad
Severidad CVSS: 9.8 (CRITICAL)
Propuesta de Parche (Java)

📖 Guía y Casos de Estudio del Triage Forense

Sigue esta guía interactiva paso a paso para depurar y resolver el Crash #001 en el simulador:

Paso 1: Agrupar por Firma (Deduplicación)

El fuzzer saca cientos de crashes, pero la mayoría son redundantes. Haz clic en "Deduplicar por Stack Hash" en la bandeja de entrada. Notarás que el Crash #003 y el Crash #005 se atenúan porque comparten el hash de stack trace (c1b52a) con el Crash #001, indicando que son el mismo bug. ¡Esto te ahorra horas de análisis!

Paso 2: Minimización del Payload (afl-tmin)

El fuzzer mutó bytes de relleno aleatorios (como letras 'A') que ensucian el caso de prueba. Arrastra el slider de minimización hasta la Zona Verde (entre 12 y 32 bytes). Verás que el payload se limpia pero el estado permanece en "Crash Activo". Si bajas a menos de 12 bytes, el caso fallará porque mutilas la firma CAFEBABE.

Paso 3: Diagnosticar la Causa Raíz y Parchear

Lee el log del sanitizer. Se detalla un error heap-buffer-overflow en la copia. Calcula la gravedad CVSS (Red, Baja, Alta, Alta -> 9.8 Crítica), asocia el CWE-125 (Out-of-bounds Read) y selecciona la propuesta de parche correcta en Java. Luego, haz clic en "Añadir caso minimizado al Corpus" para integrarlo en tu suite de regresión.

La Sala de Crisis (Respuesta y Regulación)

Dirige tu empresa de desarrollo de software ante un incidente crítico. Enfrenta la presión comercial, el reloj legal del Cyber Resilience Act (CRA) de la Unión Europea y el dilema real del bug de 20 años de SQLite. ¿Qué decisiones tomarás?

Elige tu Escenario de Crisis

Selecciona el contexto bajo el cual quieres operar la respuesta a incidentes de tu organización.

GR58