Mobile, reverse & malware

Qu'est-ce qu'un buffer overflow - Mécanisme, exploitation, protections

Buffer overflow expliqué : stack vs heap, mécanisme d'écrasement, exploitation RCE, protections modernes (ASLR, DEP, canaries, CFG), détection ASan, prévention.

Naim Aouaichia
15 min de lecture
  • Buffer Overflow
  • Vulnérabilités
  • Exploitation
  • Memory Safety
  • C C++
  • Sécurité Binaire

Un buffer overflow (ou dépassement de tampon) est une vulnérabilité mémoire qui se produit lorsqu'un programme écrit plus de données dans une zone mémoire que sa taille allouée, débordant sur les zones adjacentes. Découverte dans les années 70, popularisée par le ver Morris en 1988 et le papier Smashing The Stack For Fun And Profit d'Aleph One en 1996, c'est l'une des vulnérabilités les plus emblématiques de la sécurité informatique. En 2026, malgré 40 ans de protections (ASLR, DEP, canaries, CFG, langages mémoire-safe), elle reste classée par MITRE parmi les CWE les plus dangereuses (CWE-787 Out-of-bounds Write en tête du Top 25 depuis 2021).

1. Définition technique précise

Un buffer overflow apparaît quand :

  1. Un programme alloue une zone mémoire (buffer) de taille fixe N octets.
  2. Une opération d'écriture y dépose plus de N octets.
  3. Les octets en surplus écrasent des données adjacentes (autres variables, métadonnées, pointeurs, code).

L'opération d'écriture peut être triviale (strcpy, gets, memcpy mal dimensionné), arithmétique (boucle qui dépasse), ou indirecte (fonction tierce ne respectant pas le contrat).

Conséquences possibles, par ordre de gravité :

  • Crash (segfault) - déni de service.
  • Corruption logique - écrasement d'une variable adjacente, modifie un comportement (ex. is_admin = 0is_admin = 1).
  • Détournement du flux d'exécution - écrasement d'une adresse de retour ou d'un pointeur de fonction → exécution arbitraire de code (RCE).

Les CWE associés :

  • CWE-787 : Out-of-bounds Write.
  • CWE-119 : Improper Restriction of Operations within the Bounds of a Memory Buffer (parent).
  • CWE-120 : Buffer Copy without Checking Size of Input (classic buffer overflow).
  • CWE-121 : Stack-based Buffer Overflow.
  • CWE-122 : Heap-based Buffer Overflow.
  • CWE-125 : Out-of-bounds Read (variante en lecture, ex. Heartbleed).

2. Architecture mémoire d'un processus

Pour comprendre un buffer overflow, il faut visualiser la disposition mémoire d'un processus Linux x86-64 typique :

+--------------------+ adresses hautes
|       Stack        |  ← grandit vers le bas
|       ↓↓↓          |
+--------------------+
|         |          |
|         ↓          |
|     (libre)        |
|         ↑          |
|         |          |
+--------------------+
|        Heap        |  ← grandit vers le haut
|       ↑↑↑          |
+--------------------+
|        BSS         |  variables globales non init
+--------------------+
|       .data        |  variables globales init
+--------------------+
|       .text        |  code (read + execute)
+--------------------+ adresses basses
  • Stack : variables locales, paramètres de fonction, adresses de retour. Allocation/libération automatiques (LIFO).
  • Heap : allocations dynamiques (malloc, new). Gérées explicitement.
  • BSS / .data / .text : segments statiques.

Un overflow sur la stack et sur le heap exploite des structures différentes - d'où la distinction stack-based vs heap-based.

3. Stack-based buffer overflow

Le cas d'école, et historiquement le plus exploité.

3.1 Mécanisme

Quand une fonction est appelée, le CPU pousse l'adresse de retour sur la pile, puis la fonction réserve de l'espace pour ses variables locales. Une fois finie, la fonction restaure l'état et ret saute à l'adresse de retour stockée.

Si une variable locale est un buffer mal protégé et qu'on écrit au-delà, on peut écraser l'adresse de retour. À la sortie de la fonction, le CPU saute vers l'adresse maintenant contrôlée par l'attaquant.

3.2 Code vulnérable classique

#include <stdio.h>
#include <string.h>
 
