Los atacantes abusan de ATT&CK T1134
En nuestra anterior publicación de blog sobre tokens de acceso de Windows para profesionales de la seguridad, abordamos los siguientes temas:
- La relación entre las sesiones de inicio de sesión y los tokens de acceso
- Cómo funciona la autenticación de red en entornos Windows
Tras repasar algunos de los conceptos clave de la seguridad de Windows, ahora partiremos de este conocimiento y comenzaremos a analizar cómo los atacantes pueden abusar de la funcionalidad legítima de Windows para moverse lateralmente y comprometer los dominios de Active Directory.
Este blog intentó deliberadamente abstraer el funcionamiento de protocolos de autenticación de red específicos de Windows (por ejemplo, NTLM y Kerberos) siempre que fue posible. En consecuencia, puede haber casos en los que el comportamiento propio de estos protocolos difiera del comportamiento descrito a continuación. También presupone un conocimiento básico del protocolo de autenticación Kerberos¹.
Además, el material tratado en este serial de artículos se empleó para una presentación en BlackHat 2020 titulada "Detección de manipulación de tokens de acceso". La presentación se puede consultar aquí y las diapositivas aquí.
Manipulación de tokens de acceso (técnica ATT&CK: T1134)
Tras explicar en nuestra entrada anterior del blog los principios básicos del funcionamiento de las sesiones de inicio de sesión y los tokens de acceso, tanto a nivel local como para aplicaciones distribuidas, esta sección explicará cómo los atacantes pueden abusar de los tokens de acceso y atacar las relaciones de confianza fundamentales en los dominios de Windows para comprometer redes enteras. El objetivo de esta sección es describir las técnicas de manipulación de tokens de acceso empleadas por los atacantes en el contexto de una intrusión simulada.
Cabe destacar que ya existe una amplia bibliografía de excelente calidad sobre la manipulación de tokens de acceso (a la que se hará referencia en numerosas ocasiones a lo largo de esta publicación). Este blog pretende ampliar este conocimiento abordando la manipulación de tokens de acceso desde una perspectiva diferente: la relación entre los tokens de acceso, las sesiones de inicio de sesión y las credenciales almacenadas en caché. En opinión del autor, cualquier descripción de la manipulación de tokens que no considere estas relaciones representa solo la punta del iceberg. Por consiguiente, la definición de manipulación de tokens de acceso que se presenta en este blog es quizás mucho más amplia de lo que se suele creer.
Compromiso inicial
En caso de que un atacante logre infiltrarse en una red mediante spear phishing, normalmente terminará con un shell ejecutar en el contexto de seguridad del usuario comprometido. Esto puede lograrse mediante la creación de un nuevo proceso o la inyección directa en la memoria (dependiendo de la carga útil), pero el resultado final es el mismo: el código del atacante se ejecuta en un proceso que posee un token de acceso perteneciente al usuario comprometido.
Esto significa que cualquier comprobación de acceso local empleará el token de acceso del usuario comprometido y cualquier intento de autenticación remota empleará las credenciales almacenadas en caché del usuario comprometido². Por lo tanto, el atacante puede, tanto localmente como a través de la red, realizar todas las acciones que el usuario comprometido puede. Por ejemplo, si alguna aplicación sitio web interno emplea el inicio de sesión único (SSO) (SSO) de Windows, un atacante podrá acceder a ella como si fuera el usuario.
Manipulación de fichas: El 'arte de lo posible'
Por lo general, un atacante querrá mover desde el punto final comprometido a otro host lo más rápido posible3. Al considerar el movimiento lateral desde la perspectiva de la manipulación de tokens, el atacante tiene efectivamente tres opciones4, cada una de las cuales está limitada por la relación fundamental entre los tokens de acceso, las sesiones de inicio de sesión y las credenciales almacenadas en caché, como se ilustra a continuación:

