ret2usr, SMEP et SMAP
Le noyau faisait confiance à la mémoire userspace. SMEP et SMAP y ont mis fin — et voici comment le ROP noyau les contourne.
Ceci est le deuxième tutoriel de l'espace Exploitation du noyau. Le premier guide a détourné le flux de contrôle du noyau et exécuté une charge d'élévation de privilèges. Il reposait discrètement sur la volonté du noyau d'exécuter du code situé en userspace. Deux fonctionnalités du CPU — SMEP et SMAP — y ont mis fin, et ce guide explique la technique qu'elles ont cassée et comment le ROP noyau les contourne.
Mêmes règles : VM réinitialisable, votre propre module. Voir les règles du labo.
ret2usr : le noyau qui fait confiance à votre mémoire
Historiquement, le noyau était mappé dans le même espace d'adressage que le processus en cours d'exécution, et rien n'empêchait le ring 0 de sauter dans une page utilisateur. L'exploit noyau le plus simple était donc le return-to-user (ret2usr) : placer votre charge commit_creds(prepare_kernel_cred(0)) dans votre propre mémoire userspace, puis détourner le pointeur d'instruction du noyau pour y sauter directement.
hijacked kernel RIPcontrôle saisi en ring 0user-mapped payloadfonction de l'attaquant en mémoire ring 3commit_creds(prepare_kernel_cred(0))la tâche courante devient rootPas de gadgets noyau, pas de fuite du code noyau — la charge est votre propre fonction C. C'était la forme standard de l'exploitation du noyau pendant des années.
SMEP : pas d'exécution de l'espace utilisateur depuis le ring 0
SMEP (Supervisor Mode Execution Prevention), une fonctionnalité du CPU activée via un bit de CR4, fait lever une faute au ring 0 dès qu'il tente d'exécuter une page utilisateur. ret2usr meurt aussitôt : le noyau ne peut plus exécuter votre charge mappée en userspace.
La réponse est la même que lorsque NX a tué le shellcode en userland : cessez d'exécuter vos propres pages et réutilisez celles du noyau. Construisez toute la charge sous forme de chaîne ROP noyau (la chaîne du premier guide a déjà cette forme). Les gadgets proviennent de l'image du noyau ; la chaîne appelle directement prepare_kernel_cred et commit_creds.
Le raccourci CR4
Un raccourci célèbre : trouver un gadget comme mov cr4, rdi ; ret, mettre rdi à une valeur de CR4 avec le bit SMEP effacé, et l'exécuter. SMEP est désormais désactivé et ret2usr fonctionne à nouveau :
pop rdi ; ret -> 0x6f0 ; a CR4 value with SMEP (bit 20) cleared
mov cr4, rdi ; ret ; disable SMEP
<address of user payload> ; ret2usr now succeeds
Les noyaux modernes s'en défendent par l'épinglage de CR4 (durcissement de l'ère CONFIG_X86_PIN_CR4) : les bits CR4 critiques pour la sécurité sont mis en cache et toute tentative de les effacer est détectée, si bien que le raccourci provoque une faute ou est annulé.
SMAP : pas de lecture de l'espace utilisateur non plus
SMAP (Supervisor Mode Access Prevention) étend l'idée aux données : le ring 0 ne peut ni lire ni écrire les pages utilisateur non plus, sauf s'il encadre explicitement l'accès avec stac/clac. Cela bloque les exploits qui laissaient de fausses structures, des tableaux d'arguments ou une cible de pivot de pile en userspace pour que le noyau les consomme.
Avec SMAP activé, tout ce que le noyau doit lire pendant l'exploit doit résider en mémoire noyau. Les techniques s'adaptent : pulvériser les données nécessaires dans des objets du tas noyau, ou construire une chaîne ROP noyau pure dont tous les opérandes sont sur la pile noyau que vous avez fait déborder.
| Mitigation | Bloque | Réponse de l'attaquant |
|---|---|---|
| SMEP | Le ring 0 exécutant des pages utilisateur | ROP noyau (réutiliser le code du noyau) |
| SMAP | Le ring 0 lisant/écrivant des pages utilisateur | Garder toutes les données en mémoire noyau |
| Épinglage de CR4 | L'astuce de désactivation mov cr4 | ROP noyau pur sans désactiver SMEP |
Réactivez les mitigations
SMEP et SMAP sont activés par défaut sur tout noyau et CPU modernes (les flags de démarrage nosmep/nosmap les désactivent — ne faites jamais cela en production). Vérifiez qu'ils sont actifs :
$ grep -o 'smep\|smap' /proc/cpuinfo | sort -u
smap
smep
Combinés à un canari de pile noyau et à KASLR, ils transforment « saute vers ma charge » en « trouve une fuite, puis construis une chaîne ROP noyau qui ne touche jamais à l'espace utilisateur » — nettement plus de travail.
Ce que cela apprend à un défenseur
- SMEP/SMAP sont le moment NX/DEP du noyau. Ils ont mis fin à l'exploit ret2usr trivial et forcé les attaquants vers le ROP noyau, exactement comme NX a forcé le ROP userland. Assurez-vous qu'ils sont actifs (ils le sont, par défaut) et ne démarrez jamais avec
nosmep/nosmap. - L'épinglage de CR4 compte. Il ferme le contournement de SMEP le moins cher. Il est standard dans les noyaux modernes ; ne faites pas tourner d'anciens noyaux où il est absent.
- La surface d'attaque, encore. Le ROP noyau a toujours besoin d'un bug et généralement d'une fuite. Réduire les pilotes et appels système atteignables (seccomp,
lockdown) maintient les deux hors de portée.
Points clés à retenir
- ret2usr pointait l'exécution détournée du noyau vers une charge userspace — trivial tant que le noyau faisait confiance à la mémoire utilisateur.
- SMEP fait lever une faute sur l'exécution en ring 0 de pages utilisateur ; SMAP fait lever une faute sur l'accès en ring 0 aux données utilisateur.
- La réponse est le ROP noyau : réutiliser le code du noyau et garder toutes les données en mémoire noyau, tout comme le ROP userland après NX.
- L'épinglage de CR4 bloque le raccourci
mov cr4qui servait à désactiver SMEP.
Ensuite : KASLR, KPTI et les défenses modernes du noyau, les couches de masquage d'adresses et d'isolation qui se superposent à SMEP/SMAP.