libuhttpd: Stack Overflow en date2unix
Un header If-Modified-Since de 220 bytes desborda el buffer de stack buf[128] en date2unix. El resultado es un control del RIP con un decoder XOR montado en el propio stack. Análisis del sink, PoC y validación E2E completa.
+
00. Resumen Ejecutivo
libuhttpd es un pequeño servidor HTTP embebido extendido en aplicaciones de red (aplicaciones web de red, dashboards, gateways). Al servir un archivo estático comprueba la cabecera If-Modified-Since. El parser de fechas date2unix copia el valor de la cabecera a un buffer de 128 bytes sin comprobar la longitud de origen, con lo que un valor largo desborda el stack.
Como el valor de la cabecera es completamente controlable por el atacante y el desbordamiento escribe en el stack, se puede tomar control parcial del flujo. La ejecución de código depende de la toolchain (canarios, NX, ASLR), que en el despliegue embebido de referencia suele estar ausente o ser eludible.
01. 0x00 — El Sink: file.c date2unix
El bug es que el tamaño copiado viene dado por el origen (strlen(date)), no por el destino (sizeof(buf)). Un If-Modified-Since de más de 128 bytes empieza a sobrescribir el marco de stack de la función.
02. 0x01 — La Explotación (decoder XOR in-stack)
Para convertir el desbordamiento en control del RIP en la toolchain de referencia (sin canario), el shellcode se auto-decoda en el propio stack. La técnica: escribir el bytecode XOR in-stack para evitar bytes malos del parsing HTTP (espacios, línea nueva, etc.), y redirigir el RIP hacia allí.
La observación clave de la validación: bajo gdb (que usa ptrace) la dirección del stack era +0xC0 bytes distinta de la del run nativo. Solo reconstruyendo el layout en el run real se logró aterrizar el EIP en el shellcode. Este tipo de disparidad nativo/gdb es exactamente lo que el estándar E2E exige demostrar.
03. 0x02 — El PoC
El PoC es un GET con un If-Modified-Since de ~220 bytes. Una prueba limpia es el control de flujo con un valor guía:
04. 0x03 — Validación E2E (ASAN + gdb)
La validación reproducida:
05. 0x04 — Limitaciones de la Toolchain
| Mitigación | Impacto en el PoC |
|---|---|
| Canario (-fstack-protector) | Aborta antes del ret si está activo; no lo estaba en la toolchain de referencia |
| NX stack | Necesita el decoder+RIP ejecutable; en MCU embebido típicamente NX desactivado |
| ASLR | El layout in-stack es determinista (dirección fija), elude ASLR del heap/libs |
El fix en el mantenedor es copiar con un bound basado en el destino (strncpy(buf, date, sizeof(buf)-1) y terminar), o validar la longitud de la cabecera antes del parseo. Publicado con fines de hardening y comunicado al mantenedor como parte del proceso responsable.
06. 0x05 — Referencias
| Referencia | Descripción |
|---|---|
| file.c:136 | Sink date2unix: strncpy sin bound de destino |
| If-Modified-Since | Cabecera HTTP fuente del desbordamiento |
| CWE-121 | Stack-based Buffer Overflow |
| LECCION E2E | Disparidad de stack nativo vs gdb (+0xC0) — requiere run real |