Si un atacante quiere moverse lateralmente a través del inicio de sesión único (SSO) (SSO) de Windows, entonces deben existir estos tres vínculos (por ejemplo, que tenga un identificador para un token que esté vinculado a una sesión de inicio de sesión respaldada por las credenciales de su objetivo). De lo contrario, la libertad de movimiento de un atacante depende de la creación de nuevos enlaces (por ejemplo, nuevas sesiones de inicio de sesión) o de la modificación de los existentes (por ejemplo, cambiando las credenciales almacenadas en caché o la sesión de inicio de sesión a la que apunta su token de acceso). Estas limitaciones se analizan con más detalle en las tres opciones que se presentan a continuación:
1. Robar el token de un usuario privilegiado que ya inició sesión (inicio de sesión sin red).
Si otro usuario con privilegios ya inició sesión en el host comprometido, un atacante puede escalar sus privilegios y obtener un identificador para un token de acceso que representa a este usuario. Independientemente de si el atacante suplanta la identidad del token robado o inicia un nuevo proceso, si ese token está vinculado a una sesión de inicio de sesión que no es de red , tendrá credenciales almacenadas en caché y, por lo tanto, el atacante puede autenticar fuera del equipo para acceder a otro host5. Por lo tanto, esta técnica permite a un atacante usar las credenciales de otro usuario para acceder a hosts remotos a través de la red (mediante SSO de Windows) y, por lo tanto, pivotar sin necesidad de extraer las credenciales6.
Cabe destacar que los ataques de manipulación de tokens generalmente se relacionan con dos objetivos distintos: el movimiento lateral (que es el tema central de este blog) y la escalada de privilegios local7. El robo de tokens tiende a asociar con este último (por ejemplo, robar o suplantar un token con el fin de eludir las comprobaciones de acceso local, en lugar de emplear las credenciales almacenadas en caché para la autenticación remota), por lo que este blog no lo abordará con mayor detalle. Sin embargo, los siguientes recursos son útiles para ampliar la información:
- https://posts.specterops.io/understanding-and-defending-against-access-token-theft-finding-alternatives-to-winlogon-exe-80696c8a73b
- https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/
- https://labs.f-secure.com/assets/blogfiles/mwri-security-implications-of-windows-access-tokens-2008-04-14.pdf
2. Crea una nueva sesión de inicio de sesión con credenciales robadas y suplanta la identidad del token devuelto o inicia un nuevo proceso con él.
En este caso, no hay ningún usuario privilegiado conectado (y, por lo tanto, no hay ningún token de acceso/sesión de inicio de sesión útil correspondiente), pero el atacante aún necesita encontrar una manera de cambiar su contexto de seguridad.
Por lo tanto, el atacante debe encontrar las credenciales en otro lugar y usarlas para crear una nueva sesión de inicio de sesión como el usuario comprometido. Dado que Windows almacena automáticamente en caché las credenciales para ciertos tipos de inicio de sesión, el atacante puede obtener un token de acceso recién generado, respaldado por las credenciales robadas. Una vez que el atacante tiene acceso a un token que representa al usuario comprometido, puede autenticar fuera del sistema mediante el proceso estándar de inicio de sesión único (SSO) (SSO) de Windows.
Normalmente, los atacantes obtienen credenciales en texto plano mediante Kerberoasting o buscando credenciales en texto plano no seguras en todos los recursos accesibles, como recursos compartidos de red, SharePoint, wikis internas, GitHub empresarial, Zendesk, etc.8
3. Cambiar las credenciales almacenadas en caché asociadas con su token de acceso actual por credenciales robadas (por ejemplo, legítimamente a través de una API o “ilegítimamente”modificando directamente la memoria de lsass).
En este escenario, en lugar de crear una nueva sesión de inicio de sesión, el atacante modifica las credenciales almacenadas en caché asociadas con su token de acceso actual (y, por lo tanto, con la sesión de inicio de sesión). Como veremos, muchos proveedores de soporte de seguridad de Windows (SSP) ofrecen formas nativas de hacer esto (y que no requieren privilegios elevados).
Como alternativa, los atacantes pueden optar por la vía "directa" y modificar manualmente las credenciales almacenadas en caché en lsass. Esto requiere privilegios elevados para obtener un identificador de escritura (por ejemplo, PROCESS_VM_WRITE) para lsass a través de OpenProcess. Esto es típico de los ataques de tipo pass-the-hash, como veremos más adelante.
Ataques de manipulación de tokens de acceso
Esta entrada de blog analizará cuatro técnicas comunes empleadas por los atacantes (todas las cuales pueden clasificar como variaciones de la opción 3 anterior):
- La bandera NETONLY
- Pasar el boleto
- Pasar el hash
- Pasar por encima del hash
1. La bandera NETONLY
La API de Windows proporciona la función LogonUser para crear una nueva sesión de inicio de sesión para un usuario (o entidad principal) determinado9:
BOOL LogonUserW(
LPCWSTR lpszUsername,
LPCWSTR lpszDomain,
LPCWSTR lpszPassword,
DWORD dwLogonType,
DWORD dwLogonProvider,
PHANDLE phToken
);
El parámetro clave a tener en cuenta es dwLogonType, que especifica el tipo de inicio de sesión. Por ejemplo, si un usuario inicia sesión físicamente en su estación de trabajo, se establecerá en LOGON32_LOGON_INTERACTIVE. El tipo de inicio de sesión especificado determinará el tipo y los privilegios del token devuelto.
Por ejemplo, en el caso de un inicio de sesión interactivo, LogonUserW devolverá un token de acceso principal y, si UAC está habilitado, este token será un token filtrado (lo que significa que tendrá integridad media y no será elevado). Esto tiene una excepción: si el usuario es una cuenta de administrador local (por ejemplo, un SID *-500), Windows devolverá automáticamente un token elevado10.
En el caso de un inicio de sesión de red (LOGON32_LOGON_NETWORK), se devuelve un token de suplantación (ya que normalmente un servidor lo usaría para realizar trabajo en nombre de los clientes remotos). Además, si el usuario está en el grupo de administradores locales, el token se eleva y tiene todos los privilegios habilitados11.
Estas permutaciones de LogonUser se recogen en la tabla siguiente:
dwLogonType | Token devuelto | ¿Almacenar credenciales en caché? | ¿El token devuelto está elevado? (si es administrador) |
Interactivo (LOGON32_LOGON_INTERACTIVE) | Primario | Sí | No (se aplican las Acciones de Usuario) |
Interactivo (Cuenta de administrador local, por ejemplo, rid-500) | Primario | Sí | Sí |
Red (LOGON32_LOGON_NETWORK) | Interpretación | Nº12 | Sí (+ todos los privilegios habilitados) |
Red (cuenta de administrador local, por ejemplo, rid-500) | Interpretación | No | Depende de la configuración remota de UAC13 |
La clave reside en que LogonUser devuelve un identificador para un token recién creado, que ahora puede emplear para la suplantación de identidad.
Si el token devuelto es un token primario , primero debe convertir en un token de suplantación a través de DuplicateTokenEx pasando un TokenType de TokenImpersonate14:
BOOL DuplicateTokenEx(
HANDLE hExistingToken,
DWORD dwDesiredAccess,
LPSECURITY_ATTRIBUTES lpTokenAttributes,
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
TOKEN_TYPE TokenType,
PHANDLE phNewToken
);
La función SetThreadToken se puede usar para asignar el token de suplantación devuelto al hilo actual:
BOOL SetThreadToken(
Subproceso PHANDLE,
Token HANDLE
);
Como alternativa, la API de Windows proporciona la función ImpersonateLoggedOnUser , que permitirá al hilo que realiza la llamada suplantar el contexto de seguridad del usuario representado por el token pasado:
BOOL ImpersonateLoggedOnUser(
HANDLE hToken
);
ImpersonateLoggedOnUser tiene el beneficio adicional de que comprobará automáticamente el tipo de token pasado y lo convertirá en un token de suplantación (a través de NtDuplicateToken) si se pasó un token principal (como este tipo de token). no puede ser empleado por un hilo para suplantar)15.
Cabe señalar que, desde la perspectiva de la evasión de defensas, ambas API de suplantación son envoltorios ligeros sobre la llamada al sistema no documentada NtSetInformationThread (por ejemplo, llamada con una ThreadInformationClass de ThreadImpersonationToken). Por lo tanto, son un buen objetivo para que los atacantes empleen llamadas al sistema directas para eludir los ganchos en modo de usuario mediante técnicas como https://github.com/jthuraisamy/syswhispers.
Además, es importante destacar que Windows tiene normas estrictas en lo que respecta a la suplantación de identidad. Estos elementos se enumeran a continuación y se tomaron de la página de MSDN para ImpersonateLoggedOnUser:
Todas las funciones de suplantación, incluida ImpersonateLoggedOnUser, permiten aplicar la suplantación si se cumple alguna de las siguientes condiciones:
- El nivel de suplantación del token es inferior a SecurityImpersonation, como SecurityIdentification o SecurityAnonymous.
- El llamador tiene el privilegio SeImpersonatePrivilege.
- Un proceso (u otro proceso en la sesión de inicio de sesión del llamador) creó el token empleando credenciales explícitas a través de la función LogonUser o LsaLogonUser.
La identidad autenticada es la misma que la del llamador
Además, el nivel de integridad del token suplantado también debe ser menor o igual al nivel de integridad del proceso que realiza la llamada; de lo contrario, la llamada de suplantación también fallará16. Por lo tanto, suponiendo que un atacante sin privilegios elevados inicie sesión en un usuario administrador de forma interactiva mediante credenciales robadas, y que el UAC esté habilitado, recibirá un token sin privilegios elevados (por ejemplo, filtrado) y, por lo tanto, no tendrá problemas para suplantar al usuario devuelto y mover lateralmente, etc.
“La curiosa bandera /NETONLY”17
Sin embargo, un atacante podría descubrir que intentar iniciar sesión con un usuario que emplea credenciales robadas falla. Esto puede deber a múltiples razones, como que las credenciales sean válidas, pero la cuenta no tenga licencias para iniciar sesión en esa estación de trabajo específica, o que solo sean válidas en un dominio diferente, etc. Además, El atacante también podría querer evitar iniciar sesión en una cuenta con altos privilegios, ya que esto podría parecer muy anómalo en ciertos contextos (por ejemplo, que un administrador de dominio inicie sesión en el host de un usuario empresarial con pocos privilegios debería ser sumamente sospechoso).18
En este escenario, la bandera LOGON32_LOGON_NEW_CREDENTIALS resulta útil para el atacante. Si un atacante llama a la función LogonUserW con esta bandera y proporciona un conjunto válido de credenciales (por ejemplo, obtenidas mediante el rastreo de recursos compartidos de archivos), Windows le permitirá duplicar su token actual, pero haciéndolo apuntar a una nueva sesión de inicio de sesión, denominada sesión de inicio de sesión con nuevas credenciales, que almacena en caché las credenciales robadas. Como resultado, el usuario conserva el mismo contexto de seguridad localmente (es decir, conserva una copia del mismo token de acceso; simplemente apunta a una nueva sesión de inicio de sesión); sin embargo, cualquier intento de autenticación remota empleará las nuevas credenciales proporcionadas en la llamada a LogonUserW19. Esto se ilustra en el siguiente diagrama:

