Welcome to another Hack the Box walkthrough. In this blog post, I have demonstrated how I owned the Eighteen machine on Hack the Box. Hack The Box is a cybersecurity platform that helps you bridge knowledge gaps and prepares you for cyber security jobs.
About the Machine
Eighteen is an easy Windows Machine on Hack the Box
The first step in owning the Eighteen machine like I have always done in my previous writeups is to connect my Kali Linux terminal with Hack the Box server. To establish this connection, I ran the following command in the terminal:
Once the connection between my Kali Linux terminal and Hack the Box server has been established, I started the Eighteen machine and I was assigned an IP address (10.10.11.95).
One the machine information, two credentials were provided: kevin / iNa2we6haRj2gaw!
Nmap Enumeration
I began the initial enumeration phase with an aggressive Nmap scan to identify open ports and running services on the target:
The Nmap scan result revealed:
Port 80 – Microsoft IIS 10.0
The web server on port 80 immediately revealed that it’s running Microsoft IIS/10.0, consistent with a modern Windows Server environment. Interestingly, the HTTP title shows that the server attempts to redirect us to http://eighteen.htb/, which suggests virtual hosting and gives us a domain name to add to our /etc/hosts. This is usually an early hint in HTB machines that the real web content sits behind a vhost.
Port 1433 – Microsoft SQL Server 2022
Port 1433 is wide open, exposing a Microsoft SQL Server 2022 (16.00.1000.00 RTM) instance. Nmap’s ms-sql-* scripts leak quite a bit of Active Directory metadata:
- Domain:
EIGHTEEN - Hostname:
DC01 - FQDN:
DC01.eighteen.htb
The fact that the machine names itself DC01 strongly suggests we’re enumerating a domain controller - rare on “easy” boxes and always a sign that Active Directory abuse will soon become part of the attack chain.
Even better, SQL Server is often misconfigured on HTB labs, especially when combined with NTLM authentication, making this port a very strong foothold candidate.
Nmap also pulls the SSL certificate from SQL Server, and the Common Name is just a generic “SSL_Self_Signed_Fallback”, typical for default SQL Server setups.
Port 5985 – WinRM (HTTP)
Seeing port 5985 open confirms that WinRM is enabled. This is the default management interface for remote PowerShell execution over HTTP. If I can get a valid domain credentials later, this port will likely become my method for gaining a shell.
Mapping IP Address to Domain Name
After discovering the domain DC01.eighteen.htb and been assigned IP Address 10.10.11.95, I decided to map the target machine IP address to the domain name. This way, I could access the service by name instead of by IP address by running:
With SQL Server exposed on port 1433 from the Nmap scan, my next move was to test whether the kevin credentials I provided in the machine information would actually authenticate. Using Impacket’s mssqlclient, I connected to the database service:
SQL Server immediately required TLS, then dropped me into an interactive console. The login succeeded - already a promising sign.
Enumerating SQL Server Permissions
Once inside, I began checking what privileges the kevin account actually had. Running enum_impersonate revealed a critical misconfiguration:
This means Kevin is allowed to impersonate another SQL login, specifically appdev. On a domain controller hosting SQL Server, that’s a gold mine - SQL impersonation often leads to privilege escalation or access to sensitive databases.
I switched context using:
Now operating as appdev, I proceeded to enumerate the databases and noticed one that stood out: financial_planner.
Exploring the Financial Planner Database
I changed into the database:
Querying the table list immediately exposed several application-related tables:
users- incomes
- expenses
- allocations
- analytics
- visits
The users table was the obvious target. Inspecting its schema confirmed it contained credential-related fields:
- username
- password_hash
- is_admin
Exactly what I needed.
Next, I queried the database financial_planner and it listed the column names and data types:
Dumping User Credentials
Finally, I pulled the user data:
The dump returned two users:
| username | password_hash | |
|---|---|---|
| admin | {{ 7*7 }} | pbkdf2:sha256:600000$… |
| boltech | boltech@gmail.com | pbkdf2:sha256:600000$… |
The application stores passwords using PBKDF2-HMAC-SHA256 with 600,000 iterations - secure, but not invulnerable if the passphrase is weak. The admin email field being set to {{ 7*7 }} is a curious template artifact, possibly hinting at server-side rendering vulnerabilities.
Hashcat doesn’t support PBKDF2-SHA256 in this exact format out-of-the-box, so I built a small custom Python cracker to brute-force it with a wordlist.
First, I extracted the admin hash from the database and dropped it into a file named hash.txt for reference. Next, I created a script called hash-cracker.py and implemented PBKDF2 manually using Python’s built-in hashlib module.
The script breaks down like this:
Inside the script, I pasted the admin hash and made sure the path of my wordlist is correct. Next I ran the hash-cracker.py file with Python by running:
The admin password turned out to be “iloveyou1” - a painfully weak choice for an application password running on a domain controller. With valid credentials now in hand, I had everything I needed to pivot back into the environment and escalate the compromise even further.
Before moving forward, I wanted to verify exactly where the compromised credentials from SQL could take me inside the domain. Since the SQL service was running on a domain controller, I decided to use NetExec (nxc) to probe the MSSQL service with the kevin credentials:
NetExec successfully authenticated, confirming the account was valid on the host:
Once authenticated, I enabled --rid-brute to enumerate domain users and groups by brute-forcing RID values. Since this SQL Server is actually installed on the domain controller DC01, I immediately started receiving a full dump of Active Directory objects.
- The enumeration returned a complete picture of the domain:Core AD service accounts like Administrator, Guest, krbtgt
- Privileged groups including: Domain Admins (512), Enterprise Admins (519), Schema Admins (518), Group Policy Creator Owners (520)
- Domain-level buckets like Domain Users, Domain Controllers, Domain Computers
- Various administrative and service groups (DNSAdmins, RODC groups, Key Admins)
- A long list of individual user accounts: jamie.dunn, jane.smith, alice.jones, adam.scott, bob.brown, etc.
This enumeration confirmed two important things:
-
The machine I’m interacting with is the actual domain controller, not just a member server hosting SQL.
-
Kevin is a real domain user, and his credentials provide at least enough access to enumerate the entire Active Directory structure.
Now that I had cracked the admin password (iloveyou1), the next step was figuring out which domain user - if any - was reusing that same password. Since the SQL database had exposed a full list of employee usernames, I compiled the likely candidates into a simple users.txt file:
With the list ready, I used CrackMapExec (CME) to spray the recovered password against WinRM (port 5985):
CME initialized itself on first run and began checking each user. Most attempts failed as expected - but then one line stood out:
Bingo.
The output confirmed that adam.scott was reusing the same weak password found in the SQL database. Even better, CME flagged it with the “Pwn3d!” indicator, meaning WinRM authentication succeeded and remote command execution was now possible.
'NoneType' object has no attribute 'upper') is just a harmless CME bug - it doesn’t affect the result. The important part is clear: I now had valid WinRM access as a real domain user on the domain controller itself.
This was the foothold I needed to pivot from database compromise to full Windows host access - and potentially escalate even further.
Pivoting into the Windows Machine
With valid credentials for adam.scott in hand, the next step was to actually pivot onto the Windows machine. Since CME confirmed WinRM was open and accepting logins, I fired up Evil-WinRM - the go-to post-exploitation shell for Windows targets:
After a moment, Evil-WinRM initialized and dropped me into a PowerShell session. A minor warning about Ruby’s path completion popped up (a common harmless quirk), but the important part was clear:
I now had an interactive shell on the target as adam.scott.
Once inside, I navigated to the user’s desktop - always the first place to check for flags on HackTheBox Windows machines:
The directory listing confirmed exactly what I was hoping to find:
With the foothold secured, I read the user flag:
Hurray!!! The User flag was captured.
Now that I had a stable shell and user-level access, it was time to begin enumerating the system for privilege escalation paths to go after the root flag.
v
w
x
y
z
To be continued tomorrow, off to bed 🛌🥱😴💤















