Auditoría de Seguridad C/C++ — NexusGate SDK v2.4.1

src/ · threat_model: REMOTE · severity_filter: medium+ · 8 workers · Trail of Bits methodology

SARIF 2.1.0
Ejecutado: 2026-06-16 09:14 UTC
Duración: 3m 42s · Modelo: claude-sonnet-4-5
Critical
2
TRUE_POSITIVE
High
4
TRUE_POSITIVE
Medium
5
TRUE_POSITIVE + LIKELY_TP
Filtrados
3
FALSE_POSITIVE / <medium
Total findings
11
14 raw → 11 post-dedup
Distribución por severidad
CRITICAL
2
HIGH
4
MEDIUM
5
Workers completados8 / 8
Deduplicaciones3 findings merged
Falsos positivos eliminados3 FP removidos
Clusters de bugs auditados
Worker Cluster Findings Estado
worker-1 buffer-write-sinks 3 ✓ completed
worker-2 integer-overflow 2 ✓ completed
worker-3 use-after-free 1 ✓ completed
worker-4 race-conditions 2 ✓ completed
worker-5 format-string 1 ✓ completed
worker-6 heap-alloc-errors 2 ✓ completed
worker-7 crypto-misuse 2 ✓ completed
worker-8 command-injection 1 ✓ completed
Hallazgos CRITICAL
CRITICAL Stack buffer overflow en parse_modbus_tcp_frame() via campo length sin validar src/modbus_parser.c:187 TRUE_POSITIVE
Bug Classbuffer-overflow
Attack VectorNETWORK
ExplotabilidadHIGH
Funciónparse_modbus_tcp_frame()
CWECWE-121
IDBUF-001

La función parse_modbus_tcp_frame() lee el campo length del encabezado MBAP directamente desde la red y lo usa sin validar como tamaño en memcpy() hacia un buffer estático en el stack de 256 bytes. Un atacante remoto puede enviar una trama Modbus con length=65535 provocando un desbordamiento clásico de stack con potencial de ejecución remota de código (RCE).

C · modbus_parser.c:183 // Lectura cabecera MBAP (6 bytes) uint16_t pdu_length = ntohs(*(uint16_t *)(buf + 4)); // Buffer estático, sin validar pdu_length uint8_t payload[256]; memcpy(payload, buf + 6, pdu_length); /* ← OVERFLOW si pdu_length > 250 */ return process_pdu(payload, pdu_length);
Impacto Control total del stack pointer. Con ASLR sin PIE (configuración por defecto en este SDK) un atacante puede redirigir el flujo de ejecución. Explotable desde la red sin autenticación previa (el parseo ocurre antes del handshake de sesión).
Remediación Validar pdu_length <= 250 antes del memcpy, o usar buffer dinámico con malloc(pdu_length) + comprobación de retorno. Compilar con -fstack-protector-strong y habilitar PIE (-fPIE -pie) como mitigación defensiva en profundidad.
CRITICAL Use-after-free en session_destroy() por carrera con session_send_heartbeat() src/session_manager.c:312 TRUE_POSITIVE
Bug Classuse-after-free
Attack VectorNETWORK (trigger remoto)
ExplotabilidadMEDIUM-HIGH
Funciónsession_destroy() / session_send_heartbeat()
CWECWE-416
IDUAF-001

El hilo de heartbeat (pthread) mantiene un puntero a la estructura session_t sin adquirir el mutex global antes de acceder a session->sock_fd. Si el hilo principal llama a session_destroy() y libera la sesión mientras el heartbeat está en tránsito, se produce un use-after-free con posibilidad de escritura controlada en heap.

C · session_manager.c:307 /* hilo heartbeat — SIN mutex */ void *heartbeat_thread(void *arg) { session_t *s = (session_t *)arg; while (s->alive) { /* ← s puede ser free()d */ send(s->sock_fd, PING, sizeof(PING), 0); /* ← UAF */ sleep(30); } }
Remediación Usar referencia contada (atomic_fetch_add + atomic_fetch_sub) sobre session_t, o adquirir session_mutex en el heartbeat antes de acceder a cualquier campo. Señalizar el hilo con pthread_cancel + join antes de llamar a free().
Hallazgos HIGH
HIGH Integer overflow en cálculo de tamaño de buffer MQTT antes de malloc() src/mqtt_client.cpp:94 TRUE_POSITIVE
Bug Classinteger-overflow
Attack VectorNETWORK
CWECWE-190
IDINT-001

La expresión topic_len * 2 + payload_len + 8 se calcula con tipos uint16_t. Si topic_len ≥ 32764, el resultado desborda a un valor pequeño y el malloc() reserva un buffer insuficiente. La escritura posterior de topic+payload provoca heap overflow con datos controlados por el broker MQTT (o un broker comprometido).