Por lo tanto, el indicador LOGON32_LOGON_NEW_CREDENTIALS proporciona un mecanismo nativo para que su token de acceso actual apunte a una sesión de inicio de sesión diferente y, por consiguiente, a credenciales diferentes .20
Tenga en cuenta que llamar a LogonUserW con el indicador LOGON32_LOGON_NEW_CREDENTIALS no valida las credenciales cuando se realiza la llamada (pueden ser completamente inválidas), sino que solo son validadas por un controlador de dominio en el momento de cualquier solicitud de autenticación remota.
Como ejemplo adicional, una revisión rápida del código para la tarea 'MakeToken' del código abierto. El framework .NET C2 Covenant revela exactamente el mismo enfoque: toma una combinación de nombre de usuario y contraseña y crea una nueva sesión de inicio de sesión/token con ellos pasando el indicador LOGON32_LOGON_NEW_CREDENTIALS antes de proceder a suplantar la identidad del token devuelto.
Además, puede replicar exactamente el mismo comportamiento con CreateProcessWithLogonW pasando un dwLogonFlags de LOGON_NETCREDENTIALS_ONLY.21
BOOL CreateProcessWithLogonW(
LPCWSTR lpUsername,
LPCWSTR lpDomain,
LPCWSTR lpPassword,
DWORD dwLogonFlags,
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
La diferencia clave radica en que esto implica la creación de un nuevo proceso con el token devuelto, a diferencia de la suplantación de identidad dentro del proceso que se analizó anteriormente. De hecho, la utilidad integrada de Windows, runas, es una simple envoltura de CreateProcessWithLogonW, y el indicador /NETONLY proporciona una forma nativa de crear un nuevo proceso con credenciales de red diferentes, como se muestra a continuación:

De la misma forma que se describió anteriormente, el nuevo símbolo del sistema parece ejecutar localmente con el mismo usuario (es decir, los atributos almacenados en caché en el token son los mismos para cualquier comprobación de acceso local ; por lo tanto, whoami devuelve 'astro\cosmo'), pero cualquier intento de autenticación remota se realizará empleando las credenciales robadas del usuario 'ASTRO\Administrator'.
Estas sesiones de inicio de sesión se pueden visualizar mediante la herramienta LogonSessions de SysInternals. Las sesiones de inicio de sesión creadas con la bandera NewCredentials se pueden identificar mediante el campo Tipo de inicio de sesión, como se muestra a continuación:

Además, las sesiones de inicio de sesión anómalas de NewCredentials (por ejemplo, las generadas mediante el gadget NETONLY) dejan rastros en los registros de eventos de Windows. Estos se pueden identificar mediante el ID de evento 4642 y un LogonType de 9. En la siguiente imagen se muestra un ejemplo:

Tenga en cuenta que el usuario original se muestra en el campo SubjectUserName y las credenciales de red especificadas (por ejemplo, las credenciales pasadas) se muestran en los campos TargetOutboundUser/DomainName.22
Elevación automática
Otra peculiaridad desde la perspectiva de la escalada de privilegios locales es que, para las cuentas rid-500, CreateProcessWithLogonW elevará automáticamente el token devuelto para los inicios de sesión interactivos (por ejemplo, ignorará el UAC). Por lo tanto, a CreateProcessWithLogonW se le puede pasar una cuenta de administrador local/de dominio para ejecutar un proceso elevado desde un contexto medio/sin elevación.
Este comportamiento se puede verificar usando `runas`. Por ejemplo, cuando se usa `runas` para iniciar un proceso con una cuenta de administrador local (p. ej., `runas /user:"Administrator" cmd.exe`), el proceso resultante tendrá privilegios elevados (p. ej., integridad alta). Sin embargo, cuando se usa una cuenta que no pertenece al grupo de administradores locales (pero que aún así está en el grupo de administradores locales), el proceso resultante no tendrá privilegios elevados (p. ej., será un token filtrado/integridad media).
Nota que este comportamiento es coherente con las permutaciones enumeradas para LogonUserW en la Tabla 1. Por lo tanto, un atacante sin privilegios elevados también podría iniciar sesión como usuario administrador (sin rid-500) como inicio de sesión de red y recibir un token elevado con todos los privilegios habilitados.
Sin embargo, según las reglas de suplantación de identidad previamente descritas, el atacante no debería poder hacer nada con este token, ya que cualquier intento de suplantar el token elevado debería fallar, Puesto que tiene un nivel de integridad superior al del emisor. No obstante, es posible duplicar el token elevado, reducir el nivel de integridad del token copiado a medio (NB 'isElevated' sigue siendo verdadero)23 y comenzar a suplantar el token elevado desde un contexto de integridad no elevado/medio24. Por lo tanto, desde la perspectiva de un token de suplantación, se puede eludir el comportamiento predeterminado de Windows de elevar solo ciertas cuentas y suplantar un token elevado independientemente de si la cuenta es una cuenta rid-500 o no.
Creación de procesos
Ten en cuenta que, por defecto, cuando creas un proceso hijo, este hereda su token principal incluso si actualmente está suplantando otro contexto de seguridad25. Por ejemplo, si estás suplantando un token SYSTEM y llamas a CreateProcess(), seguirá heredando una copia del token del proceso principal (en lugar de heredar el contexto de seguridad SYSTEM del hilo).26
Por lo tanto, si un atacante desea iniciar un nuevo proceso en un contexto de seguridad diferente, debe:
- Emplea CreateProcessWithLogonW con credenciales explícitas (como se explicó anteriormente).
- Llama a CreateProcessWithTokenW o CreateProcessAsUserW y pasa un identificador a un token (por ejemplo, con el token devuelto por LogonUser o, más comúnmente, a través de un token robado).
A ambas funciones se les puede pasar un identificador para un token que representa el contexto de seguridad del nuevo proceso.27
BOOL CreateProcessWithTokenW(
HANDLE hToken,
DWORD dwLogonFlags,
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine, {cph0} DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
BOOL CreateProcessAsUserW(
HANDLE hToken,
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
cph0} LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
Por ejemplo, CreateProcessAsUserW suele ser empleado por el propio sistema operativo para iniciar el shell del usuario tras un inicio de sesión exitoso (también lo emplea el servicio de inicio de sesión secundario cuando un usuario llama a createProcessWithLogonW). En este sentido, permite al usuario «inyectar un proceso en la sesión de inicio de sesión que elija» 28. Cabe destacar que ambas API son envoltorios de CreateProcessInternalW (ubicada en KernelBase.dll).
La diferencia clave aquí es que quien realiza la llamada debe tener ciertos privilegios para llamar a estas dos API29. Sin embargo, desde la perspectiva de un atacante, el objetivo es el mismo: obtener la ejecución de código en el contexto de seguridad del usuario objetivo con el fin de moverse lateralmente.
Una peculiaridad interesante es que el marco PowerShell Empire se vio obligado a adoptar este enfoque de generación de procesos (que, sin duda, genera mucho más ruido desde la perspectiva de la detección) debido a las limitaciones en la forma en que PowerShell maneja la suplantación de identidad y los hilos múltiples, como se explica con más detalle en las notas que se anexan .
En cualquier caso, el flujo de trabajo para emplear técnicas de manipulación de tokens de generación de procesos sigue siendo el mismo. Una vez que el atacante obtuvo un identificador para el token (a través de OpenProcess/OpenProcessToken si se trata del token principal, o OpenThread/OpenThreadToken en el caso de un hilo que suplanta la identidad), el atacante debe llamar a DuplicateTokenEx para crear una copia local (principal) del token objetivo y, a continuación, proporcionar esta copia a las funciones CreateProcessWithTokenW o CreateProcessAsUserW.
Ten en cuenta que, nuevamente en este caso, los atacantes solo están interesados en las sesiones de inicio de sesión privilegiadas que no son inicios de sesión de red, ya que los inicios de sesión de red no almacenan credenciales en caché y, por lo tanto, no pueden Autenticar en otros hosts.
2. Pasar el boleto
Windows proporciona un método nativo para realizar una técnica muy similar a la bandera NETONLY usando Kerberos30. Esta técnica es aún más poderosa en el sentido de que no requiere que un atacante cree una nueva sesión de inicio de sesión, sino que cambie arbitrariamente las credenciales de Kerberos en caché (por ejemplo, TGT) asociadas a su sesión de inicio de sesión (y por tanto al token de acceso actual), como se muestra a continuación:

Para empezar a interactuar con el SSP de Kerberos y gestionar la caché de tiquetes de Kerberos, un proceso puede llamar a LsaCallAuthenticationPackage (ubicado en Sspicl.dll):
NTSTATUS LsaCallAuthenticationPackage(
HANDLE LsaHandle,
Paquete de Autenticación ULONG ,
PVOID ProtocolSubmitBuffer,
ULONG SubmitBufferLength,
PVOID *ProtocolReturnBuffer,
PULONG RetornoBufferLongitud,
PNTSTATUS ProtocolStatus
);
Ten en cuenta que el usuario deberá llamar previamente a LsaConnectUntrusted para obtener un handle de conexión al servidor LSA y LsaLookupAuthenticationPackage para encontrar el id del paquete kerberos (MICROSOFT_KERBEROS_NAME_A). Además, la inspección de estas funciones en IDA (de nuevo pueden localizar en Sspicl.dll) revelará que se conectan a la LSA mediante RPC.31.
A través de LsaCallAuthenticationPackage, un usuario puede realizar varias solicitudes sensibles, aunque las solicitudes exactas disponibles dependen de si están elevadas o no. Por ejemplo, un usuario no elevado puede realizar acciones básicas de gestión de tiquetes32, como enumerar sus tiquetes activos actuales, purgar la caché de tiquetes y aplicar tiquetes arbitrarios a su sesión de inicio de sesión actual33. Por tanto, esto permite efectivamente a un usuario cambiar las credenciales almacenadas en caché con su sesión de inicio de sesión actual y, por tanto, especificar credenciales arbitrariassolo de red.
Además, desde un contextoelevado 34 , un atacante puede enumerar y volcar tiquetes (por ejemplo, credenciales) que pertenecen a otros usuarios, proporcionando así una funcionalidad similar a mimikatz sin necesidad de abrir un handle paraLSASS 35.
Aquí se puede encontrar una lista completa de los tipos de mensajes que pueden enviar al paquete de autenticación de Kerberos . Para cambiar el TGT actual asociado a una sesión de inicio de sesión dada, se puede pasar el mensaje KerbSubmitTicket , que emplea la siguiente estructura de mensaje:
Typedef struct _KERB_SUBMIT_TKT_REQUEST {
KERB_PROTOCOL_MESSAGE_TYPE MessageType;
LUID LogonId;
ULONG Flags;
KERB_CRYPTO_KEY32 Key;
ULONG KerbCredSize;
ULONG KerbCredOffset;
} KERB_SUBMIT_TKT_REQUEST, *PKERB_SUBMIT_TKT_REQUEST
Por lo tanto, para un KerbSubmitTicketMessage, el parámetro ProtocolSubmitBuffer simplemente apunta a un bloque de memoria que consiste en una estructura KERB_SUBMIT_TKT_REQUEST seguida inmediatamente de un tiquete Kerberos codificado por ASN (que es el tiquete que se aplicará a la sesión de inicio de sesión especificada). El código relevante en mimikatz para enviar solicitudes KerbSubmitTicketMessage se puede encontrar aquí y en Rubeus aquí.
Tras la llamada a LsaCallAuthenticationPackage, el TGT del usuario se actualizó al tiquete robado. A partir de ese momento, cualquier intento de acceder a recursos de red mediante cualquier proceso/hilo vinculado al token de acceso/sesión de inicio de sesión interactiva del usuario se autenticará automáticamente a través de Kerberos usando el TGT robado (por ejemplo, aplicar diferentes tiquetes de servicio/TGS para recursos en todo el dominio).
Ten en cuenta que un usuario solo puede tener un TGT asociado a su sesión de inicio de sesión actual. Por tanto, al aplicar un nuevo tiquete, se borrará el tiquete anterior del usuario. ¿Y si un atacante quisiera preservar su TGT actual? En este caso, una vez más la bandera NETONLY acude al rescate: un atacante puede crear un proceso "sacrificado" de NETONLY mediante CreateProcessWithLogonW con credenciales arbitrarias o basura. Esto creará un nuevo proceso ficticio y, lo más importante, una nueva sesión de inicio de sesión (y por tanto un token de acceso) a la que se podrá aplicar un TGT robado (y así preservar el tiquete actual del usuario)36.
Una conclusión importante que se puede extraer de esta técnica para los profesionales de la defensa es que, dado que toda la actividad se realiza a través de LsaCallAuthenticationPackage (y por tanto a través de RPC), no requiere ninguna interacción directa con LSASS (Nota: directo aquí se refiere a abrir un handle a lsass mediante OpenProcess). Además, para este específico caso de uso (ptt), toda la actividad se realiza mediante RPC local hasta que un atacante intenta autenticar en un host remoto (lo que generará nuevos inicios de sesión).
Como ejemplo adicional, el README para Rubeus incluye la siguiente afirmación:
"Rubeus no tiene ningún código para tocar LSASS (y ninguno es intencionado), por lo que su funcionalidad se limita a extraer tiquetes de Kerberos mediante el uso de la API LsaCallAuthenticationPackage()"
Por lo tanto, cualquier lógica de detección basada en el acceso a un handle a lsass (por ejemplo, mediante una rutina de kernel ObjectPreCallback para un proceso u operación de handle de hilo especificada, o un hook en modo usuario en OpenProcess/NtOpenProcess) podría pasar por alto esta actividad. Por tanto, es un posible punto ciego para, por ejemplo, los defensores que dependen de los eventos de acceso a procesos de Sysmon para alertar sobre acceso sospechoso a la dirección de procesos.
3. Pasar el hash (PtH)
Las dos últimas técnicas que cubrirá este blog son ejemplos de un atacante que cambia "ilegítimamente" las credenciales en caché asociadas a su token de acceso/sesión de inicio de sesión actual modificando directamente la memoria LSASS. En el escenario PtH, el token de acceso del atacante no cambia y apunta a la misma sesión de inicio de sesión, sin embargo, las credenciales en caché asociadas se sobreescribir directamente a un hash robado. A partir de este punto, cualquier intento de autenticación remota usará el hash robado, como se muestra a continuación:

En este sentido, tanto la PtH como la OPtH pueden considerar funcionalmente idénticas a la técnica NETONLY discutida anteriormente.
El flujo de trabajo típico de un ataque PtH es:
- Abrir un handle de escritura en lsass (por ejemplo, a través de OpenProcess/NtOpenProcess con un acceso deseado de PROCESS_VM_WRITE)
- Enumerar la lista enlazada de sesiones de inicio de sesión
- Localiza la sesión de inicio de sesión de interés e identifica el paquete de autenticación requerido (en el caso de PtH/NTLM, este es el paquete de autenticación MSV1_0 )
- Actualizar las credenciales en caché asociadas
Cabe señalar que estas técnicas a menudo dependen de analizar y modificar estructuras de Windows no documentadas . Esto no se tratará en este blog, pero se puede encontrar más información sobre cómo se realiza aquí y aquí.
Por lo tanto, una vez que las credenciales en caché se actualizan en memoria, se usarán automáticamente para autenticar remotamente, según el diseño habitual de inicio de sesión único de Windows, cuando cualquier proceso/hilo que se ejecute como ese token intente acceder a un recurso remoto.
Ten en cuenta que, en este caso sencillo, no se crearon tokens adicionales de sesión o acceso de acceso. Sin embargo, de forma similar a los ataques de paso de tiquete, estas herramientas también suelen necesitar crear nuevos procesos basura NETONLY/sesiones de inicio de sesión para preservar las credenciales existentes o para aplicar credenciales robadas.
Como nota, para obtener un handle de escritura en LSASS, el malware suele adoptar dos enfoques:
- Adquirir SeDebugPrivilege37
- Robar e imitar un token SYSTEM
El primer enfoque se discutió en la primera parte de este serial de blogs, sin embargo, el segundo es un ejemplo típico de robo/suplantación de un token con el fin de saltar comprobaciones de acceso locales (por ejemplo, robar un token SYSTEM con un privilegio específico activado, por ejemplo, SeTcbPrivilege). Un token SYSTEM se obtiene comúnmente robando el token principal de winlogon.
4.
Sobrepasar el hash (OPtH)La técnica Overpass-the-hash aplica el mismo concepto que el pass-the-hash con una diferencia clave: convierte un hash en un tiquete TGT completo.
Cuando un usuario inicia sesión por primera vez en una estación de trabajo con Windows, como parte del proceso de autenticación Kerberos, el hash de la contraseña del usuario se emplea para cifrar una marca de tiempo y validar la identidad del usuario ante el Controlador de Dominio / Centro de Distribución de Claves (KDC) y recibir un TGT. El paso por paso del hash modifica estos hashes almacenadosen caché 38 en memoria y luego activa el protocolo normal de autenticación Kerberos (AS-REQ/AS_REP etc.) para obtener un TGT completo Por un hachís robado.39
Esta técnica puede realizar mediante el comando pth de mimikatz (que se etiqueta engañosamente como pth cuando en realidad está realizando un overpass-the-hash bajo el capó):
mimikatz # sekurlsa::p th /user:Administrator /domain:ASTRO.testlab /ntlm: c0f969f35beb20e8f09ce86ef42ccd51
Esto realiza esencialmente los mismos pasos que PtH, excepto que apunta al SSP de Kerberos (y por tanto kerberos.dll).40

Como esta técnica implica de nuevo borrar el TGT actual asociado a la sesión de inicio de sesión del usuario, un atacante puede usar un proceso NETONLY (con una sesión ficticia asociada) para preservar su TGT actual, que es exactamente como mimikatz realiza por defecto el overpass-the-hash.
En primer lugar, genera un nuevo proceso en estado suspendido mediante CreateProcessWithLogonW con la bandera LOGON_NETCREDENTIALS_ONLY. Luego obtiene un handle para el token principal de este proceso suspendido y recupera el id de autenticación para la nueva sesión de inicio de sesión ficticia a través de GetTokenInformation. Esta función se emplea para consultar la información almacenada en caché en el token a través del TOKEN_INFORMATION_CLASS enum, que en este caso es TokenStatistics.
Una vez obtenido el id de autenticación, mimikatz puede ahora empezar a enumerar la lista enlazada de sesiones de inicio de sesión dentro de LSASS, buscando la sesión de inicio de sesión recién creada. Una vez que encontró la sesión de inicio de sesión objetivo (a través del id de autenticación), puede proceder a actualizar las credenciales de Kerberos asociadas a ella. Una vez actualizadas las credenciales, el token (cuya sesión de inicio de sesión correspondiente ahora está vinculada al hash robado) puede convertir en un token de suplantación mediante DuplicateTokenEx y suplantar mediante SetThreadToken, como vimos anteriormente.
Una vez más, en esta etapa, cualquier intento que un atacante haga para acceder a recursos a través de la red usará la combinación de hash dominio\usuario y contraseña proporcionada como argumentos para mimikatz para la autenticación. Por lo tanto, todas las interacciones remotas se realizarán con el acceso y privilegios de las credenciales robadas.
Conclusión
El propósito de este serial de dos partes fue explicar cómo funcionan las características fundamentales en la Security de Windows y mostrar cómo los atacantes abusan de estas características para comprometer dominios de Windows. Este blog demostró que, independientemente de qué herramientas o proveedor de autenticación se abuse, los atacantes actúan bajo un conjunto de restricciones que resultan en las mismas señales anómalas para la manipulación de tokens de acceso (por ejemplo, inicios de sesión anómalos solo en red). Estas restricciones están determinadas por la relación fundamental entre los tokens de acceso, las sesiones de inicio de sesión y las credenciales en caché.¿Listo para una protección integral de datos con Elastic Security? Pruébalo gratis hoy mismo, o disfruta nuestra última versión del Elasticsearch Service en Elastic Cloud. Y aprovecha nuestro entrenamiento Quick Start para prepararte para el éxito.
Referencias
1. Para un resumen de cómo funciona la autenticación Kerberos, ver Programación de Security de Windows, Keith Brown o https://posts.specterops.io/kerberosity-killed-the.... Además, Rubeus, que es un kit de herramientas para interactuar con Kerberos, tiene un readme extremadamente informativo, que se recomienda para lecturas adicionales.
2. Recuerda, Windows se autenticará automáticamente con las credenciales almacenadas en caché en la sesión de inicio de sesión siempre que un usuario intente acceder a un recurso de red según el mecanismo de inicio de sesión único de Windows. Las credenciales en caché aquí pueden referir a cualquier proveedor de autenticación (por ejemplo, hashes NTLM o tiquetes de Kerberos). Nota: esto asume que el usuario está conectado de forma interactiva (no es de red).
3. Esto suele ser para evitar perder un punto de apoyo debido a la respuesta a incidentes o al aislamiento del huésped.
4. Esto obviamente solo es aplicable a la actividad del atacante en un host comprometido, a diferencia de que un atacante ejecutar código de otra fuente, por ejemplo, remotamente vía impacket.
5. https://clymb3r.wordpress.com/2013/11/03/powershel...
6. Ver el comando 'steal_token' de Cobalt Strike como ejemplo de esta técnica: https://www.cobaltstrike.com/help-beacon
7. Este comentario del marco de trabajo de PowerSploit también debería aportar una mayor claridad sobre esta distinción entre robo de tokens para escalada de privilegios locales y movimiento lateral.
8. Alternativamente, los atacantes también pueden optar por la vía de la aplicación de contraseña o intentar usar NTLM para autodescubrir o reproducir ataques mediante herramientas como el respondedor.
9. Ten en cuenta que tanto LogonUserA como W son envoltorios simples alrededor de LogonUserExExW en SspiCli.dll
10. De la misma manera, CreateProcessWithLogonW puede recibir una cuenta de administrador local (rid-500) para ejecutar un proceso elevado desde un contexto medio/no elevado.
11. Existen opciones remotas de registro UAC que pueden modificar este comportamiento.
12. Existe un tipo de inicio de sesión adicional, LOGON32_LOGON_NETWORK_CLEARTEXT, que es esencialmente un inicio de sesión de red pero con credenciales en caché. Consulta Programación de la Security Windows, Keith Brown para más información.
13. Consulta para más información:
https://blueteamer.blogspot.com/2018/12/disabling-...
https://support.microsoft.com/en-gb/help/951016/de...
https://labs.f-secure.com/blog/enumerating-remote-...
14. Nota: también existe una función DuplicateToken , pero esta solo devuelve un token de suplantación.
15. Esto puede verificar examinando la función en IDA. Alternativamente, consulta aquí en ReactOS.
16. Este resumen es una ligera simplificación de la seguridad por suplantación. Para una visión general más completa, ver las diapositivas "Introducción a la escalada de privilegios lógicos en Windows" de James Forshaw (p26): https://conference.hitb.org/hitbsecconf2017ams/mat...
17. Este título está tomado de un excelente blog de Raphael Mudge: Tokens de acceso a Windows y credenciales alternativas.
18. Esta es normalmente la principal razón por la que la opción 2 no es empleada habitualmente por los atacantes.
19. Por lo tanto, ejecutar 'whoami' seguirá mostrando el mismo usuario (ya que el token sigue siendo el mismo), a pesar de que el token duplicado tenga diferentes credenciales de red. Esto es una fuente común de confusión al usar el comando make_token de Cobalt Strike (que realiza la misma técnica que se describe en el capó).
20. Las API RPC/COM de Windows también permiten al usuario especificar credenciales solo de red. Por ejemplo, esto se puede lograr para RPC llamando a RpcBindingSetAuthInfoExW y pasando una estructura SEC_WINNT_AUTH_IDENTITY a través del parámetro AuthIdentity. Para más información, ver Programación de Windows Security, Keith Brown y https://docs.microsoft.com/en-us/windows/win32/wmisdk/setting-authentication-using-c-.
21. Aunque las dos banderas tienen nombres diferentes, su significado es el mismo; Estas credenciales solo deben usar en la red.
22. Ten en cuenta que todavía existen formas de evitar crear registros de eventos sospechosos para sesiones de inicio de sesión anómalas.
23. Esto es un truco de James Forshaw - ver el siguiente blog para más detalles: https://www.tiraniddo.dev/2017/05/reading-your-way.... Además, TokenViewer es una herramienta excelente para experimentar con este tipo de técnica.
24. Con este token de suplantación resultante es posible escribir un archivo en System32, etc.
25. Sin embargo, aún puede haber razones legítimas para suplantar antes de llamar a una API, como obtener un privilegio que no tienes actualmente antes de llamar a una API que lo requiera (aunque hay que tener en cuenta que algunas API activan automáticamente privilegios).
26. Hay varias formas de evitar esto. Por ejemplo, puedes generar un proceso como hijo de un proceso SYSTEM obteniendo un handle para un proceso SYSTEM a través de OpenProcess con el derecho de acceso PROCESS_CREATE_PROCESS . Este HANDLE puede pasar entonces a NtCreateProcess como el parámetro ParentProcess. Esto también se puede lograr mediante el parámetro PROC_THREAD_ATTRIBUTE_PARENT_PROCESS y CreateProcess: https://gist.github.com/xpn/a057a26ec81e736518ee50...
27. Curiosamente, CreateProcessWithTokenW adopta el argumento dwLogonFlags a pesar de requerir también un handle para un token existente, que por definición ya debería tener una sesión de inicio de sesión correspondiente. Parece probable que esto tenga que ver con cargar el perfil de usuario.
28. Programación de la Security de Windows, Keith Brown
29. Específicamente, SE_IMPERSONATE_NAME para CreateProcessWithTokenW y SE_INCREASE_QUOTA_NAME (&) SE_ASSIGNPRIMARYTOKEN_NAME (si el token no es asignable) para CreateProcessAsUserW
30. Un resumen de la autenticación de Kerberos puede encontrar aquí y ver lo siguiente para más información sobre ataques relacionados con kerberos: https://www.blackhat.com/docs/us-14/materials/us-1..., , https://github.com/GhostPack/Rubeus#readme
31. https://googleprojectzero.blogspot.com/2019/12/cal...
32. Por ejemplo, la herramienta nativa de Windows klist ofrece una funcionalidad similar y claramente es un envoltorio alrededor de LsaCallAuthenticationPackage.
33. Tenga en cuenta que un usuario no elevado solo puede aplicar tiquetes a su propia sesión de inicio de sesión; se necesitan privilegios elevados para aplicar un TGT a una sesión de inicio de sesión diferente.
34. Hay algunas advertencias/matices en esta afirmación que se responden mejor en el readme de Rubeus. En resumen, el llamante necesita registrar una conexión LSA a través de LsaRegisterLsaProcess que requiere el privilegio SeTcbPrivilege (es decir, el llamante forma parte de la base de computación confiable).
35. Como observación, también puedes comunicarte con el paquete de autenticación msv1_0 a través de LsaCallAuthenticationPackage y enviar los siguientes tipos de mensajes: https://docs.microsoft.com/en-us/windows/win32/api..., aunque no investigué si también es posible recuperar credenciales NTLM a través de esta interfaz.
36. Para más información, consulta el readme del repositorio de GitHub de Rubeus, que tiene un excelente resumen de muchas funcionalidades relacionadas con kerberos y consideraciones de opsec.
37. Ver aquí un ejemplo de cómo habilitar un privilegio
38. Esto se puede verificar mirando PsOpenProcess/Thread en IDA y buscando una llamada a SePrivilegeCheck.
39. Ten en cuenta que adquirir SeDebugPrivilege suele ser muy ruidoso desde la perspectiva de la lógica de detección.
40. Ten en cuenta que el hash/clave puede ser rc4_hmac (por ejemplo, NTLM), aes128_hmac, aes256_hmac, etc. Consulta aquí para más información.
41. Ver para más detalles: https://www.blackhat.com/docs/us-14/materials/us-1...
42. Como nota, la funcionalidad asktgt de Rubeus realiza una variante de sobrepaso al hash mediante la construcción de tráfico AS-REQ en bruto para un hash dado desde un contexto no elevado y sin necesidad de tocar lsass.