
Exploit para CVE-2021-40449 - Vulnerabilidade de Elevação de Privilégio no Win32k (LPE)
Exploit para CVE-2021-40449 (Win32k - LPE)
CVE-2021-40449 é um use-after-free no Win32k que permite escalada de privilégio local.
A vulnerabilidade foi encontrada em campo pela Kaspersky.
O exploit descoberto foi escrito para suportar os seguintes produtos Windows:
No entanto, este exploit foi testado atualmente apenas nas seguintes versões:
Recomendo fortemente a leitura do artigo técnico da Kaspersky antes de prosseguir.
Conforme mencionado no artigo técnico por Kasperky, a vulnerabilidade existe em GreResetDCInternal. Se um atacante interceptar o callback em modo de usuário DrvEnablePDEV, que é chamado durante hdcOpenDCW, é possível destruir o contexto de dispositivo original chamando ResetDC, o que causa um use-after-free no kernel quando o callback de modo de usuário retorna.
O pseudo-código a seguir é parcialmente criado a partir do código-fonte vazado do Windows XP e por engenharia reversa do GreResetDCInternal mais recente (antes do patch) do Win32kfull.sys. As partes irrelevantes foram removidas com [...]. Procure pelos comentários VULN:.
BOOL GreResetDCInternal(
HDC hdc,
DEVMODEW *pdmw,
BOOL *pbBanding,
DRIVER_INFO_2W *pDriverInfo2,
PVOID ppUMdhpdev)
{
// [...]
HDC hdcNew;
{
// Create DCOBJ from HDC
DCOBJ dco(hdc);
if (!dco.bValid())
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
}
else
{
// Create DEVOBJ from `dco`
PDEVOBJ po(dco.hdev());
// [...]
// Create the new DC
// VULN: Can result in a usermode callback that destroys old DC, which
// invalidates `dco` and `po`
hdcNew = hdcOpenDCW(L"",
pdmw,
DCTYPE_DIRECT,
po.hSpooler,
prton,
pDriverInfo2,
ppUMdhpdev);
if (hdcNew)
{
po->hSpooler = NULL;
DCOBJ dcoNew(hdcNew);
if (!dcoNew.bValid())
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
}
else
{
// Transfer any remote fonts
dcoNew->pPFFList = dco->pPFFList;
dco->pPFFList = NULL;
// Transfer any color transform
dcoNew->pCXFList = dco->pCXFList;
dco->pCXFList = NULL;
PDEVOBJ poNew((HDEV)dcoNew.pdc->ppdev());
// Let the driver know
// VULN: Method is taken from old (possibly destroyed) `po`
PFN_DrvResetPDEV rfn = po->ppfn[INDEX_DrvResetPDEV];
if (rfn != NULL)
{
(*rfn)(po->dhpdev, poNew->dhpdev);
}
// [...]
}
}
}
}
// Destroy old DC
// [...]
}
Como pode ser visto no pseudo-código, o contexto de dispositivo antigo pode ser liberado em um callback de modo de usuário a partir da chamada hdcOpenDCW, e posteriormente, o método DrvResetPDEV é recuperado do contexto de dispositivo antigo e chamado com (po->dhpdev, poNew->dhpdev).
Para criar e interceptar um contexto de dispositivo, pode-se fazer o seguinte:
EnumPrintersOpenPrinter, GetPrinterDriver e LoadLibraryExAGetProcAddress e DrvEnableDriverVirtualProtectCreateDC(NULL, printerName, NULL, NULL)Agora devemos ter um contexto de dispositivo para uma impressora com callbacks de modo de usuário interceptados.
Estamos interessados em apenas um hook, a saber, DrvEnablePDEV. Este hook é interessante em dois aspectos: desencadear o UAF e controlar os argumentos, conforme descrito anteriormente. Para desencadear a vulnerabilidade UAF, chamaremos ResetDC dentro do hook, que destruirá o contexto de dispositivo antigo. Quando retornarmos do hook, ainda estaremos dentro do primeiro GreResetDCInternal, que logo em seguida obterá e chamará o ponteiro de função para DrvResetPDEV do nosso contexto de dispositivo antigo e destruído com os dois argumentos que foram retornados de DrvEnablePDEV; o antigo e o novo DHPDEV.
Se o seu processo estiver rodando com um nível de integridade médio, o KASLR não deve ser um problema com a ajuda de EnumDeviceDrivers e NtQuerySystemInformation.
Kaspersky menciona que o exploit original usava objetos de paleta GDI e uma única chamada de função do kernel para alcançar leitura/escrita arbitrária de memória. Este exploit usa uma técnica para alocar um BitMapHeader no big pool e RtlSetAllBits para habilitar todas as permissões no token do nosso processo atual. O BitMapHeader apontará para o _SEP_TOKEN_PRIVILEGES do token do nosso processo atual. Chamando RtlSetAllBits(BitMapHeader), é possível habilitar todas as permissões para o token do nosso processo atual com uma única chamada de função do kernel. A partir daí, pode-se abusar das novas permissões para obter SYSTEM. Este exploit usa SeDebugPrivilege para injetar shellcode no processo winlogon.exe.