C++ · mqtt_client.cpp:90 uint16_t topic_len = topic.size(); uint16_t payload_len = payload.size(); size_t buf_sz = topic_len * 2 + payload_len + 8; /* ← overflow uint16 */ uint8_t *pkt = (uint8_t*)malloc(buf_sz); memcpy(pkt, topic.c_str(), topic_len); /* ← heap overflow */
Remediación Usar size_t para la aritmética, o __builtin_add_overflow / checked_add. Añadir assert(buf_sz < MQTT_MAX_PKT) y validar las longitudes máximas de topic (MQTT spec: 65535 bytes, pero el SDK debería limitar mucho menos).
HIGH Format string injection en log_session_error() — input no sanitizado src/session_manager.c:156 TRUE_POSITIVE
Bug Classformat-string
Attack VectorNETWORK
CWECWE-134
IDFMT-001

El mensaje de error recibido del cliente (campo error_msg en el handshake) se pasa directamente como formato a fprintf(). Un atacante puede incluir especificadores de formato como %n para escrituras arbitrarias en memoria o %s%s%s%s para lectura de stack.

C · session_manager.c:154 /* error_msg viene del cliente remoto */ char *error_msg = parse_handshake_error(buf); fprintf(stderr, error_msg); /* ← FORMAT STRING INJECTION */
Remediación Cambiar a fprintf(stderr, "%s", error_msg). Compilar con -Wformat-security -Werror para detectar este patrón en el futuro.
HIGH Token JWT comparado con strcmp() — timing oracle en auth.c src/auth.c:78 TRUE_POSITIVE
Bug Classcrypto-misuse (timing-oracle)
Attack VectorNETWORK
CWECWE-208
IDCRYPT-001

La validación de tokens de sesión usa strcmp() en lugar de una comparación en tiempo constante. Mediante mediciones de latencia de red (~100 ms por byte) es teóricamente posible deducir el token byte a byte. El riesgo es bajo en redes con jitter pero presente en redes LAN industriales de baja latencia.

Remediación Usar mbedtls_ct_memcmp() o CRYPTO_memcmp(). Verificar longitud antes de comparar para evitar timing leaks adicionales.
HIGH malloc() sin comprobar NULL — crash DoS en sesiones concurrentes src/session_manager.c:203 TRUE_POSITIVE
Bug Classheap-alloc-errors
Attack VectorNETWORK (agotamiento de memoria)
CWECWE-476
IDHEAP-001

session_alloc() llama a malloc(sizeof(session_t)) y desreferencia el puntero inmediatamente sin comprobar si es NULL. Bajo presión de memoria (más de ~2.000 sesiones concurrentes o ataque de agotamiento de recursos), el gateway crashea con SIGSEGV sin posibilidad de recuperación.

Remediación Añadir if (!s) { log_error("OOM"); return NULL; } tras cada malloc(). Implementar un pool de sesiones con límite configurable para prevenir el agotamiento.
Hallazgos MEDIUM
ID Título Ubicación Bug Class CWE Veredicto
INT-002 Off-by-one en lectura de registro Modbus holding modbus_parser.c:241 integer-overflow CWE-193 LIKELY_TP
BUF-002 strncpy() no garantiza terminación null en topic MQTT mqtt_client.cpp:167 buffer-write-sinks CWE-120 TRUE_POSITIVE
RACE-001 TOCTOU en check+uso de archivo de configuración TLS auth.c:134 race-conditions CWE-367 LIKELY_TP
CRYPT-002 IV fijo en cifrado AES-CBC para tokens en reposo auth.c:89 crypto-misuse CWE-329 TRUE_POSITIVE
CMD-001 Ruta de certificado pasada a system() sin sanitizar auth.c:201 command-injection CWE-78 TRUE_POSITIVE
REPORT.sarif — extracto
"$schema": "https://json.schemastore.org/sarif-2.1.0.json",
"version": "2.1.0",
"runs": [{
  "tool": {
    "driver": {
      "name": "c-review",
      "version": "1.0.0",
      "informationUri": "https://github.com/trailofbits/skills"
    }
  },
  "results": [
    {
      "ruleId": "BUF-001",
      "level": "error",
      "message": { "text": "Stack buffer overflow in parse_modbus_tcp_frame() via unchecked MBAP length field" },
      "locations": [{ "physicalLocation": { "artifactLocation": { "uri": "src/modbus_parser.c" }, "region": { "startLine": 187 } } }],
      "properties": { "severity": "CRITICAL", "fp_verdict": "TRUE_POSITIVE", "attack_vector": "NETWORK" }
    },
    {
      "ruleId": "UAF-001",
      "level": "error",
      "message": { "text": "Use-after-free in session_destroy() racing with heartbeat thread" },
      "locations": [{ "physicalLocation": { "artifactLocation": { "uri": "src/session_manager.c" }, "region": { "startLine": 312 } } }],
      "properties": { "severity": "CRITICAL", "fp_verdict": "TRUE_POSITIVE", "attack_vector": "NETWORK" }
    },
    /* … 9 resultados más … */
  ]
}]