Saltar a contenido

Módulo 7 — Windows Mitigations and bypass techniques

← Volver al índice

Resumen: este módulo introduce las mitigaciones modernas de explotación kernel en Windows y cómo pensarlas desde el punto de vista ofensivo: KASLR, CFG/KCFG, SMEP, SMAP, HVCI, KCET, el cambio fuerte de Windows 11 24H2 sobre leaks de kernel base, la vulnerable driver blocklist, y los patrones de bypass más comunes: primero conseguir un leak, después construir ROP/gadgets, deshabilitar o esquivar SMEP, o directamente hacer ataques data-only sobre estructuras kernel como _EPROCESS y _TOKEN. También se estudia cómo ubicar y modificar privilegios dentro de un token (_EX_FAST_REF, _TOKEN, _SEP_TOKEN_PRIVILEGES) con WinDbg.


Tabla de Contenidos

  1. Contexto del módulo
  2. Mapa rápido de mitigaciones
  3. KASLR — Kernel Address Space Layout Randomization
  4. CFG, KCFG y KCET
  5. SMEP — Supervisor Mode Execution Prevention
  6. SMAP — Supervisor Mode Access Prevention
  7. HVCI — Hypervisor-Protected Code Integrity
  8. Mitigaciones antes y después de Windows 24H2
  9. Microsoft Vulnerable Driver Blocklist
  10. El fix que no fue: CVE-2025-53136
  11. Patrones de bypass
  12. Race conditions como amenaza moderna: CVE-2025-62215
  13. Por qué SMEP/SMAP no frenan un ataque data-only
  14. Encontrar _EPROCESS y el token de un proceso
  15. _EX_FAST_REF: puntero + refcount en el token
  16. Inspeccionar _TOKEN y _SEP_TOKEN_PRIVILEGES
  17. Modificar privilegios con eq
  18. Tabla de privilege bits
  19. Validar el cambio con !token y whoami /priv
  20. Workflow mental del módulo
  21. Cheat sheet
  22. Glosario corto

Clase 1 apuntes

1. Contexto del módulo

El módulo 7 cambia el foco: ya no alcanza con encontrar un bug kernel y lograr corrupción. En Windows moderno la explotación tiene que contestar varias preguntas:

1. ¿Cómo encuentro direcciones kernel si KASLR oculta bases?
2. ¿Puedo redirigir control flow si CFG/KCFG validan destinos indirectos?
3. ¿Puedo ejecutar shellcode user-mode desde ring 0 si SMEP está activo?
4. ¿Puedo leer/escribir user pages desde kernel si SMAP estuviera activo?
5. ¿Puedo cargar o abusar un driver vulnerable si existe blocklist?
6. ¿Hace falta ejecutar código o alcanza con tocar data kernel?

La idea central: las mitigaciones no eliminan la explotación, cambian el tipo de primitiva que conviene construir.

Dos familias grandes:

Familia Idea
Control-flow attack ganar RIP/EIP kernel, armar ROP, saltar a gadgets, deshabilitar SMEP, etc.
Data-only attack no ejecutar código nuevo; modificar estructuras como _TOKEN, _EPROCESS, privilegios, punteros o flags

2. Mapa rápido de mitigaciones

Slide 2 — classic kernel mitigations

Mitigación Qué intenta frenar Idea ofensiva típica
KASLR no saber direcciones kernel primero conseguir leak de base/punteros
CFG llamadas indirectas a destinos no válidos usar destinos válidos o data-only
KCFG versión kernel-mode de CFG evitar control-flow arbitrario o usar gadgets válidos
KCET shadow stack kernel complica ROP/ret hijacking clásico
SMEP kernel ejecutando páginas user ROP para deshabilitar SMEP o data-only
SMAP kernel accediendo páginas user en Windows está soportado por hardware pero no enabled default
HVCI integridad de código protegida por hypervisor evitar cargar/ejecutar código no íntegro; data-only/BYOVD más complejo
Driver blocklist cargar drivers vulnerables conocidos buscar drivers no bloqueados, variantes, configuración vulnerable

