
Analyse technique détaillée et implémentation d'exploit pour CVE-2015-0057, une vulnérabilité de type use-after-free dans win32k.sys, couvrant les systèmes Windows 32 bits et 64 bits de XP à 8.1.
Auteur : Aaron Adams
Traduction : 55-AA
Note du traducteur : certaines parties de cet article sont traduites librement ; en cas de doute, veuillez vous référer à l'original.
Termes :
Plus tôt cette année, j'ai eu l'occasion de travailler sur une vulnérabilité intéressante dans win32k.sys (CVE-2015-0057) et j'ai réussi à en faire une exploitation stable sur systèmes 32 et 64 bits, avec une portée allant de XP à Windows 8.1 (avec quelques exceptions). Cet article décrit en détail comment j'ai procédé sur ces deux plates-formes, et inclut également quelques éléments supplémentaires à la fin. Il décrit aussi comment réaliser l'exploitation avec des privilèges de faible intégrité sur Windows 8.1 avec SMEP activé.
Cet article est long ; j'ai essayé de fournir autant de détails que possible pour montrer la complexité de l'exploitation de cette vulnérabilité, sans les cacher, même si j'ai bien sûr omis certains points. J'espère que ces détails seront utiles à tous.
Le 10 février 2015, Microsoft a publié les détails de MS15-010. Ce bug a été découvert en premier par Udi Yavo d'enSilo. Udi a fourni une excellente analyse sur le blog breaking malware : "one bit rule-bypassing windows 10 protections using single bit". Je recommande vivement la lecture de cet article pour bien comprendre le bug, bien que je donne ici le maximum de détails sur les obstacles à surmonter lors du déclenchement de la vulnérabilité. L'exploitation de cette vulnérabilité est très intéressante, et de nombreux détails proviennent du blog d'Udi. Voici sa déclaration :
Divulgation raisonnable : bien que ce blog soit technique, nous ne divulguerons aucun code ni détail complet, afin d'empêcher tout expert technique de reproduire cette exploitation.
En récompense supplémentaire pour l'exploitation de cette vulnérabilité, nous avons obtenu une évolution de Pokémon : le Pokémon technique. Je pense devoir rendre hommage à Udi pour avoir découvert ce bug, avoir fourni des informations sur le blog et les détails de son exploitation, qui ont été très utiles.
Avant cela, je n'avais jamais exploité de vulnérabilité dans win32k.sys, je n'étais pas familier avec les rappels en mode utilisateur ni avec de nombreuses API associées. Je remercie donc également les chercheurs en sécurité renommés qui ont mis en ligne des ressources précieuses, comme Skywing, Tarjei Mandt, Alex Ionescu et j00ru. Tous ces gens méritent d'être loués pour avoir rendu publiques tant d'informations techniques. Je me suis largement appuyé sur un article de Tarjei Mandt : Win32k.sys exploitation paper.
Au moment où j'écrivais cette exploitation, un excellent ingénieur en rétro-ingénierie a réalisé une exploitation stable de CVE-2015-1701. Les exemples de code pour les rappels en mode utilisateur ont été très utiles ; merci à cet auteur.
Il est à noter que mon analyse ci-dessous a été réalisée sur Windows 7, car c'est apparemment la seule version où toutes les structures de win32k.sys ont des symboles correspondants. La plupart de ces symboles sont utilisables pour les structures des autres versions de Win32k.sys. Pour une raison inconnue, Microsoft a supprimé ces symboles à partir de Windows 8.
Enfin, je précise que ma méthode d'exploitation est assez complexe. Il est tout à fait possible qu'il existe une méthode plus simple que je n'ai pas trouvée. J'aimerais entendre parler de méthodes différentes. Quoi qu'il en soit, j'espère que tout cela sera utile pour l'étude des vulnérabilités de win32k.sys.
Voyons maintenant le bug dans le désassemblage de win32k!xxxEnableWndSBArrows, un bug assez subtil :
Avant correctif :
.text:FFFFF97FFF1B157D mov r8d, r13d
.text:FFFFF97FFF1B1580 mov rdx, r14
.text:FFFFF97FFF1B1583 call xxxDrawScrollBar ; déclenche un rappel mode utilisateur
.text:FFFFF97FFF1B1588 jmp short loc_FFFFF97FFF1B1519
[...]
.text:FFFFF97FFF1B1519 mov eax, [rbx] ; référence le pointeur tagSBINFO sans vérification
.text:FFFFF97FFF1B151B mov ebp, 0FFFFFFFBh
.text:FFFFF97FFF1B1520 xor eax, esi
Dans le code ci-dessus, Win32K!xxxdrawscrollbar peut effectuer un rappel vers l'espace utilisateur dans certaines conditions. Dans le code utilisateur, le pointeur tagSBINFO peut être libéré par l'attaquant. De retour en mode noyau, le code à l'adresse 0xFFFFF97FFF1B1519 utilisera un pointeur invalide.
Après correctif :
.text:FFFFF97FFF1D69C3 xor r8d, r8d
.text:FFFFF97FFF1D69C6 mov rdx, rbp
.text:FFFFF97FFF1D69C9 call xxxDrawScrollBar ; déclenche un rappel mode utilisateur
.text:FFFFF97FFF1D69CE cmp rbx, [rdi+0B0h] ; vérifie que le pointeur tagSBINFO est correct
---.text:FFFFF97FFF1D69D5 jz short loc_FFFFF97FFF1D69E4; si correct, continue le flux original
| .text:FFFFF97FFF1D69D7 mov rcx, rbp
| .text:FFFFF97FFF1D69DA call _ReleaseDC
| .text:FFFFF97FFF1D69DF jmp loc_FFFFF97FFF1D6958 ; saute vers la sortie de la fonction
|->.text:FFFFF97FFF1D69E4 mov eax, [rbx] ; utilise le pointeur tagSBINFO correct en toute sécurité
.text:FFFFF97FFF1D69E6 xor eax, r14d
Dans la version corrigée ci-dessus, on voit que le pointeur tagSBINFO est vérifié avant utilisation. Les informations sur la structure associée seront données plus loin.
Pour réaliser cette exploitation, nous avons effectué plusieurs corruptions. L'une d'elles déclenche la vulnérabilité.
La cause technique de ce bug est un UAF (use-after-free) dans le tas du bureau (Desktop Heap). Au début, cela m'a beaucoup dérouté, car je ne connaissais pas le mécanisme de rappel en mode utilisateur de win32k.sys ni son fonctionnement. J'ai donc pensé qu'il s'agissait d'une condition de concurrence sur un verrou menant à un UAF. En fait, le verrou de cette structure est utilisé correctement et le flux est conforme aux attentes. En bref, le vrai problème est le suivant :
Voilà, si on ignore le rappel en mode utilisateur, cette phase est assez simple.