
CVE-2022-42046 DKOM के माध्यम से wfshbr64.sys स्थानीय विशेषाधिकार वृद्धि का प्रमाण अवधारणा
CVE-2022-42046 wfshbr64.sys स्थानीय विशेषाधिकार वृद्धि का प्रूफ ऑफ कॉन्सेप्ट
wfshbr64.sys और wfshbr32.sys द्वारा विशेष रूप से तैयार किया गया पेलोड किसी भी अनधिकृत उपयोगकर्ता को मनमाने EPROCESS ऑफसेट और फ्लैग्स मान के साथ बिटवाइज़ ऑपरेशन करने की अनुमति देता है, ताकि EPROCESS.Protection और EPROCESS.SignatureLevel फ्लैग्स में हेरफेर करके गेम प्रक्रिया को कोडजेन फुल सुरक्षा (एक फीचर के रूप में सुरक्षा छेद) तक जानबूझकर बढ़ाया जा सके।
ड्राइवर पर माइक्रोसॉफ्ट हार्डवेयर संगतता प्रकाशक द्वारा हस्ताक्षर किया गया है, जो माइक्रोसॉफ्ट हार्डवेयर प्रोग्राम के माध्यम से प्रस्तुत किया गया है।
इस परियोजना पर @DoranekoSystems के साथ सह-शोध किया गया था।
MIT. LICENSE देखें
ObRegisterCallbacks का उपयोग करें। इसका एक अच्छा उदाहरण यहाँ है।पूर्ण होने के बाद IRP का संदर्भ न दें। यदि आपने ड्राइवर वेरिफ़ायर सक्षम किया है, तो आप पकड़े जाएँगे।
IofCompleteRequest(Irp, IO_NO_INCREMENT); // IRP यहाँ मुक्त हो जाता है
return Irp->IoStatus.Status;
इसके बजाय आपको स्थानीय चर का उपयोग करना चाहिए।
NTSTATUS status = STATUS_SUCCESS;
Irp->IoStatus.Status = status;
IofCompleteRequest(Irp, IO_NO_INCREMENT); // IRP यहाँ मुक्त हो जाता है
return status;
ऐसा लगता है कि आप IoGetCurrentProcess के वापसी मान के विरुद्ध शून्य पॉइंटर की जाँच कर रहे हैं, लेकिन यह डिज़ाइन के अनुसार कभी शून्य पॉइंटर नहीं लौटाता है, इसलिए आपको इसकी जाँच करने की आवश्यकता नहीं है।
PEPROCESS CurrentProcess = IoGetCurrentProcess();
if ( !CurrentProcess ) // शून्य पॉइंटर की जाँच की आवश्यकता नहीं है
break;
रिपोर्ट के कुछ समय बाद, डेवलपर ने सुरक्षा छेद को एक फीचर के रूप में बनाने से पीछे हटने के बजाय हमारे पहले PoC को हराने के लिए एक चालाक "अतिरिक्त सत्यापन" लागू किया।
इसमें जाँचें जोड़ी गईं:
IOCTL_WFSHBR_REMOVE_FLAGIOCTL_WFSHBR_ADD_FLAGIOCTL_WFSHBR_AND_FLAGcase IOCTL_WFSHBR_ADD_FLAG: // 0xAA013884
if ( !KwfsVerifyCaller(Buffer) ) // कॉलर सत्यापित करें
break;
- if ( Buffer->ArbitraryEProcessOffset >= 0x1000 ) // ऑफसेट सीमा जाँच
+ if ( !KwfsVerifyOffsetAndFlags(Buffer->ArbitraryEProcessOffset,
+ Buffer->DesiredFlags) ) // ऑफसेट और फ्लैग्स सत्यापित करें
break;
*(ULONG*)(IoGetCurrentProcess() + Buffer->ArbitraryEProcessOffset) |= Buffer->DesiredFlags;
यह रूटीन हर बार क्लाइंट द्वारा EPROCESS के संशोधन का अनुरोध करने पर कॉल करने के लिए डिज़ाइन किया गया है, और इस PoC में ArbitraryEProcessOffset फ़ील्ड द्वारा प्रदान किए गए Offset का सत्यापन करता है ― और साथ ही इस PoC में DesiredFlags फ़ील्ड द्वारा प्रदान किए गए Flags का भी।
सत्यापन काफी सरल है क्योंकि यह प्रदान किए गए फ्लैग्स के प्रत्येक बिट फ़ील्ड में 1 बिट्स की गणना करता है और यदि गणना आठ से अधिक है तो यह विफल हो जाता है।
संभावित फ्लैग्स पैटर्न मैप केवल चार हैं:
22 00 00 0000 22 00 0000 00 22 0000 00 00 22यह कहते हुए, निम्नलिखित ऑपरेशन 4 बार करने से गारंटी मिल सकती है कि कम से कम एक प्रयास सफल होना चाहिए:
ArbitraryEProcessOffset फ़ील्ड को अनुक्रमणिका द्वारा घटाएं: offset - index,DesiredFlags फ़ील्ड में बिट्स को अनुक्रमणिका द्वारा समायोजित करें: flag << (index * 8)।ऑफसेट घटाया जाता है, इसलिए बिटफ़ील्ड समायोजन बिटवाइज़ ऑपरेटरों में ऑफसेट को समायोजित करने का कारण बनेगा।
*(ULONG*)(IoGetCurrentProcess() + offset) |= flags;
*(ULONG*)(IoGetCurrentProcess() + offset) &= ~flags;
हमने WfsProtectProcessSupreme और WfsUnprotectProcessSupreme फ़ंक्शन जोड़े हैं जो प्रयास करते हैं और नई ट्रिक को हरा देते हैं।
enum KwfsState {
KwfsStateOnceCall = 0,
KwfsStateNeedsValueEquality = 1,
KwfsStateValueHasBeenSet = 2,
};
bool KwfsVerifyOffsetAndFlags(_In_ ULONG offset, _In_ ULONG offset flags)
{
if (KwfsState::KwfsState == KwfsState::KwfsStateOnceCall) {
g_KwfsVerifyState = KwfsState::KwfsStateValueHasBeenSet;
g_KwfsVerifyStateOffset = offset;
g_KwfsVerifyStateFlags = flags;
if (offset < 0x1000) { // ऑफसेट सीमा जाँच यहाँ स्थानांतरित की गई
auto bitcount = 0;
for (auto i = 0; i < 32; ++i) { // फ्लैग्स में `1` बिट्स गिनें
if (flags & (1 << i)) {
++bitcount;
}
}
if (bitcount <= 8) { // गणना नौ से कम होनी चाहिए
g_KwfsVerifyState = 1;
return true;
}
}
}
else
{
if (g_KwfsVerifyState != KwfsState::KwfsStateValueHasBeenSet
|| offset != g_KwfsVerifyStateOffset
|| flags != g_KwfsVerifyStateFlags) {
return false;
}
}
return false;
}