ROP (Return-Oriented Programming)
hackingDéfinition
Le ROP (Return-Oriented Programming) est une technique avancée d'exploitation de vulnérabilités mémoire permettant à un attaquant d'exécuter une séquence d'instructions arbitraire sur un système protégé par les mécanismes de sécurité DEP (Data Execution Prevention) ou NX (No-eXecute), qui empêchent l'exécution de code directement injecté dans une zone mémoire marquée non exécutable comme la pile, contournement historiquement obtenu par l'injection classique de shellcode désormais bloquée par ces protections. Plutôt que d'injecter du code nouveau, le ROP réutilise des fragments d'instructions déjà présents et légitimement exécutables dans le code du programme ciblé ou de ses bibliothèques chargées, appelés gadgets, chacun se terminant par une instruction de retour (RET) qui, en manipulant soigneusement le contenu de la pile lors d'un débordement de tampon, permet d'enchaîner ces fragments dans un ordre précis pour reconstituer une logique d'exécution complète, contournant ainsi la protection puisqu'aucune instruction n'est jamais réellement injectée, toutes provenant du code légitime déjà marqué exécutable. La construction d'une chaîne ROP nécessite d'identifier des gadgets exploitables dans le binaire ciblé, tâche automatisée par des outils comme ROPgadget ou Ropper, puis de les assembler pour atteindre l'objectif final, souvent l'invocation d'une fonction système exécutant un shell. Cette technique, liée aux vulnérabilités mémoire (CWE-787), reste activement utilisée et motive des contre-mesures comme le CFI et l'ASLR.
ROP (Return-Oriented Programming) est une technique d'exploitation avancée qui consiste à détourner le flux d'exécution d'un programme en enchaînant des gadgets — de courts fragments de code déjà présents en mémoire et se terminant par une instruction de retour. Elle permet d'obtenir une exécution de code arbitraire sans jamais injecter de shellcode, contournant ainsi les protections de type DEP/NX qui rendent la pile non exécutable.
Pourquoi le ROP est apparu
Historiquement, l'exploitation d'un débordement de tampon (buffer overflow) suivait un schéma simple : écraser l'adresse de retour sauvegardée sur la pile, y placer l'adresse d'un shellcode injecté dans le même tampon, et laisser le processeur exécuter la charge utile.
L'arrivée de DEP (Data Execution Prevention sous Windows) et NX (No-eXecute sous Linux/Unix) a brisé ce modèle : les pages mémoire inscriptibles — pile, tas, sections de données — sont marquées non exécutables. Le shellcode injecté est toujours écrit en mémoire, mais toute tentative de l'exécuter déclenche une faute matérielle.
La parade, formalisée par Hovav Shacham en 2007 (après les travaux sur le ret2libc de Solar Designer), repose sur un constat : l'attaquant n'a pas besoin d'écrire du code, il lui suffit de réutiliser celui qui est déjà là. Le binaire et ses bibliothèques partagées (libc, ntdll, kernel32) contiennent des millions d'octets de code exécutable et légitime.
Fonctionnement technique
Un gadget est une séquence de une à cinq instructions se terminant par ret (x86/x64), pop {…, pc} (ARM 32) ou un retour équivalent. Exemples classiques sur x86-64 :
pop rdi ; ret— charge le premier argument d'appel de fonctionpop rsi ; pop r15 ; ret— charge le deuxième argumentmov [rdi], rax ; ret— écriture arbitraire en mémoirexor rax, rax ; ret— remise à zéro d'un registresyscall ; ret— déclenchement d'un appel système
Le mécanisme repose entièrement sur le contrôle de la pile. Sur x86, l'instruction ret dépile la valeur pointée par rsp et saute à cette adresse, tout en incrémentant rsp. Si l'attaquant contrôle le contenu de la pile, il contrôle donc une liste chaînée d'adresses de retour : chaque gadget s'exécute, puis son ret final passe automatiquement la main au suivant. On parle de chaîne ROP (ROP chain).
Cette pile falsifiée mêle deux types de valeurs : les adresses des gadgets, et les données qu'ils vont consommer (les valeurs dépilées par les pop). Lorsque le débordement initial ne permet pas d'écrire une chaîne assez longue, l'attaquant utilise un stack pivot — un gadget comme xchg rsp, rax ; ret ou leave ; ret — pour rediriger rsp vers une zone mémoire plus vaste qu'il maîtrise (souvent sur le tas).
Shacham a démontré que sur un jeu d'instructions à longueur variable comme x86, l'ensemble des gadgets disponibles dans une libc standard est Turing-complet. Mieux : parce que le décodage x86 n'est pas aligné, on peut « sauter au milieu » d'une instruction légitime et obtenir un gadget qui n'existe pas dans le code source original. Les outils ROPgadget, ropper et pwntools automatisent aujourd'hui la recherche de gadgets et la construction de chaînes.
Objectif typique d'une chaîne ROP
Construire une chaîne complète pour toute la charge utile est fastidieux. En pratique, l'attaquant vise le chemin le plus court vers l'exécution native :
- Appeler
mprotect()(Linux) ouVirtualProtect()(Windows) pour rendre exécutable la page contenant le shellcode déjà injecté — puis y sauter. C'est le scénario le plus fréquent. - Appeler
system("/bin/sh")ouexecve, variante moderne duret2libc. - Fuiter une adresse via
puts@pltouwrite()pour vaincre l'ASLR, puis relancer l'exploitation avec la base de la libc connue.
Variantes et concepts liés
- ret2libc : l'ancêtre du ROP, limité à l'appel d'une fonction complète de bibliothèque.
- JOP / COP (Jump/Call-Oriented Programming) : remplacent
retpar desjmpoucallindirects, pour contourner les défenses ciblant spécifiquement les retours. - SROP (Sigreturn-Oriented Programming) : abuse du signal frame Unix pour restaurer d'un coup l'ensemble des registres avec très peu de gadgets.
- ret2csu : exploite les routines d'initialisation de la libc pour contrôler des arguments quand les gadgets manquent.
- BROP (Blind ROP) : construit une chaîne à l'aveugle, sans copie du binaire, en observant les crashs d'un service qui redémarre.
Contre-mesures
Le ROP a directement motivé une génération entière de protections :
- ASLR / PIE : randomiser les adresses de chargement rend les adresses de gadgets imprévisibles. C'est la défense la plus efficace — mais elle tombe dès qu'une fuite d'information (infoleak) est disponible.
- Stack canaries (
-fstack-protector-strong) : détectent l'écrasement de l'adresse de retour avant qu'elle ne soit utilisée. - CFI (Control Flow Integrity), via
clang -fsanitize=cfiou Control Flow Guard sous Windows : valide que chaque transfert indirect vise une cible légitime. - Shadow stack matérielle : Intel CET, ARM BTI/PAC, Windows Hardware-enforced Stack Protection. Une copie protégée des adresses de retour est comparée à celle de la pile — c'est la réponse structurelle au ROP.
- RELRO complet et Fortify Source pour réduire la surface exploitable.
- Langages mémoire-sûrs (Rust, Go) : suppriment la classe de vulnérabilité en amont, seule stratégie réellement définitive.
Pour un RSSI, le ROP illustre un principe essentiel : une protection isolée ne suffit jamais. DEP seul est contournable ; DEP + ASLR + canaries + CET impose à l'attaquant d'enchaîner plusieurs primitives, ce qui élève considérablement le coût d'une exploitation fiable. Le durcissement de compilation doit donc être vérifié systématiquement (via checksec ou winchecksec) sur tout binaire exposé, et intégré aux critères d'acceptation des développements internes comme des logiciels tiers.
Articles liés
Expert en cybersécurité offensive et intelligence artificielle. Pentest, audit et développement IA sur-mesure.
Services
- Audit Infrastructure
- Audit Kubernetes
- Audit Microsoft 365
- Audit Sécurité Réseau
- Analyse de Risques
- Audit Active Directory
- Audit Application Web
- Audit Cloud (AWS/Azure/GCP)
- Audit Messagerie
- Audit API (OWASP Top 10)
- Audit DevSecOps & CI/CD
- Audit Code Source (SAST)
- Audit Postes de Travail
- Audit Sauvegarde & Résilience
- Audit OT/SCADA (IEC 62443)
- Développement IA
- Formations
Ressources
Projets & Outils
© 2026 Ayi NEDJIMI Consultants. Tous droits réservés. 2.1.7
Un projet cybersécurité ?
Expert dispo · Réponse 24h