Clase 1 — Mitigaciones modernas, token stealing y SeDebugPrivilege¶
← Volver al Módulo 7¶
Resumen: esta clase repasa las mitigaciones kernel del módulo 7 y baja a demos prácticas con WinDbg. Primero se revisa por qué
KASLR,SMEP,SMAP,HVCI,KCFGyKCETcambian el exploit moderno. Después se muestra cómo en23H2todavía se podía usar leaks para ubicarEPROCESS, cómo funciona el token stealing clásico copiando el token deSystem, por qué_EX_FAST_REFobliga a limpiar los low bits para usar!token, y cómo habilitarSeDebugPrivilegemodificando_TOKEN.Privileges.Presenty_TOKEN.Privileges.Enabled.
Tabla de Contenidos¶
- Contexto de la clase
- Repaso de mitigaciones kernel
24H2: por qué se pierden leaks cómodos- Data-only attacks: por qué siguen siendo fuertes
- Demo 1 — encontrar
EPROCESSy el offsetToken - Demo 2 — token stealing clásico a mano
_EX_FAST_REF: cuándo alinear y cuándo copiar crudo- Demo 3 — otra build con
Tokenen0x248 - Demo 4 — habilitar
SeDebugPrivilege - Contexto user/kernel en WinDbg
- Errores comunes vistos en vivo
- Workflow mental de la clase
- Cheat sheet
1. Contexto de la clase¶
La clase arranca con un repaso corto de las slides del módulo 7 y después pasa a demos. La idea no es quedarse en la definición de cada mitigación, sino ver cómo impacta en una cadena de explotación real.
Flujo general:
1. Repasar mitigaciones kernel modernas.
2. Comparar pre/post Windows 24H2.
3. Mostrar que el data-only attack evita varias mitigaciones de control-flow.
4. Hacer token stealing manual desde WinDbg.
5. Habilitar SeDebugPrivilege modificando bits del token.
6. Validar que ahora se pueden abrir/leer procesos SYSTEM.
2. Repaso de mitigaciones kernel¶
| Mitigación | Qué remarca la clase |
|---|---|
KASLR |
equivalente kernel de ASLR; al reiniciar cambian direcciones de módulos/data |
CFG |
valida indirect calls en runtime para impedir redirección arbitraria |
SMEP |
impide ejecutar código user desde kernel; CR4 bit 20 |
SMAP |
impide leer/escribir user desde kernel; CR4 bit 21, default off en Windows |
HVCI |
integridad de código, drivers firmados, virtualización |
KCFG |
CFG aplicado a kernel-mode |
KCET |
shadow stack para evitar corrupción de return addresses y complicar ROP |
Comentario clave sobre SMEP:
no podés saltar directo a user-mode;
para volver al ret2user clásico tendrías que deshabilitar el bit de CR4.
Comentario clave sobre SMAP:
3. 24H2: por qué se pierden leaks cómodos¶
Antes de 24H2, NtQuerySystemInformation era una vía cómoda:
NtQuerySystemInformation
-> leak de base kernel
-> leak de EPROCESS
-> leak de objetos kernel
-> incluso podía ayudar a ubicar pipes por tag
La clase recalca que en 23H2 esto hacía que, si ya tenías una primitiva read/write, la explotación fuese mucho más directa:
En 24H2/25H2 esa comodidad cae:
Conclusión:
la técnica data-only sigue funcionando,
pero el problema moderno es conseguir el leak o las direcciones correctas.
4. Data-only attacks: por qué siguen siendo fuertes¶
El instructor remarca que robar un token o cambiar privilegios no ejecuta shellcode.
Por eso:
SMEPno frena la técnica;KCETno frena directamente la técnica;CFG/KCFGno entran si no hay indirect call hijack;SMAPpodría complicar accesos user/kernel, pero no está default on.
Modelo:
kernel write primitive
-> modificar _EPROCESS.Token
-> o modificar _TOKEN.Privileges
-> SYSTEM / SeDebugPrivilege
5. Demo 1 — encontrar EPROCESS y el offset Token¶
Buscar el proceso¶
Por nombre:
Por PID:
Para System:
Confirmar el offset del token¶
No se hardcodea sin mirar la build:
Valores vistos en clase:
| Build / VM | Offset de _EPROCESS.Token |
|---|---|
| demo principal | 0x4B8 |
| otra VM/build | 0x248 |
Regla práctica:
6. Demo 2 — token stealing clásico a mano¶
El token stealer clásico hace esto:
Paso 1 — calcular la dirección donde escribir¶
Para el proceso objetivo:
Verlo con:
La clase insiste en no confundir:
target_EPROCESS + TokenOffset = dirección del campo
poi(target_EPROCESS+TokenOffset) = valor actual del token
Paso 2 — leer el token de System¶
Paso 3 — escribir el token de System en el target¶
eq significa edit qword.
Después de esto, el proceso objetivo apunta al mismo token que System.
7. _EX_FAST_REF: cuándo alinear y cuándo copiar crudo¶
_EPROCESS.Token es un _EX_FAST_REF: empaqueta puntero + refcount en los low bits.
Para usar !token, hay que limpiar el low nibble:
Si se pasa el valor crudo que termina en algo como ...5 o ...6, !token puede decir que no es token válido.
Pero para token stealing se copia el valor de memoria tal como está:
Resumen:
| Operación | Valor correcto |
|---|---|
Inspeccionar con !token |
puntero alineado (value & ~0xF) |
| Copiar token entre procesos | valor crudo del campo _EX_FAST_REF |
8. Demo 3 — otra build con Token en 0x248¶
La clase repite la idea en otra VM/build donde el offset no es 0x4B8, sino 0x248.
El método no cambia. Cambia el offset.
Conclusión:
9. Demo 4 — habilitar SeDebugPrivilege¶
La demo final no copia todo el token de System. Sólo cambia bits del token actual.
Objetivo:
habilitar SeDebugPrivilege
-> abrir procesos SYSTEM
-> leer/escribir memoria remota
-> actuar como debugger user-mode
Probar sin privilegio¶
El binario de prueba intenta abrir procesos sensibles:
Sin SeDebugPrivilege:
Encontrar el proceso actual¶
En la clase se toma el PID decimal y se convierte a hex:
Se usa:
El flag 1 muestra token e información suficiente. El flag 7 muestra mucha más información.
Ir a _TOKEN.Privileges¶
Confirmación:
Prender bit 20¶
SeDebugPrivilege es bit 20:
Valores vistos:
Comandos conceptuales:
Si sólo se modifica Present, el privilegio aparece como disponible pero no activo. Para que funcione debe estar en Present y Enabled.
Validar¶
Salida esperada:
Después de aceptar el cartelito del binario de prueba, la lectura del proceso System pasa a ser exitosa.
10. Contexto user/kernel en WinDbg¶
Advertencia práctica: cuando se debuggea user-mode desde kernel debugger, un break puede dejarte en otro contexto.
Flujo recomendado:
Notas:
- si trabajás sólo kernel, no hace falta
.reload /usertodo el tiempo; - si querés ver módulos user o pegar breakpoints user, sí hace falta contexto correcto;
lm m <module>sobre un módulo user no sirve si todavía estás en otro proceso.
11. Errores comunes vistos en vivo¶
- Confundir
0x4B8con0x4B0. - Usar offsets de una build en otra.
- Confundir dirección del campo token con valor del token.
- Pasar a
!tokenun_EX_FAST_REFsin limpiar low bits. - Sumar
0x40dos veces al token. - Habilitar
Presentpero olvidarse deEnabled. - Mantener Process Explorer abierto y ver información vieja después de modificar el token.
12. Workflow mental de la clase¶
1. Repasar mitigaciones: KASLR, CFG, SMEP, SMAP, HVCI, KCFG, KCET.
2. Entender que 24H2 cierra leaks cómodos por NtQuerySystemInformation.
3. Para token stealing:
a. buscar EPROCESS target
b. buscar EPROCESS System
c. confirmar TokenOffset
d. copiar System.Token crudo al target.Token
4. Para inspección:
a. alinear token con & ~0xF
b. usar !token y dt _TOKEN
5. Para SeDebugPrivilege:
a. TOKEN+0x40 = Present
b. TOKEN+0x48 = Enabled
c. prender bit 20 en ambos
6. Validar con !token y whoami /priv.
7. Reintentar abrir/leer procesos SYSTEM.
13. Cheat sheet¶
Comandos WinDbg¶
!process 0 0 <process.exe>
!process <pid_hex> 0
!process <pid_hex> 1
!process 4 0
dt ntkrnlmp!_EPROCESS Token
dt ntkrnlmp!_TOKEN <TOKEN>
dp <addr>
dps <addr>
!token <TOKEN_REAL>
eq <addr> <qword>
Offsets y valores¶
| Elemento | Valor |
|---|---|
SMEP |
CR4 bit 20 |
SMAP |
CR4 bit 21 |
_EPROCESS.Token demo 1 |
0x4B8 |
_EPROCESS.Token demo 2 |
0x248 |
_TOKEN.Privileges |
0x40 |
_SEP_TOKEN_PRIVILEGES.Enabled |
+0x8 desde Privileges |
SeDebugPrivilege |
bit 20 |
1 << 20 |
0x100000 |
Token stealing¶
TokenOffset = validar_por_build()
target_field = target_EPROCESS + TokenOffset
system_token = poi(system_EPROCESS + TokenOffset)
eq target_field system_token
Habilitar SeDebugPrivilege¶
Apunte basado en clase-modulo-7-1.txt. La clase aterriza las mitigaciones modernas en dos demos data-only: copiar el token de System y habilitar SeDebugPrivilege modificando bitmasks dentro de _TOKEN.