void vulnerable(char *input) {
    char buffer[64];
    strcpy(buffer, input);  // pas de borne, faille
    printf("Reçu: %s\n", buffer);
}
 
int main(int argc, char **argv) {
    if (argc > 1) vulnerable(argv[1]);
    return 0;
}

Si argv[1] fait 200 octets, strcpy écrira 200 octets dans un buffer de 64 - les 136 octets en trop écrasent ce qui suit sur la pile : autres locales, sauvegarde de RBP, puis l'adresse de retour.

3.3 État de la pile après débordement

Pile avant strcpy :          Pile après strcpy d'un payload long :
+-------------------+        +----------------------------------+
|  ret address      |        |  AAAAAAAA (écrasé)              |
+-------------------+        +----------------------------------+
|  saved RBP        |        |  AAAAAAAA (écrasé)              |
+-------------------+        +----------------------------------+
|  buffer[63]       |        |  A                              |
|     ...           |        |     ...                         |
|  buffer[0]        |        |  A                              |
+-------------------+        +----------------------------------+

L'attaquant choisit son payload pour que les octets qui tombent sur l'adresse de retour pointent vers du code qu'il maîtrise (shellcode injecté dans le buffer ou - aujourd'hui - une chaîne ROP).

3.4 Fonctions C dangereuses

Les coupables historiques. À éviter ou à utiliser avec extrême prudence :

Fonction dangereuseAlternative recommandée
gets()fgets(buf, sizeof(buf), stdin) (ou supprimée en C11)
strcpy()strncpy() ou mieux strlcpy() (BSD), snprintf()
strcat()strncat(), strlcat()
sprintf()snprintf(buf, sizeof(buf), ...)
scanf("%s", ...)scanf("%63s", ...) avec largeur explicite
memcpy() avec longueur calculéeVérifier longueur ≤ taille destination

4. Heap-based buffer overflow

Mécaniquement différent, exploite les métadonnées de l'allocateur (glibc malloc, dlmalloc, jemalloc, ptmalloc2).

4.1 Principe

malloc retourne un bloc avec en amont des métadonnées (taille, pointeurs vers chunk précédent/suivant en cas de free). Un overflow sur un chunk déborde sur les métadonnées du chunk adjacent. Lors d'un free ultérieur, l'allocateur suit les pointeurs corrompus → écriture arbitraire en mémoire.

4.2 Techniques d'exploitation historiques

  • Unlink attack (Solar Designer, 2000s) : exploiter unlink() lors de la coalescence de chunks libres. Mitigée depuis glibc 2.4 par check d'intégrité.
  • House of Force, House of Spirit, Fastbin Attack, Tcache Poisoning - techniques modernes ciblant les structures de l'allocateur. Activement étudiées en CTF.

Le heap exploitation est réputé plus difficile que le stack overflow : non-déterminisme, contraintes d'agencement, fenêtres de timing. Mais reste exploitable - cf. nombreux CVE récents sur navigateurs et noyaux.

5. Variantes proches

5.1 Off-by-one

Écriture d'un seul octet en trop. Souvent due à confusion < vs <= dans une boucle, ou oubli du \0 final d'une chaîne. Suffit parfois à écraser le LSB d'un pointeur sauvegardé et déclencher une RCE.

5.2 Integer overflow vers buffer overflow

size_t total = nb_items * item_size;  // overflow possible
char *buf = malloc(total);            // alloue trop peu
memcpy(buf, src, nb_items * item_size); // déborde

Si nb_items * item_size déborde l'entier, malloc reçoit une petite valeur, mais le memcpy copie la valeur réelle. CVE-2002-0083 (OpenSSH), nombreux exemples ImageMagick.

5.3 Format string

printf(user_input);  // si user_input contient %s, %x, %n

Permet lecture (%x, %s) et écriture mémoire arbitraire (%n). Considéré comme une famille proche du buffer overflow car il viole l'isolation mémoire.

5.4 Out-of-bounds read

Symétrique : on lit au-delà du buffer. Conséquence typique : exfiltration de données. Cas célèbre : Heartbleed (CVE-2014-0160, OpenSSL) - un OOB read jusqu'à 64 ko de mémoire serveur exposée par requête.

6. Exemples historiques marquants