3. KASLR — Kernel Address Space Layout Randomization

KASLR randomiza direcciones base de código y data kernel al boot.

sin KASLR:
  ntoskrnl.exe siempre en base conocida
  gadgets / variables globales / funciones con direcciones fijas

con KASLR:
  ntoskrnl.exe, drivers y regiones kernel cambian por boot
  necesitás un leak antes de usar direcciones absolutas

Qué rompe:

  • hardcodear nt!PsInitialSystemProcess;
  • hardcodear gadgets de ntoskrnl.exe;
  • usar offsets absolutos de drivers;
  • cadenas ROP sin leak previo.

Lo que no rompe:

  • corrupción data-only si ya tenés punteros válidos;
  • offsets relativos dentro de estructuras (_EPROCESS.Token, _TOKEN.Privileges, etc.);
  • explotación que primero obtiene una dirección kernel y calcula todo relativo a esa base.

Modelo mental:

leak kernel pointer
  -> identificar módulo / base
  -> base + offset gadget/función/global
  -> usar primitive de read/write o ROP

4. CFG, KCFG y KCET

CFG — Control Flow Guard

CFG valida targets de llamadas indirectas en runtime.

call rax / call [mem] / jmp rax
  -> target tiene que ser válido según metadata de CFG

Objetivo: impedir que una corrupción de puntero de función salte a cualquier dirección arbitraria.

KCFG

KCFG aplica la idea de CFG al kernel-mode. Es relevante cuando el exploit quiere abusar de:

  • function pointers;
  • callbacks;
  • vtables;
  • dispatch tables;
  • indirect calls dentro de drivers.

Bypass conceptual:

no saltar a cualquier address,
sino a un target válido que igual sirva para la cadena,
o evitar control-flow hijack y hacer data-only.

KCET

KCET es CET para kernel-mode: shadow stack / protección contra manipulación clásica de returns.

Qué complica:

  • ROP basado en ret;
  • stack pivot + chain clásica;
  • sobrescribir return address y volver feliz.

Qué empuja a buscar:

  • data-only;
  • corrupción de objetos/callbacks compatibles con validaciones;
  • primitivas de read/write sobre estructuras sensibles;
  • bugs de lógica o race donde no hace falta ejecutar shellcode.

5. SMEP — Supervisor Mode Execution Prevention

SMEP impide que el kernel ejecute páginas user-mode.

CR4 bit 20 = SMEP

Antes de SMEP, una técnica clásica era ret2user:

1. poner shellcode en user-mode
2. corromper RIP kernel
3. hacer que kernel salte al shellcode user-mode
4. shellcode corre en ring 0

Con SMEP activo:

kernel RIP -> user page executable
  => fault / crash

Bypass típico de control-flow:

kernel bug
  -> leak KASLR
  -> ROP chain en kernel gadgets
  -> modificar CR4 y apagar SMEP
  -> saltar a shellcode / seguir ROP
  -> SYSTEM

Pero el módulo remarca algo importante: si el exploit es data-only, SMEP no ayuda, porque nunca se intenta ejecutar código user-mode.


6. SMAP — Supervisor Mode Access Prevention

SMAP impide que el kernel lea/escriba páginas user-mode arbitrariamente.

CR4 bit 21 = SMAP

Diferencia con SMEP:

Mitigación Bloquea
SMEP ejecución de user pages desde kernel
SMAP lectura/escritura de user pages desde kernel

Punto crítico de las slides:

SMAP está soportado por hardware,
pero NO está enabled por defecto en Windows.

Por eso muchas rutas METHOD_NEITHER / user pointers siguen siendo relevantes: Windows depende de validaciones explícitas (ProbeForRead, ProbeForWrite, try/except, checks de modo) en vez de tener SMAP cortando todo por hardware.


7. HVCI — Hypervisor-Protected Code Integrity

HVCI usa virtualización para reforzar code integrity.

Idea:

