
Exploit per CVE-2021-40449 - Vulnerabilità di elevazione dei privilegi di Win32k (LPE)
Exploit per CVE-2021-40449 (Win32k - LPE)
CVE-2021-40449 è una use-after-free in Win32k che consente l'escalation dei privilegi locali.
La vulnerabilità è stata scoperta in the wild da Kaspersky.
L'exploit scoperto è stato scritto per supportare i seguenti prodotti Windows:
Tuttavia, questo exploit è attualmente testato solo sulle seguenti versioni:
Consiglio vivamente di leggere l'analisi tecnica di Kaspersky prima di procedere.
Come menzionato nell'analisi tecnica di Kasperky, la vulnerabilità risiede in GreResetDCInternal. Se un attaccante aggancia la callback in modalità utente DrvEnablePDEV, che viene chiamata durante hdcOpenDCW, è possibile distruggere il contesto di dispositivo originale chiamando ResetDC, causando una use-after-free nel kernel quando la callback in modalità utente ritorna.
Il seguente pseudo-codice è stato ricavato in parte dal codice sorgente trapelato di Windows XP e dal reverse engineering della versione più recente (pre-patch) di GreResetDCInternal da Win32kfull.sys. Le parti irrilevanti sono state rimosse con [...]. Cercare i commenti 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
// [...]
}
Come si può vedere dallo pseudo-codice, il vecchio contesto di dispositivo può essere liberato in una callback in modalità utente durante la chiamata a hdcOpenDCW; successivamente, il metodo DrvResetPDEV viene recuperato dal vecchio contesto di dispositivo e chiamato con (po->dhpdev, poNew->dhpdev).
Per creare e agganciare un contesto di dispositivo, si può procedere nel seguente modo:
EnumPrintersOpenPrinter, GetPrinterDriver e LoadLibraryExAGetProcAddress e DrvEnableDriverVirtualProtectCreateDC(NULL, printerName, NULL, NULL)A questo punto dovremmo avere un contesto di dispositivo per una stampante con le callback in modalità utente agganciate.
Siamo interessati a un solo hook, ovvero DrvEnablePDEV. Questo hook è interessante sotto due aspetti: innescare la UAF e controllare gli argomenti, come descritto in precedenza. Per innescare la vulnerabilità UAF, chiameremo ResetDC all'interno dell'hook, distruggendo così il vecchio contesto di dispositivo. Quando l'hook ritorna, saremo ancora all'interno della prima chiamata a GreResetDCInternal, che poco dopo recupererà e chiamerà il puntatore a funzione di DrvResetPDEV dal nostro vecchio e distrutto contesto di dispositivo, con i due argomenti restituiti da DrvEnablePDEV; il vecchio e il nuovo DHPDEV.
Se il vostro processo è in esecuzione con un livello di integrità medio, KASLR non dovrebbe essere un problema con l'aiuto di EnumDeviceDrivers e NtQuerySystemInformation.
Kaspersky menziona che l'exploit originale utilizzava oggetti palette GDI e una singola chiamata a una funzione del kernel per ottenere lettura/scrittura arbitraria della memoria. Questo exploit usa una tecnica per allocare un BitMapHeader nella big pool e RtlSetAllBits per abilitare tutti i privilegi sul token del processo corrente. Il BitMapHeader punterà a _SEP_TOKEN_PRIVILEGES del token del processo corrente. Chiamando RtlSetAllBits(BitMapHeader), è possibile abilitare tutti i privilegi per il token del processo corrente con una singola chiamata a una funzione del kernel. Da qui, si possono abusare dei nuovi privilegi per ottenere SYSTEM. Questo exploit usa SeDebugPrivilege per iniettare shellcode nel processo winlogon.exe.