AnnéeIncidentTypeImpact
1988Morris WormStack BO sur fingerd~6000 machines (10 % de l'Internet de l'époque)
2001Code RedStack BO sur IIS .ida359 000 machines en 14h, ~2 G$ de dommages
2003SQL SlammerStack BO sur SQL Server UDP75 000 machines en 10 min
2003BlasterStack BO RPC DCOM WindowsMillions de machines
2008ConfickerStack BO RPC NetAPI (MS08-067)9-15 millions de machines
2014HeartbleedOOB read OpenSSLQuasi-tout l'Internet TLS
2017EternalBluePool overflow SMBv1 (MS17-010)Bases pour WannaCry, NotPetya
2021Log4Shell(ce n'est pas un BO, lookup JNDI - mais souvent confondu)Quasi-tout l'écosystème Java
2022-2025Nombreux CVE Chrome / WebKit / Linux kernelHeap BO et UAFExploits sur navigateurs et téléphones (Pegasus chains)

Les BO « basiques » sur services réseau exposés à Internet ont fortement diminué grâce aux mitigations - mais la classe reste vivante dans les navigateurs, noyaux, hyperviseurs, et logiciels embarqués.

7. Exploitation : du crash à la RCE

Trois étapes typiques pour transformer un BO en exécution de code :

7.1 Trouver l'offset

Calibrer le payload pour identifier l'offset exact entre le début du buffer et l'adresse de retour. Outils : cyclic / pattern_create (pwntools, Metasploit), debug avec gdb.

7.2 Choisir la cible du saut

  • Avant DEP/NX : injecter du shellcode dans le buffer, faire pointer ret vers le buffer.
  • Avec DEP/NX : impossible d'exécuter sur la stack. On utilise ROP (Return-Oriented Programming) - chaînes de petits gadgets (séquences se terminant par ret) déjà présents dans le binaire ou les bibliothèques chargées.
  • Avec ASLR : adresses randomisées, il faut d'abord une fuite d'information pour défaire l'aléa.

7.3 Atteindre l'objectif

Spawn shell, lire fichier sensible, élever les privilèges, désactiver une protection. En réseau : binder un shell sur un port, ou faire revenir une connexion (reverse shell).

L'exploitation moderne (2020-2026) est rarement triviale : il faut chaîner BO + info leak + ROP + bypass de canary, parfois avec contraintes de caractères (pas de \0, pas d'espaces). C'est la spécialité pwn des CTF.

8. Protections modernes

Quatre décennies de mitigations empilées. Aucune n'est suffisante seule, leur combinaison rend l'exploitation difficile.

8.1 Stack Canaries (StackGuard, ProPolice, /GS)

Une valeur aléatoire (le canary) est insérée entre les variables locales et l'adresse de retour. Avant ret, le code vérifie que le canary n'a pas changé. Un BO classique l'écrase et déclenche un abort.

// Compilation avec canary :
gcc -fstack-protector-strong sample.c

Bypass possible : fuite de la valeur du canary, ou écriture qui ne traverse pas le canary (off-by-one ciblé).

8.2 DEP / NX bit (Data Execution Prevention)

Marque les pages de données (stack, heap) comme non exécutables. Un saut vers du shellcode injecté dans la stack provoque une exception. Disponible depuis 2004 (Windows XP SP2, processeurs avec NX bit).

Bypass : ROP / JOP / SROP. C'est précisément ce qui a poussé l'invention du ROP par Hovav Shacham (2007).

8.3 ASLR (Address Space Layout Randomization)

Les adresses de la stack, du heap, des bibliothèques (et du binaire si compilé PIE) sont randomisées à chaque exécution. L'attaquant ne sait plus où sauter sans information préalable.

Limites : entropie réduite sur 32 bits (bruteforce possible en quelques heures), ne protège pas si le binaire n'est pas PIE, contournable par fuite d'info.

# Vérifier ASLR sur Linux :
cat /proc/sys/kernel/randomize_va_space  # 2 = full ASLR

8.4 RELRO et FORTIFY_SOURCE

  • RELRO (Relocation Read-Only) : marque la GOT en lecture seule après résolution dynamique.
  • FORTIFY_SOURCE : remplace certaines fonctions par des versions vérifiant la taille à la compilation (-D_FORTIFY_SOURCE=2 -O2).

