Skip to content
KitploitKITPLOIT
StrumentiBlog
Log in
Invia
StrumentiBlog
Invia

Strumenti di Hacking, PenTest e Cybersecurity per il tuo Arsenale di Sicurezza!

Kitploit è una directory di strumenti di hacking, cybersecurity e pentesting. Scopri gli ultimi aggiornamenti dei progetti per trovare vulnerabilità, analizzare sistemi, automatizzare i test e rafforzare la tua sicurezza.

··Feed·Contatto·Privacy·© 2026 Kitploit

Directory degli strumenti

Categorie

Vedi tutte le categorie
Loading categories
CVE-2023-21768 — Proof-of-concept exploit per CVE-2023-21768, una vulnerabilità di scrittura arbitraria del kernel nel driver Windows Ancillary Function Driver (AFD.sys) che consente l'escalation dei privilegi locali tramite I/O ring. | Kitploit
Strumenti/GitHubGitHub/h1bana/cve-2023-21768
Escalation di PrivilegiAnalisi delle VulnerabilitàExploitBinary Exploitation
GitHubh1bana/cve-2023-21768

CVE-2023-21768

Proof-of-concept exploit per CVE-2023-21768, una vulnerabilità di scrittura arbitraria del kernel nel driver Windows Ancillary Function Driver (AFD.sys) che consente l'escalation dei privilegi locali tramite I/O ring.

Vedi Repository
33 anni faNon ancora revisionato

Più Popolari

Vedi tutti →

Scopri gli strumenti più utilizzati dalla nostra community.

Esplora tutti gli strumenti

Sfoglia la nostra collezione di strumenti

Vedi tutti gli strumenti →
Condividi

CVE-2023-21768

Windows Ancillary Function Driver for WinSock

Secondo la descrizione dettagliata di CVE-2023-21768 pubblicata da Microsoft Security Response Center (MSRC), la vulnerabilità risiede in Ancillary Function Driver (AFD), il cui file di sistema è afd.sys. Il modulo AFD è il punto di ingresso kernel di WinSock API. In questa analisi lo useremo per sfruttare l'escalation dei privilegi su Windows 11.

Patch Diff e Root Cause Analysis

Scarica due versioni di afd.sys da Winbindex: una versione recente prima della patch e una dopo la patch. Quindi usa Bindiff per confrontare le due versioni. bindiff

Confrontando le due versioni a livello generale, vediamo che solo una funzione presenta differenze: AfdNotifyRemoveIoCompletion. Osserva il dettaglio delle differenze di questa funzione tra le due versioni. bindiff

Non ci sono molte differenze tra le due versioni. Nella versione post-patch sono state aggiunte istruzioni assembly per impostare i parametri e chiamare la funzione ProbeForWrite. Secondo la documentazione di Microsoft, questa funzione viene utilizzata per verificare se un indirizzo appartiene effettivamente allo spazio utente, se ha permessi di scrittura e se è correttamente allineato. Analizziamo più nel dettaglio questo codice:

  • pre-patch afd.sys version 10.0.22621.608 code1

  • post-patch afd.sys version 10.0.22621.1105 code2

Entrambi controllano il valore di r15_1. Se è uguale a 0, scrivono il valore di var_304 nel puntatore specificato in un campo di struct_1. Se è diverso da 0, viene chiamato ProbeForWrite per assicurarsi che il puntatore punti a un indirizzo valido. Nella versione pre-patch, la scrittura del valore di var_304 nel puntatore avviene dopo, ma manca questo controllo. Da questa patch possiamo dedurre che possiamo chiamare questo codice con il valore di arg3_1->field_18 controllato. Se riusciamo a impostare un indirizzo kernel in field_18, possiamo scrivere var_304 in un indirizzo di memoria del kernel.

=> tipo di bug: scrittura arbitraria Write-Where nel kernel

Ora dobbiamo trovare un modo per attivare il bug. La funzione AfdNotifyRemoveIoCompletion viene chiamata direttamente nella funzione AfdNotifySock. crossRef

Analogamente, cercando il riferimento incrociato di AfdNotifySock, notiamo che non viene chiamata direttamente da altre funzioni, ma l'indirizzo della funzione è salvato in un indirizzo in .rdata. cross2

Questo indirizzo si trova subito prima di AfdIrpCallDispatch. cross3

Per attivare il bug, chiamerò DeviceIoControl con IOCTL_AFD_NOTIFY_SOCK e verrà chiamata AfdNotifySock.

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 e debug

Per ogni driver viene creato un oggetto DRIVER_OBJECT nel kernel, definito come segue:

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;

L'ultimo componente, MajorFunction, è un array contenente le funzioni di dispatch del driver per gestire le comunicazioni tra kernel e usermode. La funzione di dispatch corrispondente alla chiamata DeviceIoControl è salvata in MajorFunction[IRP_MJ_DEVICE_CONTROL].

#define IRP_MJ_DEVICE_CONTROL           0x0e

Dalla funzione DriverEntry di afd.sys possiamo vedere che il driver ha creato l'oggetto device "\Device\Afd": code3

Assegna MajorFunction[IRP_MJ_DEVICE_CONTROL] = AfdDispatchDeviceControl, quindi quando si chiama DeviceIoControl per comunicare con il kernel, viene richiamata questa funzione. code4

In AFD esistono due tabelle di dispatch: AfdIrpCallDispatch e AfdImmediateCallDispatch. dispatchtable1 dispatchtable2

È facile notare che AfdDispatchDeviceIoControl calcola un indice tramite IoControlCode e prende il valore corrispondente da AfdIoctlTable per verificarlo con IoControlCode. 1

Dalla distanza tra l'indirizzo di inizio di AfdImmediateCallDispatch e l'indirizzo in cui è salvato AfdNotifySock, calcoliamo l'indice 73, con codice di controllo 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;
}

it works!

bp1

Come detto all'inizio, la vulnerabilità si verifica quando possiamo passare un puntatore non convalidato tramite una struct. Questa struct viene passata direttamente da usermode tramite lpInBuffer di DeviceIoControl. Viene poi passata a AfdNotifySock come quarto parametro e a AfdNotifyRemoveIoCompletion come terzo parametro.

Scarica lo strumento