Skip to content
KitploitKITPLOIT
FerramentasExploitsBlog
Log in
Enviar
FerramentasExploitsBlog
Enviar

Ferramentas de Hacking, PenTest e Cibersegurança para o seu Arsenal de Segurança!

Kitploit é um diretório de ferramentas de hacking, cibersegurança e pentesting. Descubra as últimas atualizações de projetos para encontrar vulnerabilidades, analisar sistemas, automatizar testes e fortalecer sua segurança.

··Feeds·Contato·Privacidade·© 2026 Kitploit

Diretório de Ferramentas

Categorias

Ver todas as categorias
Loading categories
CVE-2023-21768 — Exploit de prova de conceito para CVE-2023-21768, uma vulnerabilidade de escrita arbitrária no kernel do Driver de Função Auxiliar do Windows (AFD.sys) que possibilita escalonamento de privilégio local via I/O ring. | Kitploit
Ferramentas/GitHubGitHub/h1bana/cve-2023-21768
Escalada de PrivilégiosAnálise de VulnerabilidadesExploraçãoExploração de Binários
GitHubh1bana/cve-2023-21768

CVE-2023-21768

Exploit de prova de conceito para CVE-2023-21768, uma vulnerabilidade de escrita arbitrária no kernel do Driver de Função Auxiliar do Windows (AFD.sys) que possibilita escalonamento de privilégio local via I/O ring.

Ver Repositório
3há 3 anosAinda não revisado

Mais Populares

Ver todos →

Descubra as ferramentas mais usadas pela nossa comunidade.

Explore todas as ferramentas

Navegue pela nossa coleção de ferramentas

Ver todas as ferramentas →
Compartilhar

CVE-2023-21768

Driver de Função Auxiliar do Windows para WinSock

De acordo com a descrição detalhada da CVE-2023-21768 publicada pelo Microsoft Security Response Center (MSRC), a vulnerabilidade existe no Ancillary Function Driver (AFD), cujo nome de arquivo no sistema é afd.sys. O módulo AFD é o ponto de entrada no kernel da WinSock API. Nesta análise, usarei-a para explorar a elevação de privilégio no Windows 11.

Análise de Diff de Patch e Causa Raiz

Baixe duas versões do afd.sys do Winbindex, uma versão mais recente antes do patch e uma versão após o patch. Em seguida, use o Bindiff para comparar essas duas versões. bindiff

Comparando as duas versões de forma geral, vemos que apenas uma função tem diferença: AfdNotifyRemoveIoCompletion. Veja mais detalhes sobre as diferenças desta função entre as duas versões. bindiff

Não há muitas diferenças entre as duas versões. Na versão pós-patch, há instruções assembly adicionais para definir parâmetros e chamar a função ProbeForWrite. De acordo com a documentação da Microsoft, esta função é usada para verificar se um endereço realmente pertence ao modo de usuário, tem permissão de escrita e está alinhado corretamente. Análise mais detalhada deste código:

  • pré-patch afd.sys version 10.0.22621.608 code1

  • pós-patch afd.sys version 10.0.22621.1105 code2

Ambas verificam o valor de r15_1; se for 0, escrevem o valor de var_304 no ponteiro especificado em um campo de struct_1. Se for diferente de 0, ProbeForWrite é chamado para garantir que o ponteiro aponte para um endereço válido. Na versão pré-patch, o valor de var_304 é escrito no ponteiro após essa verificação, que está ausente. A partir deste patch, podemos inferir que podemos chamar este código com o valor de arg3_1->field_18 sob controle. Se for possível definir um valor de endereço de kernel em field_18, podemos escrever var_304 em um endereço de memória do kernel.

=> tipo de bug: escrita arbitrária no kernel (Write-Where)

Agora precisamos encontrar uma forma de acionar o bug. A função AfdNotifyRemoveIoCompletion é chamada diretamente na função AfdNotifySock. crossRef

Da mesma forma, ao procurar a referência cruzada de AfdNotifySock, vemos que ela não é chamada diretamente por nenhuma outra função, mas o endereço da função está armazenado em um endereço no .rdata cross2

Este endereço está imediatamente antes de AfdIrpCallDispatch. cross3

Para acionar o bug, chamarei DeviceIoControl com IOCTL_AFD_NOTIFY_SOCK e AfdNotifySock será chamado.

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
);

engenharia reversa e depuração

Para cada driver, um objeto DRIVER_OBJECT é criado no kernel, definido da seguinte forma:

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;

O último componente MajorFunction é uma matriz contendo as funções de despacho do driver para lidar com a comunicação entre kernel e modo de usuário. A função de despacho correspondente à chamada DeviceIoControl é armazenada em MajorFunction[IRP_MJ_DEVICE_CONTROL].

#define IRP_MJ_DEVICE_CONTROL           0x0e

A partir da função DriverEntry do afd.sys, podemos ver que o driver criou o objeto de dispositivo "\Device\Afd": code3

Atribui MajorFunction[IRP_MJ_DEVICE_CONTROL] = AfdDispatchDeviceControl, então ao chamar DeviceIoControl para se comunicar com o kernel, essa função será chamada. code4

No AFD, existem duas tabelas de despacho: AfdIrpCallDispatch e AfdImmediateCallDispatch. dispatchtable1 dispatchtable2

É fácil ver que AfdDispatchDeviceIoControl calcula um índice a partir do IoControlCode e obtém o valor correspondente ao índice da tabela AfdIoctlTable para validar com o IoControlCode. 1

A partir da distância entre o endereço inicial de AfdImmediateCallDispatch e o endereço onde AfdNotifySock está armazenado, calculamos que o índice é 73, com código de controle 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;
}

funciona!

bp1

Como dito no início, a vulnerabilidade ocorre quando podemos passar um ponteiro não validado por meio de uma struct. Essa struct é passada diretamente do modo de usuário através de lpInBuffer do DeviceIoControl. Em seguida, é passada para AfdNotifySock como o quarto parâmetro e para AfdNotifyRemoveIoCompletion como o terceiro parâmetro.

Baixar ferramenta