VBS / hypervisor
  -> protege decisiones de integridad de código
  -> hace más difícil ejecutar o cargar código kernel no autorizado

Impacto ofensivo:

  • complica drivers unsigned o manipulación de código;
  • reduce utilidad de payloads que dependen de patching directo de código kernel;
  • empuja a BYOVD con drivers firmados y no bloqueados;
  • empuja a data-only sobre estructuras ya existentes.

No significa que no haya explotación: significa que la cadena tiene que evitar violar code integrity o usar un camino donde el código vulnerable ya está cargado y firmado.


8. Mitigaciones antes y después de Windows 24H2

Slide 4 — mitigations before and after 24H2

Antes de Windows 24H2

Había leaks cómodos:

NtQuerySystemInformation(SystemModuleInformation)
  -> leakeaba bases de módulos kernel
  -> cualquier usuario podía consultarlo

Esto hacía que el bypass de KASLR fuera casi un trámite:

SystemModuleInformation
  -> ntoskrnl base
  -> nt base + offset(gadget/global)

También se menciona un PTE_BASE hardcodeado:

#define PTE_BASE 0xFFFFFA00`00000000

Esa clase de constantes históricas facilitaba introspección y ataques sobre page tables.

Después de Windows 24H2

Cambio importante:

kernel base addresses están SUPPRESSED
salvo que el caller tenga SeDebugPrivilege

Y SeDebugPrivilege queda restringido a procesos administrativos.

Consecuencia:

low-priv user ya no puede hacer:
  NtQuerySystemInformation(SystemModuleInformation) -> nt base

Entonces un exploit moderno low-priv necesita otro leak.


9. Microsoft Vulnerable Driver Blocklist

La blocklist intenta impedir que drivers vulnerables conocidos carguen.

BYOVD clásico:
  cargar driver firmado pero vulnerable
  usar IOCTL para read/write kernel
  elevar privilegios / desactivar defensas

blocklist:
  si el hash/cert/driver está listado -> Windows bloquea la carga

Límites conceptuales:

  • bloquea conocidos, no todos los vulnerables;
  • depende de configuración y versión;
  • puede haber variantes no listadas;
  • no arregla drivers vulnerables ya presentes/cargados;
  • no frena bugs en drivers de Microsoft o del propio sistema.

Regla práctica:

blocklist reduce la superficie BYOVD obvia,
pero no reemplaza hardening de drivers ni elimina EoP locales.

10. El fix que no fue: CVE-2025-53136

Slide 5 — CVE-2025-53136

Las slides presentan un caso donde la mitigación de 24H2 fue bypassed a los pocos meses.

Qué pasó

Un patch de 2024 para CVE-2024-43511 (bug TOCTOU) modificó:

RtlSidHashInitialize

El nuevo código, por un momento breve, escribía un puntero kernel a TOKEN dentro de un buffer controlado por user-mode.

kernel TOKEN pointer -> user-controlled buffer

Con ganar una carrera de lectura alcanzaba para capturar ese puntero.

Impacto

Low IL / AppContainer
  -> leak confiable de dirección kernel
  -> sin SeDebugPrivilege

Encadenado con un write-what-where:

leak TOKEN pointer
  -> calcular/ubicar estructuras
  -> primitive write-what-where
  -> full LPE en build 24H2 actual

Lección

mitigations close known doors, not all doors
cada patch nuevo es superficie de ataque nueva para los patches anteriores

La idea importante: Microsoft cerró el leak obvio (SystemModuleInformation), pero otro cambio introdujo un leak distinto.


11. Patrones de bypass

Slide 6 — bypass patterns

1. ROP chain en kernel

Kernel vulnerability
  -> control RIP / stack pivot
  -> ROP chain con gadgets kernel
  -> disable SMEP
  -> shellcode / token stealing
  -> SYSTEM

Requisitos:

  • bug que permita control-flow hijack;
  • leak para KASLR;
  • gadgets válidos;
  • lidiar con KCFG/KCET si aplican.

2. KASLR bypass first

info leak
  -> KASLR bypass
  -> gadgets conocidos
  -> disable SMEP
  -> payload kernel

