
CVE-2021-40449 के लिए एक्सप्लॉइट - Win32k विशेषाधिकार वृद्धि भेद्यता (LPE)
CVE-2021-40449 (Win32k - LPE) के लिए एक्सप्लॉइट
CVE-2021-40449 Win32k में एक use-after-free है जो स्थानीय विशेषाधिकार वृद्धि (local privilege escalation) की अनुमति देता है।
यह भेद्यता Kaspersky द्वारा जंगल में (in the wild) पाई गई थी।
खोजा गया एक्सप्लॉइट निम्नलिखित Windows उत्पादों को सपोर्ट करने के लिए लिखा गया था:
हालाँकि, यह एक्सप्लॉइट वर्तमान में केवल निम्नलिखित संस्करणों पर परीक्षण किया गया है:
आगे बढ़ने से पहले मैं Kaspersky के तकनीकी राइटअप को पढ़ने की अत्यधिक अनुशंसा करता हूँ।
जैसा कि Kaspersky के तकनीकी राइटअप में उल्लेख किया गया है, यह भेद्यता GreResetDCInternal में मौजूद है। यदि कोई हमलावर user-mode कॉलबैक DrvEnablePDEV को हुक करता है, जिसे hdcOpenDCW के दौरान कॉल किया जाता है, तो ResetDC को कॉल करके मूल डिवाइस कॉन्टेक्स्ट को नष्ट करना संभव है, जो user-mode कॉलबैक लौटने पर कर्नेल में use-after-free का कारण बनता है।
निम्नलिखित स्यूडो-कोड आंशिक रूप से लीक हुए Windows XP स्रोत कोड से और Win32kfull.sys से नवीनतम (पैच से पहले) GreResetDCInternal को रिवर्स-इंजीनियरिंग करके बनाया गया है। अप्रासंगिक भागों को [...] से हटा दिया गया है। 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
// [...]
}
जैसा कि स्यूडो-कोड से देखा जा सकता है, पुराने डिवाइस कॉन्टेक्स्ट को hdcOpenDCW कॉल से user-mode कॉलबैक में मुक्त किया जा सकता है, और बाद में, DrvResetPDEV विधि पुराने डिवाइस कॉन्टेक्स्ट से प्राप्त की जाती है और (po->dhpdev, poNew->dhpdev) के साथ कॉल की जाती है।
डिवाइस कॉन्टेक्स्ट बनाने और हुक करने के लिए, कोई निम्न कार्य कर सकता है:
EnumPrinters के साथ एक उपलब्ध प्रिंटर खोजेंOpenPrinter, GetPrinterDriver और LoadLibraryExA के साथ प्रिंटर ड्राइवर को मेमोरी में लोड करेंGetProcAddress और DrvEnableDriver के साथ प्रिंटर ड्राइवर की user-mode कॉलबैक तालिका प्राप्त करेंVirtualProtect के साथ प्रिंटर ड्राइवर की user-mode कॉलबैक तालिका को अनप्रोटेक्ट करेंCreateDC(NULL, printerName, NULL, NULL) के साथ प्रिंटर के लिए डिवाइस कॉन्टेक्स्ट बनाएंअब हमारे पास हुक किए गए user-mode कॉलबैक वाले प्रिंटर के लिए डिवाइस कॉन्टेक्स्ट होना चाहिए।
हमें केवल एक हुक में रुचि है, अर्थात् DrvEnablePDEV। यह हुक दो पहलुओं में दिलचस्प है: UAF को ट्रिगर करना और तर्कों को नियंत्रित करना, जैसा कि पहले वर्णित किया गया है। UAF भेद्यता को ट्रिगर करने के लिए, हम हुक के अंदर ResetDC को कॉल करेंगे, जो पुराने डिवाइस कॉन्टेक्स्ट को नष्ट कर देगा। जब हम हुक से लौटते हैं, तब भी हम पहले GreResetDCInternal के अंदर होंगे, जो थोड़ी देर बाद हमारे पुराने और नष्ट किए गए डिवाइस कॉन्टेक्स्ट से DrvResetPDEV के लिए फ़ंक्शन पॉइंटर प्राप्त करेगा और उसे उन दो तर्कों के साथ कॉल करेगा जो DrvEnablePDEV से लौटाए गए थे; पुराना और नया DHPDEV।
यदि आपकी प्रक्रिया मध्यम अखंडता स्तर (medium integrity level) के साथ चल रही है, तो EnumDeviceDrivers और NtQuerySystemInformation की सहायता से KASLR कोई समस्या नहीं होनी चाहिए।
Kaspersky उल्लेख करता है कि मूल एक्सप्लॉइट ने मनमानी मेमोरी रीड/राइट प्राप्त करने के लिए GDI पैलेट ऑब्जेक्ट्स और एकल कर्नेल फ़ंक्शन कॉल का उपयोग किया था। यह एक्सप्लॉइट बड़े पूल पर BitMapHeader आवंटित करने की एक तकनीक और हमारे वर्तमान प्रोसेस टोकन पर सभी विशेषाधिकार सक्षम करने के लिए RtlSetAllBits का उपयोग करता है। BitMapHeader हमारे वर्तमान प्रोसेस टोकन के _SEP_TOKEN_PRIVILEGES की ओर इंगित करेगा। RtlSetAllBits(BitMapHeader) को कॉल करके, एकल कर्नेल फ़ंक्शन कॉल के साथ हमारे वर्तमान प्रोसेस टोकन के लिए सभी विशेषाधिकार सक्षम करना संभव है। यहाँ से, कोई SYSTEM प्राप्त करने के लिए नए विशेषाधिकारों का दुरुपयोग कर सकता है। यह एक्सप्लॉइट winlogon.exe प्रक्रिया में शेलकोड इंजेक्ट करने के लिए SeDebugPrivilege का उपयोग करता है।