19 Comments
Solid man. I hope you can mentor me. I want to become a full time hacker too. You can reach me on wellssam40@gmail.com
ReplyDeleteI will launch a bootcamp in January/February 2026 and I am thinking of creating a class on malware analysis. The information regarding this will be posted in due time. Thank you and don't forget to follow me on LinkedIn.
DeleteAny tips on the second part of the task?
ReplyDeleteI will publish the complete walkthrough soon.
DeleteHint : BadSuccessor - make sure you use the LATEST version you can find of exploit binaries (especially Rubeus). Alternatively you can compile it yourself. I striggled a lot on that part only because i had an outdated version of Rubeus.
DeleteHint 2: Make sure your attacker's machine clock is synced with the target machine during Kerberos interactions. Tools like faketime can help to spoof the clock for specific commands. Additionally, you can use Nmap to check for clock skew between your machine and the target system.
DeleteWhats the correct version of Rubeus you used?because i used bith Rubeus 2.2.0 & 2.3.3 both didn't gave me the LUID
DeleteBro what is the latest version of Rubeus? and Badsuccessor too? i trying them but still its unable to exploit.
Deletei believe the badprocessor is the key for the second part but i just cant fix it...
ReplyDeleteI will publish the complete walkthrough soon. Keep an eye out for the updated post.
DeleteThere's something strange in this writeup that doesn't fit the machine and i don't really understand : nxc mssql 10.10.11.95 -u kevin -p '****' --rid-brute --local-auth does not perform user enum via mssql but rather SMB RPC (ports 445 / 135 / 139) and those ports are filtered as of december 6th 2025. Maybe it wasn't at release time. Therefore this command isn't relevant anymore and enumeration must be done in another way i believe. It would be very nice if the author of this article could check if the command is still working for him, maybe i'm missing something important. Also, i am unable to enumerate users through the mssql protocol using SUSER_SNAME and SUSER_SID functions or at least, i can only enumerate basic users like Administrator, Guest.. I suspect the machine to have been updated making the enum part of this writeup irrelevant.
ReplyDeleteI will try to check if netexec (nxc) can still be used to probe the MSSQL service with the kevin credentials. Most of the times, HTB update the machines after three days or a week. If the method no longer works, I will provide an alternative method. Thank you for dropping by. I hope you enjoy reading my writeup.
DeleteThanks for the fast response, and yes i enjoyed reading you writeup. It is always useful for me to know if i'm on the good path. I can add that i tried the adam.*** username and i can successfully log in to winrm using evil-winrm so the intended path for this machine requires we find the username in one way or another. I look forward to hearing from you.
DeleteNevermind, i've just understood my mistake. Since my own version of nxc does not support --rid-brute arg, i wrote my own python script to mimic nxc --rid-brute behaviour. I started iterating from the wrong SID; SUSER_SID('DC01\Administrator') -> 010500000000000515000000a90f058d0a240185e3dfe0a9f4010000 != SUSER_SID('EIGHTEEN\Domain Users') -> 010500000000000515000000dfdeac44d4131d236f599b7601020000 In more simple terms, i mixed the SID's.. This has nothing to do with any update in the machine, it was my mistake. Thank you.
DeleteBut the command really does not allow to use arg --rid-brute pairing with mssql but only smb. I tried using nxc, it just show unrecognized arguments: --rid-brute.
DeleteWhen we gonna have the rest, keep going youre doing great
ReplyDeleteMuy buen artículo, puedes subir la 2 parte?
ReplyDeletePlease upload the rooting section and the Gravel and Darkzero machine parts. Great work!
ReplyDeleteI will publish the write-up for Gavel and Darkzero soon. Don't forget to subscribe so you get a push notification immediately I publish a new writeup.
Delete