El leak es el primer ladrillo. Sin leak, no sabés dónde están gadgets/funciones/globales.

3. Data-only attacks

no ejecutar user code
no inyectar shellcode
sólo modificar data kernel

Ejemplos:

  • cambiar _EPROCESS.Token;
  • modificar _TOKEN.Privileges;
  • cambiar flags de protección;
  • manipular listas o referencias;
  • corromper objetos para conseguir read/write.

Ventaja: SMEP no ayuda porque no hay ejecución de páginas user.


12. Race conditions como amenaza moderna: CVE-2025-62215

Slide 7 — CVE-2025-62215 race condition

Las slides usan CVE-2025-62215 como ejemplo real de race condition kernel parcheada en noviembre de 2025.

Características:

Campo Valor
Tipo privilege escalation vía race condition
Acceso local only
Privilegios low privileges / cualquier usuario
Complejidad alta
Resultado kernel memory corruption -> SYSTEM

Flujo conceptual:

low privilege user
  -> trigger race condition
  -> kernel memory corruption
  -> SYSTEM

La conclusión es que en builds modernos siguen apareciendo bugs explotables. Las mitigaciones suben la complejidad, pero las race conditions y UAFs siguen siendo amenazas principales.


13. Por qué SMEP/SMAP no frenan un ataque data-only

Slide 8 — takeaways

El caso moderno del módulo se apoya en data-only:

no shellcode execution
no ret2user
no ejecutar user pages
sólo manipular estructuras kernel

Por qué SMEP no ayuda

SMEP sólo bloquea ejecución de user pages desde kernel.

si nunca salto a user shellcode,
SMEP no tiene nada que bloquear.

Por qué SMAP podría ayudar, pero no está default

SMAP bloquearía accesos kernel a páginas user, pero la slide remarca:

Windows tiene SMAP off por defecto.

Entonces muchos bugs siguen dependiendo de checks de software.

Observaciones clave

  • siguen existiendo vulnerabilidades en 24H2/25H2;
  • mitigaciones hacen la explotación más difícil, no imposible;
  • race conditions y UAF siguen siendo de las clases más relevantes;
  • si el exploit logra una primitiva de write kernel, puede atacar data y evitar varias defensas de control-flow.

14. Encontrar _EPROCESS y el token de un proceso

Slide 9 — Looking for TOKEN

La segunda mitad del módulo baja a WinDbg y token internals.

Buscar el proceso por PID

Ejemplo del slide:

0: kd> !process 1a34 0     ; 1a34 es el PID
Searching for Process with Cid == 1a34
PROCESS ffff87869c4490c0   ; este es el EPROCESS
SessionId: 1  Cid: 1a34  Peb: f08083000  ParentCid: 03e8
DirBase: b3e0c002  ObjectTable: ffff9d07a63d0600  HandleCount: 98
Image: cmd.exe

Ubicar el campo Token

0: kd> dt ntkrnlmp!_EPROCESS Token ffff87869c4490c0
+0x4b8 Token : _EX_FAST_REF

En esa build:

_EPROCESS.Token offset = 0x4b8

Con recursión:

kd> dt -r ntkrnlmp!_EPROCESS ffff87869c4490c0
+0x4b8 Token : _EX_FAST_REF
   +0x000 Object : 0xffff9d07`a6b6d776 Void
   +0x000 RefCnt : 0y0110
   +0x000 Value  : 0xffff9d07`a6b6d776

15. _EX_FAST_REF: puntero + refcount en el token

Slide 10 — EX_FAST_REF

_EPROCESS.Token no es directamente un puntero plano: es _EX_FAST_REF.

ntdll!_EX_FAST_REF
+0x000 Object : Ptr64 Void
+0x000 RefCnt : Pos 0, 4 Bits
+0x000 Value  : Uint8B

La idea:

Value = puntero_al_token | refcount_low_bits

Como los objetos kernel están alineados, los bits bajos pueden almacenar refcount. Para obtener el puntero real al _TOKEN, se limpian los bits bajos:

