Skip to content
KitploitKITPLOIT
OutilsExploitsBlog
Log in
Soumettre
OutilsExploitsBlog
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-2023-21768 — Preuve de concept d'exploit pour CVE-2023-21768, une vulnérabilité d'écriture arbitraire dans le noyau du pilote de fonction auxiliaire Windows (AFD.sys) permettant une élévation de privilèges locale via I/O ring. | Kitploit
Outils/GitHubGitHub/h1bana/cve-2023-21768
Escalade de PrivilègesAnalyse des VulnérabilitésExploitationExploitation de Binaires
GitHubh1bana/cve-2023-21768

CVE-2023-21768

Preuve de concept d'exploit pour CVE-2023-21768, une vulnérabilité d'écriture arbitraire dans le noyau du pilote de fonction auxiliaire Windows (AFD.sys) permettant une élévation de privilèges locale via I/O ring.

Voir le dépôt
3il y a 3 ansPas encore vérifié

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-2023-21768

Windows Ancillary Function Driver for WinSock

Selon la description détaillée de CVE-2023-21768 publiée par le Microsoft Security Response Center (MSRC), la vulnérabilité existe dans le Ancillary Function Driver (AFD), dont le nom de fichier système est afd.sys. Le module AFD est le point d'entrée noyau de l'API WinSock. Dans cette analyse, je l'utiliserai pour effectuer une escalade de privilèges sous Windows 11.

Analyse du correctif et cause racine

Téléchargez deux versions de afd.sys depuis Winbindex, une version proche avant le correctif et une version après le correctif. Utilisez ensuite Bindiff pour comparer ces deux versions. bindiff

En comparant globalement les deux versions, on voit qu'une seule fonction est différente : AfdNotifyRemoveIoCompletion. Examinez plus en détail les différences de cette fonction entre les deux versions. bindiff

Il n'y a pas trop de différences entre les deux versions. Dans la version post-correctif, des instructions assembleur supplémentaires sont ajoutées pour définir les paramètres et appeler la fonction ProbeForWrite. Selon la documentation de Microsoft, cette fonction sert à vérifier qu'une adresse est bien en mode utilisateur, accessible en écriture et correctement alignée. Analysons ce code plus en détail :

  • Version pré-correctif : afd.sys version 10.0.22621.608 code1

  • Version post-correctif : afd.sys version 10.0.22621.1105 code2

Les deux vérifient la valeur de r15_1 ; si elle est égale à 0, la valeur de var_304 est écrite dans le pointeur spécifié à un champ de struct_1. Si différente de 0, ProbeForWrite est appelée pour s'assurer que le pointeur pointe vers une adresse valide. Dans la version pré-correctif, la valeur de var_304 est ensuite écrite dans le pointeur, mais cette vérification manque. Grâce à ce correctif, on peut supposer que nous pouvons appeler ce code avec la valeur de arg3_1->field_18 contrôlée. Si l'on peut définir une adresse noyau dans field_18, on peut écrire var_304 à une adresse mémoire noyau.

=> type de bug : écriture arbitraire dans le noyau (Write-Where)

Maintenant, il faut trouver comment déclencher le bug. La fonction AfdNotifyRemoveIoCompletion est appelée directement dans AfdNotifySock. crossRef

De même, en recherchant les références croisées de AfdNotifySock, on voit qu'elle n'est appelée directement par aucune autre fonction, mais son adresse est stockée à une adresse dans .rdata. cross2

Cette adresse se trouve juste avant AfdIrpCallDispatch. cross3

Pour déclencher le bug, j'appellerai DeviceIoControl avec IOCTL_AFD_NOTIFY_SOCK et AfdNotifySock sera appelée.

BOOL DeviceIoControl(
  [in]                HANDLE       hDevice,
  [in]                DWORD        dwIoControlCode,
  [in, optional]      LPVOID       lpInBuffer,
  [in]                DWORD        nInBufferSize,
  [out, optional]     LPVOID       lpOutBuffer,
  [in]                DWORD        nOutBufferSize,
  [out, optional]     LPDWORD      lpBytesReturned,
  [in, out, optional] LPOVERLAPPED lpOverlapped
);

Reverse et debug

Pour chaque pilote, un objet DRIVER_OBJECT est créé dans le noyau, défini comme suit :

typedef struct _DRIVER_OBJECT {
  CSHORT             Type;
  CSHORT             Size;
  PDEVICE_OBJECT     DeviceObject;
  ULONG              Flags;
  PVOID              DriverStart;
  ULONG              DriverSize;
  PVOID              DriverSection;
  PDRIVER_EXTENSION  DriverExtension;
  UNICODE_STRING     DriverName;
  PUNICODE_STRING    HardwareDatabase;
  PFAST_IO_DISPATCH  FastIoDispatch;
  PDRIVER_INITIALIZE DriverInit;
  PDRIVER_STARTIO    DriverStartIo;
  PDRIVER_UNLOAD     DriverUnload;
  PDRIVER_DISPATCH   MajorFunction[IRP_MJ_MAXIMUM_FUNCTION + 1];
} DRIVER_OBJECT, *PDRIVER_OBJECT;

Le dernier élément MajorFunction est un tableau contenant les fonctions de dispatch du pilote pour gérer les communications entre le noyau et le mode utilisateur. La fonction de dispatch correspondant à l'appel DeviceIoControl est stockée dans MajorFunction[IRP_MJ_DEVICE_CONTROL].

#define IRP_MJ_DEVICE_CONTROL           0x0e

À partir de la fonction DriverEntry de afd.sys, nous pouvons voir que le pilote a créé l'objet de périphérique "\Device\Afd" : code3

Affecte MajorFunction[IRP_MJ_DEVICE_CONTROL] = AfdDispatchDeviceControl, donc lorsqu'on appelle DeviceIoControl pour communiquer avec le noyau, cette fonction est invoquée. code4

Dans AFD, il y a deux tables de dispatch : AfdIrpCallDispatch et AfdImmediateCallDispatch. dispatchtable1 dispatchtable2

On voit facilement que AfdDispatchDeviceIoControl calcule un indice via IoControlCode et récupère la valeur correspondante à partir de AfdIoctlTable pour la vérifier avec IoControlCode. 1

À partir de la distance entre l'adresse de début de AfdImmediateCallDispatch et l'adresse où est stockée AfdNotifySock, on calcule un indice de 73, avec le code de contrôle 0x12127. ioctl

int main() {
    WSADATA WSAData;
    SOCKET s;
    SOCKADDR_IN sa;
    int ierr;

    WSAStartup(0x2, &WSAData);
    s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    memset(&sa, 0, sizeof(sa));
    sa.sin_port = htons(135);
    sa.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
    sa.sin_family = AF_INET;
    ierr = connect(s, (const struct sockaddr*)&sa, sizeof(sa));

    char outBuf[100];
    DWORD bytesRet;
    DWORD inbuf1[100];

    memset(inbuf1, 0, sizeof(inbuf1));

    DeviceIoControl((HANDLE)s, 0x12127, (LPVOID)inbuf1, 0x30, outBuf, 0, &bytesRet, NULL);
    return 0;
}

Ça fonctionne !

bp1

Comme dit au début, la vulnérabilité survient lorsque nous pouvons passer un pointeur non validé via une structure. Cette structure est transmise directement depuis le mode utilisateur via lpInBuffer de DeviceIoControl. Elle est ensuite passée à AfdNotifySock en tant que 4ᵉ paramètre, puis à AfdNotifyRemoveIoCompletion en tant que 3ᵉ paramètre.

Télécharger l’outil