Aller au contenu

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.

Publié le 5 min de lecture

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.

ret2usr — le noyau exécute une charge mappée en userspace
hijacked kernel RIPcontrôle saisi en ring 0
saute vers
user-mapped payloadfonction de l'attaquant en mémoire ring 3
s'exécute avec le privilège ring 0
commit_creds(prepare_kernel_cred(0))la tâche courante devient root
codewritable memory

Pas 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.

MitigationBloqueRéponse de l'attaquant
SMEPLe ring 0 exécutant des pages utilisateurROP noyau (réutiliser le code du noyau)
SMAPLe ring 0 lisant/écrivant des pages utilisateurGarder toutes les données en mémoire noyau
Épinglage de CR4L'astuce de désactivation mov cr4ROP 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 cr4 qui 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.

Guides associés

0x9000 · Exploitation du noyau

Exploitation du noyau : d'un bug à root

Un bug mémoire du noyau vise le privilège, pas un shell : modèle de credentials, charge commit_creds(prepare_kernel_cred(0)), retour propre en userspace.

0x9000 · Exploitation du noyau

KASLR, KPTI et défenses modernes du noyau

Randomisation d'adresses, isolation des tables de pages et options de configuration qui durcissent un noyau Linux : ce que chacune arrête et comment l'activer.

0xa000 · Exploitation Windows

Contourner DEP sous Windows avec ROP

DEP rend le shellcode sur la pile inexécutable ; une chaîne ROP appelle VirtualProtect pour rendre la région exécutable, puis y saute.