token_object = Token.Value & ~0xF

Ejemplo del slide:

Value/Object mostrado: 0xffff9d07`a6b6d776
Token real alineado:   0xffff9d07`a6b6d770

Después:

!token ffff9d07`a6b6d770

16. Inspeccionar _TOKEN y _SEP_TOKEN_PRIVILEGES

Slide 11 — TOKEN fields

Primero se ve el token con !token:

!token ffff9d07`a6b6d770

Después se dumpea la estructura:

0: kd> dt ntkrnlmp!_TOKEN ffff9d07`a6b6d770
+0x000 TokenSource      : _TOKEN_SOURCE
+0x010 TokenId          : _LUID
+0x018 AuthenticationId : _LUID
+0x020 ParentTokenId    : _LUID
+0x028 ExpirationTime   : _LARGE_INTEGER 0x7fffffff`ffffffff
+0x030 TokenLock        : 0xffff8786`9c35ce90 _ERESOURCE
+0x038 ModifiedId       : _LUID
+0x040 Privileges       : _SEP_TOKEN_PRIVILEGES

Campo clave:

_TOKEN + 0x40 = Privileges : _SEP_TOKEN_PRIVILEGES

Estructura:

_SEP_TOKEN_PRIVILEGES
+0x000 Present          : uint64
+0x008 Enabled          : uint64
+0x010 EnabledByDefault : uint64

Significado:

Campo Qué indica
Present privilegios que existen en el token
Enabled privilegios activos ahora
EnabledByDefault privilegios que arrancan enabled por default

17. Modificar privilegios con eq

Slide 12 — modifying token privileges

En el ejemplo, la dirección de _SEP_TOKEN_PRIVILEGES es:

0xffff9d07`a6b6d7b0

Antes:

Present          = 0x602880000
Enabled          = 0x800000
EnabledByDefault = 0x40800000

Comandos usados:

eq ffff9d07`a6b6d7b0 602980000    ; Present
eq ffff9d07`a6b6d7b8 900000       ; Enabled

Después:

Present          = 0x602980000
Enabled          = 0x900000
EnabledByDefault = 0x0

Qué cambió:

0x602880000 -> 0x602980000
0x800000    -> 0x900000

Esa diferencia agrega el bit de SeDebugPrivilege (20). En hexadecimal:

1 << 20 = 0x100000
0x800000 | 0x100000 = 0x900000

Por eso después SeDebugPrivilege aparece como enabled.

Nota práctica: esto es una demo con WinDbg escribiendo memoria kernel. En un exploit real, el equivalente sería usar una primitiva de kernel write para cambiar esos QWORDs.


18. Tabla de privilege bits

Slide 13 — privilege bits

La slide 13 es una tabla visual de nombres de privilegios y número de bit. Los más relevantes para explotación/debugging:

Constante Privilegio Bit
SE_CREATE_TOKEN_NAME SeCreateTokenPrivilege 2
SE_ASSIGNPRIMARYTOKEN_NAME SeAssignPrimaryTokenPrivilege 3
SE_LOCK_MEMORY_NAME SeLockMemoryPrivilege 4
SE_INCREASE_QUOTA_NAME SeIncreaseQuotaPrivilege 5
SE_MACHINE_ACCOUNT_NAME SeMachineAccountPrivilege 6
SE_TCB_NAME SeTcbPrivilege 7
SE_SECURITY_NAME SeSecurityPrivilege 8
SE_TAKE_OWNERSHIP_NAME SeTakeOwnershipPrivilege 9
SE_LOAD_DRIVER_NAME SeLoadDriverPrivilege 10
SE_SYSTEM_PROFILE_NAME SeSystemProfilePrivilege 11
SE_SYSTEMTIME_NAME SeSystemtimePrivilege 12
SE_PROF_SINGLE_PROCESS_NAME SeProfileSingleProcessPrivilege 13
SE_INC_BASE_PRIORITY_NAME SeIncreaseBasePriorityPrivilege 14
SE_CREATE_PAGEFILE_NAME SeCreatePagefilePrivilege 15
SE_CREATE_PERMANENT_NAME SeCreatePermanentPrivilege 16
SE_BACKUP_NAME SeBackupPrivilege 17
SE_RESTORE_NAME SeRestorePrivilege 18
SE_SHUTDOWN_NAME SeShutdownPrivilege 19
SE_DEBUG_NAME SeDebugPrivilege 20
SE_AUDIT_NAME SeAuditPrivilege 21
SE_SYSTEM_ENVIRONMENT_NAME SeSystemEnvironmentPrivilege 22
SE_CHANGE_NOTIFY_NAME SeChangeNotifyPrivilege 23
SE_REMOTE_SHUTDOWN_NAME SeRemoteShutdownPrivilege 24
SE_UNDOCK_NAME SeUndockPrivilege 25
SE_SYNC_AGENT_NAME SeSyncAgentPrivilege 26
SE_ENABLE_DELEGATION_NAME SeEnableDelegationPrivilege 27
SE_MANAGE_VOLUME_NAME SeManageVolumePrivilege 28
SE_IMPERSONATE_NAME SeImpersonatePrivilege 29
SE_CREATE_GLOBAL_NAME SeCreateGlobalPrivilege 30
SE_TRUSTED_CREDMAN_ACCESS_NAME SeTrustedCredManAccessPrivilege 31
SE_RELABEL_NAME SeRelabelPrivilege 32
SE_INC_WORKING_SET_NAME SeIncreaseWorkingSetPrivilege 33
SE_TIME_ZONE_NAME SeTimeZonePrivilege 34
SE_CREATE_SYMBOLIC_LINK_NAME SeCreateSymbolicLinkPrivilege 35
SE_DELEGATE_SESSION_USER_IMPERSONATE_NAME SeDelegateSessionUserImpersonatePrivilege 36

Regla para prender un privilegio:

mask = 1ULL << bit
Present |= mask
Enabled |= mask

Ejemplo para SeDebugPrivilege:

bit = 20
mask = 1 << 20 = 0x100000

19. Validar el cambio con !token y whoami /priv

Slide 14 — SeDebugPrivilege enabled

Después de modificar el token, se valida de dos formas.

En kernel debugger

!token ffff9d07`a6b6d770

El output muestra:

20 0x00000014 SeDebugPrivilege    Attributes - Enabled

En user-mode

whoami /priv

Salida relevante:

Privilege Name        Description      State
====================  ===============  =======
SeDebugPrivilege      Debug programs   Enabled

Esto confirma que la escritura sobre _SEP_TOKEN_PRIVILEGES tuvo efecto visible en el proceso.


20. Workflow mental del módulo

1. Identificar mitigaciones presentes: KASLR, CFG/KCFG, SMEP, HVCI, KCET, blocklist
2. Preguntar si el exploit necesita control-flow o puede ser data-only
3. Si necesita gadgets -> primero conseguir leak de KASLR
4. En 24H2, SystemModuleInformation ya no da kernel base sin SeDebugPrivilege
5. Buscar leaks alternativos: bugs nuevos, races, TOCTOU, UAF, info leaks
6. Si hay control RIP -> ROP en kernel, no ret2user directo por SMEP
7. Si hay write kernel -> preferir data-only sobre _TOKEN/_EPROCESS
8. Encontrar proceso target con !process <pid> 0
9. Leer _EPROCESS.Token en offset de la build (ej. 0x4b8)
10. Limpiar bits bajos de _EX_FAST_REF: token = Value & ~0xF
11. Dump _TOKEN y ubicar _SEP_TOKEN_PRIVILEGES en +0x40
12. Calcular bit del privilegio deseado (ej. SeDebugPrivilege = 20)
13. Present |= 1 << bit; Enabled |= 1 << bit
14. Escribir QWORDs con primitive kernel write o eq en WinDbg
15. Validar con !token y whoami /priv

21. Cheat sheet

Mitigaciones

Mitigación Bit / dato Nota
SMEP CR4 bit 20 bloquea ejecución de user pages desde kernel
SMAP CR4 bit 21 bloquea access a user pages desde kernel; no enabled default en Windows
KASLR base random por boot requiere info leak
CFG user/control-flow valida indirect calls
KCFG kernel/control-flow versión kernel de CFG
KCET shadow stack complica ROP basado en returns
HVCI VBS/code integrity complica código kernel no íntegro

Windows 24H2

Antes:
  NtQuerySystemInformation(SystemModuleInformation) -> kernel base para cualquier user

Después:
  kernel bases suprimidas si no hay SeDebugPrivilege
  SeDebugPrivilege restringido a procesos administrativos

WinDbg token commands

!process <pid> 0

dt ntkrnlmp!_EPROCESS Token <EPROCESS>
dt -r ntkrnlmp!_EPROCESS <EPROCESS>

; limpiar low nibble del _EX_FAST_REF
; token = value & ~0xF

!token <TOKEN>
dt ntkrnlmp!_TOKEN <TOKEN>

Offsets de la demo

Estructura Campo Offset
_EPROCESS Token 0x4b8
_TOKEN Privileges 0x40
_SEP_TOKEN_PRIVILEGES Present 0x0
_SEP_TOKEN_PRIVILEGES Enabled 0x8
_SEP_TOKEN_PRIVILEGES EnabledByDefault 0x10

Direcciones de la demo

EPROCESS cmd.exe:       ffff87869c4490c0
_EX_FAST_REF Value:     ffff9d07`a6b6d776
TOKEN real alineado:    ffff9d07`a6b6d770
Privileges struct:      ffff9d07`a6b6d7b0