8.5 Control Flow Integrity (CFI) et CET

  • CFG (Control Flow Guard, Windows) : valide les cibles de sauts indirects.
  • Intel CET (Control-flow Enforcement Technology) : Shadow Stack matérielle (sauvegarde séparée de l'adresse de retour) + IBT (Indirect Branch Tracking).
  • ARM PAC (Pointer Authentication Codes) : signe les pointeurs avec une clé secrète. Apple Silicon, Android moderne.
  • MTE (Memory Tagging Extension) : marque chaque allocation avec un tag, vérifié à l'accès. Disponible sur ARMv8.5+ (Pixel 8+).

8.6 Tableau récapitulatif

ProtectionAnnéeDéfaut surBypass classique
Stack canaries1998gcc, MSVCFuite d'info, brute force
DEP / NX2004Windows XP SP2+, Linux 2.6+ROP / JOP
ASLR2003-2007Linux, Windows Vista+Info leak, partial overwrite
RELRO Full~2010gcc/ldSi lazy binding actif
CFG2014Windows 8.1+Bypass complexe, recherches actives
Intel CET2020Windows 11, Linux récentTrès récent, peu de bypass publics
ARM PAC2018Apple A12+, AndroidPACMAN attack (académique 2022)
ARM MTE2024Pixel 8+, prochains SoCEn cours d'évaluation

9. Détection et test

9.1 Sanitizers

  • AddressSanitizer (ASan) : détection runtime de OOB read/write, UAF, double free. Coût ~2x mémoire et CPU. À activer en dev/test.
gcc -fsanitize=address -g -O1 sample.c -o sample
./sample
  • MemorySanitizer (MSan) : détecte les lectures de mémoire non initialisée.
  • UndefinedBehaviorSanitizer (UBSan) : détecte les comportements indéfinis (overflow d'entier signé, etc.).
  • Valgrind / Memcheck : alternative historique, plus lent qu'ASan.

9.2 Fuzzing

  • AFL++ : fork de AFL, le standard open source.
  • libFuzzer : intégré à Clang, in-process.
  • honggfuzz : Google, multi-architecture.
  • Jazzer, cargo-fuzz, go-fuzz - fuzzers par langage.

Combiner fuzzer + ASan est la méthode la plus efficace pour découvrir des BO en 2026.

9.3 Analyse statique

  • clang-tidy, cppcheck, Coverity, CodeQL : détectent certains patterns (utilisation de gets, oubli de borne, etc.). Faux positifs et faux négatifs présents.

9.4 Audit manuel

Pour les fonctions critiques, rien ne remplace une revue manuelle ciblée sur les opérations mémoire. Lecture systématique des appels à memcpy, strncpy, read, recv, et de toute arithmétique de taille.

10. Prévention en 2026

10.1 Choisir un langage mémoire-safe

La meilleure prévention reste de ne pas utiliser C/C++ pour le code nouveau quand c'est évitable :

  • Rust : ownership et borrow checker éliminent les BO sans cost runtime. Adopté par Linux kernel (modules), Windows kernel (composants), Android (Bluetooth, ULTRA-HDR).
  • Go, Java, C#, Kotlin, Swift, Python : runtime géré, BO impossibles dans le code utilisateur (mais possibles dans le runtime ou les bindings natifs).

Le NSA, la CISA, l'ANSSI, la Maison Blanche (rapport ONCD 2024) recommandent explicitement la migration des composants critiques vers les langages mémoire-safe.

10.2 Pour le code C/C++ existant

  • Compiler avec toutes les protections : -fstack-protector-strong -D_FORTIFY_SOURCE=2 -O2 -fPIE -pie -Wl,-z,relro,-z,now.
  • Utiliser les API safe : strncpy, snprintf, memcpy_s (C11 Annex K), strlcpy/strlcat (BSD).
  • Activer warnings stricts : -Wall -Wextra -Wformat-security -Wconversion.
  • Audit régulier avec ASan + fuzzing en CI.
  • Refactor des fonctions critiques en Rust quand possible (FFI / interop).

10.3 Au runtime

Activer toutes les mitigations OS : ASLR full, DEP, CFG, CET si disponible. Ne jamais les désactiver « pour debug » en production.

11. FAQ

11.1 Quelle différence entre stack overflow et heap overflow ?

Le stack overflow déborde sur la pile (variables locales, adresse de retour). Le heap overflow déborde sur le tas (chunks malloc, métadonnées allocateur). Le premier est historiquement plus simple à exploiter (adresse de retour immédiatement après le buffer), le second exploite les structures de l'allocateur, plus complexe mais toujours exploitable.

11.2 Pourquoi les buffer overflows existent encore en 2026 ?

Trois raisons : (1) le code C/C++ legacy représente des milliards de lignes en production (noyaux, bibliothèques système, navigateurs, embarqué) ; (2) certains domaines (firmware, OS, jeux haute performance) restent dépendants de C/C++ ; (3) même les nouveaux développements C/C++ continuent d'introduire des BO faute de discipline ou de revue.

11.3 ASLR et DEP suffisent-ils à empêcher l'exploitation ?

Non. ASLR + DEP rendent l'exploitation plus coûteuse mais une fuite d'information (info leak) suffit à défaire ASLR, et ROP contourne DEP. Les exploits modernes (Pwn2Own, NSO Pegasus) chaînent typiquement 3-7 vulnérabilités pour atteindre RCE + SBX + LPE.

11.4 Le langage Rust empêche-t-il vraiment tous les buffer overflows ?

Dans le code safe Rust (par défaut), oui : le compilateur refuse les accès hors borne, et les indexations runtime panique au lieu de déborder. Dans les blocs unsafe (FFI, structures de données performantes), les BO redeviennent possibles - d'où l'importance d'auditer ces sections. Mais leur surface est très réduite par rapport au tout-C/C++.

11.5 Comment savoir si un binaire a les protections activées ?

Outil checksec (recommandé) :

checksec --file=./binary
# Affiche : RELRO, Canary, NX, PIE, Fortify

Sur Windows, PESec ou WinChecksec. Pour vérifier ASLR au runtime côté OS Linux : cat /proc/sys/kernel/randomize_va_space (2 = full).

11.6 Puis-je exploiter un buffer overflow pour apprendre ?

Oui, c'est la voie classique - dans un cadre légal. Les CTF (picoCTF, FCSC, HackTheBox, pwn.college) proposent des challenges pwn dédiés. Le tutoriel canonique reste Smashing The Stack For Fun And Profit d'Aleph One (Phrack #49, 1996) - lecture obligatoire pour tout aspirant exploit developer. Pour l'exploitation moderne, pwn.college et LiveOverflow (chaîne YouTube) sont les meilleures ressources gratuites.


Le buffer overflow est la vulnérabilité fondatrice de la sécurité offensive moderne. Comprendre son mécanisme - et celui des protections qui ont émergé en réponse - reste un passage obligé pour qui veut faire du pentest binaire, du reverse engineering, ou de l'AppSec native sérieuse. Sa disparition annoncée à chaque génération technologique ne s'est jamais réalisée : tant que du C/C++ tournera dans les noyaux, navigateurs et firmwares, les BO continueront d'alimenter l'industrie de l'exploitation et de la défense.

Trajectoire formation et accompagnement

Pour les ingénieurs et profils tech qui veulent se spécialiser en reverse engineering, malware analysis ou exploit development, le panorama des formations cybersécurité pour profils tech liste les parcours adaptés au profil et au rythme attendu. L'auteur Naïm Aouaichia, ingénieur cybersécurité ex-DevSecOps IN Groupe avec audits CAC 40 à son actif, publie régulièrement sur les sujets reverse engineering et carrière cyber via la chaîne YouTube Zeroday Cyber Academy et la newsletter Substack Zeroday Notes.

Questions fréquentes

  • Buffer overflow en une phrase, c'est quoi ?
    Un buffer overflow est une vulnérabilité où un programme écrit plus de données dans un buffer mémoire que sa taille allouée, écrasant les zones mémoire adjacentes (variables locales, return address de la pile, métadonnées du heap). Conséquence : crash du programme dans le meilleur cas, prise de contrôle de l'exécution (RCE) dans le pire. Connu depuis le ver Morris en 1988, exploité via stack overflow (zone de pile) ou heap overflow (zone allouée dynamiquement). Référence académique : Aleph One *Smashing The Stack for Fun and Profit* (Phrack 49, 1996), texte fondateur du domaine. Classé CWE-119, CWE-120 dans la classification MITRE.
  • Stack overflow vs heap overflow, quelle différence en pratique ?
    Stack overflow : débordement dans la pile, écrase la return address, permet de rediriger le flow d'exécution vers un shellcode ou un gadget ROP. Plus simple à exploiter historiquement, mais largement mitigé par les protections modernes (canaries de pile, ASLR, DEP/NX). Heap overflow : débordement dans la zone allouée dynamiquement par malloc, écrase les métadonnées allocateur (chunk headers, free list pointers). Exploitation plus complexe (House of Force, Unsafe Unlink, Tcache poisoning) mais souvent plus stealth et persistant. Selon CVE Details 2024, 65 % des CVE buffer overflow exploités en 2023-2024 sont heap overflow (vs 35 % stack). Les protections heap (CFG, Pointer Authentication ARM, MTE) commencent à se généraliser mais restent partielles.
  • Les buffer overflows sont-ils encore d'actualité en 2026 ?
    Oui, surtout dans le code natif (C, C++) qui reste majoritaire dans l'OS, drivers, navigateurs, jeux, embedded. Selon CVE statistics 2024, environ 25 % des CVE critiques publiées concernent encore des memory safety bugs (buffer overflow, use-after-free, double-free). Microsoft estime que 70 % des vulnérabilités historiques sur ses produits sont des memory safety issues (Microsoft Security Response Center 2019, statistique reprise en 2024). Le passage à Rust, Go, Swift réduit le risque dans les nouveaux projets, mais le legacy C/C++ représente des milliards de lignes en production. Les buffer overflows restent un sujet d'apprentissage central pour comprendre la sécurité système et lire intelligemment les CVE publiées.
  • Quelles protections existent contre les buffer overflows en 2026 ?
    Six couches cumulatives. Premièrement, stack canaries (Stack Smashing Protector) : valeur aléatoire placée avant la return address, vérifiée à l'epilog. Activé par défaut depuis GCC 4.x. Deuxièmement, ASLR (Address Space Layout Randomization) : positions mémoire randomisées à chaque exécution, complique le ROP. Activé par défaut Linux/Windows/macOS. Troisièmement, DEP/NX (Data Execution Prevention) : pages mémoire data non exécutables, force ROP plutôt que shellcode direct. Quatrièmement, CFG/CET (Control Flow Guard, Intel CET) : vérification des cibles de jumps indirects à l'exécution. Cinquièmement, MTE ARM (Memory Tagging Extension, ARMv8.5+) : tagging des allocations mémoire, détection automatique des access invalides. Sixièmement, langages memory-safe : Rust, Go, Swift éliminent par construction. Pattern défensif moderne : combinaison de tous + audit code C/C++ via fuzzing (AFL++, libFuzzer).
  • Comment apprendre à exploiter les buffer overflows en 2026 ?
    Parcours structuré sur 6-12 mois. Mois 1-2 : lire Smashing The Stack for Fun and Profit (Aleph One, 1996) et The Shellcoder's Handbook (Anley, Heasman, Linder). Pratique sur protostar.io (binaires intentionnellement vulnérables), niveaux stack0-7. Mois 3-4 : pratique sur Pwnable.kr (Corée, gratuit, 80+ challenges). Mois 5-8 : pwn.college Memory Errors module (université Arizona, gratuit, structuré). Mois 9-12 : Hack The Box section Pwn (binaires modernes avec protections récentes). Outils : pwntools (Python lib pour exploitation), gdb-peda ou pwndbg (gdb enrichi), ROPgadget (recherche ROP gadgets). Ressources complémentaires : LiveOverflow YouTube channel (Fabian Faessler, série binary exploitation), CTF write-ups (ctftime.org).

Écrit par

Naim Aouaichia

Cyber Security Engineer et fondateur de Zeroday Cyber Academy

Ingénieur cybersécurité avec un parcours hybride : développement, DevOps Capgemini, DevSecOps IN Groupe (sécurité des documents d'identité régaliens), audits CAC 40. Fondateur de Hash24Security et Zeroday Cyber Academy. Présence LinkedIn 43 000 abonnés, Substack Zeroday Notes 23 000 abonnés.