
(1) IQVW32.sys avant la version 1.3.1.0 et (2) IQVW64.sys avant la version 1.3.1.0 dans le pilote de diagnostic Ethernet Intel pour Windows permet à des utilisateurs locaux de provoquer un déni de service ou éventuellement d'exécuter du code arbitraire avec les privilèges du noyau via un appel IOCTL contrefait (a) 0x80862013, (b) 0x8086200B, (c) 0x8086200F ou (d) 0x80862007.
(1) IQVW32.sys avant la version 1.3.1.0 et (2) IQVW64.sys avant la version 1.3.1.0 dans le pilote de diagnostic Ethernet Intel pour Windows permet aux utilisateurs locaux de provoquer un déni de service ou éventuellement d'exécuter du code arbitraire avec des privilèges noyau via un appel IOCTL contrefait (a) 0x80862013, (b) 0x8086200B, (c) 0x8086200F, ou (d) 0x80862007.
Ce dépôt contient un rapport sur la vulnérabilité en question, ainsi que des preuves de concept fonctionnelles sur Windows 7 SP1 64 bits et Windows 10 20H2. Le fichier du pilote se trouve dans le répertoire Driver Files. Si vous découvrez des fautes de frappe dans le rapport/document, ou si vous souhaitez voir certains détails avec une description plus élaborée, veuillez créer un ticket (issue) sur le dépôt ! Je les corrigerai dès que possible.
La motivation derrière l'écriture d'un exploit pour ce pilote de périphérique en particulier est uniquement parce qu'il est actuellement abusé dans la nature pour charger un rootkit non signé d'un attaquant. En utilisant la méthode BYOVD (Bring Your Own Vulnerable Driver), les logiciels malveillants peuvent vérifier s'ils s'exécutent avec des privilèges élevés, déposer une copie du pilote vulnérable, charger le pilote, puis l'exploiter pour obtenir l'exécution de code noyau afin de charger le rootkit. Je n'ai pas réussi à rétro-ingénierer l'échantillon de logiciel malveillant, j'ai donc pris sur moi de créer l'exploit.
Samples spotted in the wild: https://bazaar.abuse.ch/sample/84ed7fec67de5621806dbb43af5167a5fc60ab7f2403448519dc0eca2b8f9022/ https://bazaar.abuse.ch/sample/0925b8985b19d7925d68186d666b0050a4cb3f2a577d64765d770a57a2eab9ae/ https://bazaar.abuse.ch/sample/e8b7f42d544fe8b954c4021315cff2fdd44d67d11704009cdf3037d34e0c0a93/
Le pilote de périphérique, à savoir iqvw64e.sys, est un pilote conçu pour effectuer des diagnostics de carte réseau. Il permet au composant en mode utilisateur d'interagir avec le pilote pour exécuter une multitude de routines noyau en exposant quelques codes de contrôle d'E/S (également appelés IOCTL), avec un code de contrôle IOCTL "sub" fourni dans le tampon d'entrée de l'utilisateur lors de l'interaction. Le code de contrôle IOCTL qui sera utilisé pour atteindre le chemin de code vulnérable est 0x80862007. En plus du code de contrôle principal, les codes de contrôle sub susmentionnés qui seront couverts dans cette analyse seront le code 0x33 pour atteindre l'appel de fonction memmove, et le code 0x30 pour atteindre les chemins de code de l'appel de fonction memset. Ce rapport ne couvrira aucun détail concernant la routine DriverEntry, car il existe suffisamment de documentation sur la page de documentation de Microsoft pour vous donner une explication approfondie.
Pour commencer, nous voulons savoir comment interagir avec ce pilote de périphérique particulier en premier lieu. Le moyen le plus courant de communiquer avec un pilote de périphérique est d'utiliser une fonction nommée DeviceIoControl. L'idée générale derrière cette fonction est que nous pouvons passer un handle de pilote valide créé par CreateFileA, passer un code de contrôle IOCTL qui correspond à la routine noyau que nous voulons, passer une structure (ou tampon) qu'elle attend, et elle retournera des données dans notre tampon de sortie. Bien que ces routines puissent parfois être nécessaires (par exemple, accéder aux registres spécifiques au modèle pour l'overclocking), elles posent également un risque sérieux pour la sécurité. Mais... comment ?
Dans le cas de CVE-2015-2291, la vulnérabilité peut être déclenchée par un utilisateur non privilégié. Comme il n'y a pas de vérifications d'assainissement présentes et que les privilèges d'administrateur ne sont pas nécessaires pour exploiter la vulnérabilité, cela pose un risque de sécurité. Ce qui se cache derrière ces deux défauts, c'est la capacité de contrôler complètement les appels de fonction memset et memmove exposés par l'interface des codes de contrôle IOCTL. Souvenez-vous de la fonction DeviceIoControl mentionnée précédemment, comment nous pouvons passer une structure qui sera utilisée dans une routine noyau ? C'est ainsi que tout s'assemble.
Prenons du recul. Nous voulons d'abord obtenir le handle du pilote lié au pilote vulnérable. Avant cela cependant, nous devons localiser l'objet de périphérique nommé correspondant. Ceux-ci sont exposés à l'espace utilisateur par un lien symbolique (généralement codé en dur), qui peut être trouvé en utilisant WinObj, faisant partie de la suite [SysInternals]. Bien que nous puissions utiliser un utilitaire de vidage de chaînes pour vider le lien symbolique, ou alternativement rétro-ingénierer le pilote, j'ai simplement chargé le pilote et l'ai localisé en utilisant WinObj. Le lien symbolique trouvé en relation avec le pilote est \\.\GLOBALROOT\Device\Nal. Pour obtenir le handle du pilote, nous devons appeler la fonction CreateFileA et lui faire retourner un handle de pilote valide que nous utiliserons plus tard dans le processus. Le code pour ce processus est le suivant :```C
if (h_nal == (HANDLE)-1)
{
printf("\n[-] Unable to obtain a driver handle to the Nal device driver. Error: %d (0x%x)", GetLastError(), GetLastError());
unused = getchar();
return 1;
}
printf("\n[+] Obtained a driver handle to the Nal device driver. Handle Value: 0x%p", h_nal);
Nous utiliserons le handle du pilote plus tard dans le processus d'exploitation. Pour l'instant, nous allons commencer la préparation de notre exploit. L'étape suivante consiste à charger la bibliothèque `ntdll.dll` à l'aide de la fonction [LoadLibraryA](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibrarya) pour obtenir un [handle de module](https://docs.microsoft.com/en-us/windows/win32/winprog/windows-data-types), afin de localiser dynamiquement les fonctions nécessaires. Bien que la bibliothèque `ntdll.dll` soit peut-être déjà chargée dans notre processus, nous devons néanmoins obtenir un handle vers celle-ci que nous pourrons utiliser. Les fonctions dont nous avons besoin pour l'exploitation sont [NtQuerySystemInformation](https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntquerysysteminformation) pour fuiter l'adresse de base du noyau NT (avec une intégrité de processus moyenne) plus tard dans le processus d'exploitation, et la fonction [NtQueryIntervalProfile](http://undocumented.ntinternals.net/index.html?page=UserMode%2FUndocumented%20Functions%2FNT%20Objects%2FProfile%2FNtQueryIntervalProfile.html) pour déclencher la vulnérabilité. Quant au code pour charger la bibliothèque `ntdll.dll`, il est le suivant :```C
h_ntdll = LoadLibraryA("C:\\Windows\\System32\\ntdll.dll");
if (!h_ntdll)
{
printf("\n[-] Failed to load the \"ntdll.dll\" API library. Error: %d (0x%x)", GetLastError(), GetLastError());
unused = getchar();
return 0;
}
printf("\n[+] Loaded the \"ntdll.dll\" API library. Handle Value: 0x%p", h_ntdll);