Activar SeDebugPrivilege en la demo

bit(SeDebugPrivilege) = 20
mask = 1 << 20 = 0x100000

antes:
  Present = 0x602880000
  Enabled = 0x800000

después:
  Present = 0x602980000
  Enabled = 0x900000

WinDbg:
  eq ffff9d07`a6b6d7b0 602980000
  eq ffff9d07`a6b6d7b8 900000

Patrones de bypass

KASLR bypass:
  info leak -> base -> offsets/gadgets

SMEP bypass clásico:
  ROP kernel -> clear CR4 bit 20 -> ret2user/shellcode

Mitigation-agnostic:
  data-only -> modify TOKEN/EPROCESS -> no shellcode

22. Glosario corto

Término Descripción
KASLR Randomización de bases kernel; obliga a conseguir leaks.
CFG Control Flow Guard; valida targets indirectos.
KCFG CFG aplicado al kernel.
KCET CET/shadow stack en kernel, complica ROP clásico.
SMEP Impide ejecutar user pages desde kernel; CR4 bit 20.
SMAP Impide leer/escribir user pages desde kernel; CR4 bit 21, no default en Windows.
HVCI Code integrity protegida por hypervisor.
BYOVD Bring Your Own Vulnerable Driver; cargar/abusar driver firmado vulnerable.
Vulnerable Driver Blocklist Lista de drivers vulnerables conocidos que Windows bloquea.
Data-only attack Exploit que sólo modifica datos kernel, sin ejecutar shellcode.
_EPROCESS Estructura kernel de proceso; contiene el campo Token.
_EX_FAST_REF Empaqueta puntero + refcount en bits bajos.
_TOKEN Objeto token de seguridad del proceso/thread.
_SEP_TOKEN_PRIVILEGES Bitmasks de privilegios presentes/enabled/default del token.
SeDebugPrivilege Privilegio de debugging; bit 20, requerido para ciertos leaks post-24H2.
eq Comando WinDbg para escribir un QWORD en memoria.

Apunte basado en el PDF Module_07_Windows_Mitigations_and_bypass_techniques.pdf y en la inspección visual de sus slides renderizados. El módulo resume mitigaciones kernel modernas, sus límites, patrones de bypass y una demo práctica de manipulación de privilegios en _TOKEN para habilitar SeDebugPrivilege.