North Stone
Challenge Lab (Hard) - by 2ubZ3r0
The following post by 0xb0b is licensed under CC BY 4.0
Scenario
Objective
North Stone, a premier luxury real estate marketplace, has engaged Hack Smarter for a full-scope penetration test. Your objective: identify critical vulnerabilities and demonstrate real-world business impact by achieving complete domain compromise.
Initial Access
The client has provided you with VPN access to their network, but no credentials.
Summary
Summary
In North Stone, we begin with external enumeration and discover a Domain Controller DC.northstone.local exposing DNS on port 53, Kerberos on 88, LDAP on 389 and 636, SMB on 445, RDP on 3389, WinRM on 5985, IIS on 80, and MSSQL on 1433. Initial SMB enumeration fails without credentials, so we pivot to the web service and discover a subdomain testsql.northstone.local via vhost fuzzing. The subdomain hosts a search interface vulnerable to SQL injection on /search.aspx?q=; the verbose error message leaks connection string credentials for the webapp database user, granting us authenticated MSSQL access.
Connected to the MSSQL service, we enumerate linked servers and discover SQLBACKUP. Using xp_dirtree, we force a connection attempt to our SMB share and capture the NTLMv2 hash of svc_backup, which we successfully crack. With credentials in hand, we run BloodHound to enumerate the domain and identify user c.mcgill with Kerberos pre-authentication disabled. We AS-REP roast c.mcgill, crack the resulting hash, and use BloodyAD to discover that we possess write permissions over user t.dalton. We disable Kerberos pre-auth on t.dalton, AS-REP roast the account, and crack it.
Authenticating as t.dalton, we use Certipy to discover a vulnerable certificate template called TemporaryWinRMsusceptible to ESC13. We enroll a certificate, authenticate via Kerberos using the resulting PFX, and establish a WinRM shell as t.dalton. On the user's desktop, we find an email detailing a scheduled task that runs WindowsUpdateCheckerevery minute under the context of c.white. We decompile the executable with ILSpy, discover it loads wuaclt.dll from the modules directory, and craft a malicious DLL that silently downloads and executes a Sliver stager via PowerShell. Placing the DLL in the modules folder grants us a C2 session as c.white.
Examining c.white's group memberships, we discover membership in database backup operators. We locate a backup file NorthStoneDB.bak in C:\BackupDB\, restore it to a local Docker MSSQL instance, and query the auth_test_users table to recover credentials for k.bennett. BloodHound reveals a lateral movement chain through r.parker to l.turner. We use BloodyAD to change r.parker's password, then deploy Certipy's Shadow Credentials attack to extract l.turner's NT hash and establish a WinRM session.
As l.turner, we enumerate group-related services and locate PrintNotifyService, which is managed by the print services operators group. We upload a service-aware Go stager capable of handling SCM control requests, modify the service's binPath to point to our stager, restart the service, and receive a stable Sliver session as NT AUTHORITY\SYSTEM, yielding the root flag at C:\Users\Administrator\desktop\root.txt.
Recon
We use rustscan -b 500 -a 10.0.22.176 --top -- -sC -sV -Pn to enumerate all TCP ports on the target machine, piping the discovered results into Nmap which runs default NSE scripts -sC, service and version detection -sV, and treats the host as online without ICMP echo -Pn.
A batch size of 500 trades speed for stability, the default 1500 balances both, while much larger sizes increase throughput but risk missed responses and instability.

The target 10.0.22.176 is a Domain Controller DC.northstone.local. DNS is exposed on port 53 and Kerberos on port 88, alongside Kerberos password change on port 464. LDAP and LDAPS services are available on ports 389 and 636, with the Global Catalog on ports 3268 and 3269. SMB is exposed via ports 139 and 445 with message signing enabled and required. A web server (Microsoft IIS 10.0) is hosting a "NorthStone | Coming Soon - US Real Estate Portal" page on port 80, and Microsoft SQL Server 2019 is reachable on ports 1433. Remote management and access are available through RDP on port 3389 and WinRM on port 5985. The host also exposes a .NET Message Framing service on port 9389, RPC over HTTP on port 593, and several MSRPC endpoints on ports 135, 49664, 49667+.

SMB
We try to authenticate anonymously and via guest against SMB using NetExec but without success. The acount is disabled. Nevertheless we will generate a hosts file entry with the following command:

We add the following entry to our /etc/hosts file.
WEB
Since we don't have any users and can't authenticate ourselves anonymously, we'll proceed with the web service. The nmap scan already revealed that a page is indeed being hosted.
We have a real estate search platform infront of us which is currently under development. At first glance it seems like a static site.

We scroll down and find a development changelog. We see a databse has been establishd and a backup process implemented.

We continue with a directory scan using Feroxbuster, but do not find any interesting endpoints.

Next, we perform a VHOST scan using FFuF. After a while we are able to detect a vhost called testsql using the subdomains-top1million-110000.txt wordlist.

We edit our /etc/hosts entry like the following and proceed with the enumeration on testsql.northstone.local.
Here we are able to query the database through a search bar.

We test for SQL injection by entering a single quote and retrieving an error message. The target is susceptible to SQL injection.

Access as webapp
We scroll down the error message.and also the connection string is revealed containing the database credentials. The error message is too verbose and contains sensitve information.

Next, we try to connect to the MSSQL service on port 1433 using impackets mssqlclient.py. We are successful and are able to query the database from there.

The following part shows the attempt via SQLMap and can be skipped.
We can continue with the section Access as svc_backup.
I did this because I made the mistake of not reviewing the entire error log.
However, the database contains a table that is empty in this instance but will become relevant later on.
Using SQLMap we see the target is vulnerable to the following techniques:
error-based, time-base blind and stacked queries.


We are able to enumerate the databases.

In NorthstoneDB we find a table called auth_test_users.


But unfortunately its empty.

Access as svc_backup
We do not find anything interesting in the database beside an empty table called auth_test_users on the DB NorthStoneDB, but this might be interesting later on.
With the connection esabtlished to 1433 we try to execute system commands with xp_cmdshell, but we are missing the permission.


What else we can try is to catch an NTLMv2 hash by forcing a connection to our share via xp_dirtree. For this, we set up Responder

We connect to our share...

... and receive the DC$ NTLMv2 hash, but we cannot crack it.

Next, we try to enumerate linked servers and actually do find one. The SQLBACKUP server.

For this we try to execute commands again using xp_cmdshell, but also here we're missing the permissions to do so. But also we try to catch a NTLMv2 hash via a connection attempt to our share using xp_dirtree.

And we are successful. We retrieve the hash of svc_backup.

This hash is actually crackable.

We test the credentails of svc_backup using NetExec and successfully authenticate against the domain controller.

BloodHound Enumeration
Now that we have credentials we'll enumerate the domain using BloodHound.

The Administrator is the only Domain Admin.

Our recent compromised user does not seem to have any special privileges / outbound object control according to our bloodhound data gathered.

We look for quick wins, and find a single user c.mcgill AS-REP roastable. This user does not have any special outbound object control, but might have access to shares or hold other special privilges we can't see right now with the bloodhound data gathered. We give it a try.

With ASREProasting accounts with Kerberos pre-authentication disabled are exploited by requesting a TGT for them, since the KDC will return an AS-REP containing a session key encrypted with the user's password-derived hash. We can then crack that hash offline to recover the plaintext password, though the TGT itself remains unusable without it.

Access as c.mcgill
We use NetExec for AS-REP Roasting and are able to extract the blob from c.mcgill.

Next, we try to crack the blob and are successful.

With the credentials recovered we are able to authenticate as c.mcgill against SMB using NetExec. But there are no new shares available.

Access as t.dalton
As a last resort we try to query for writable AD objects using BloodyAD by authenticating as c.mcgill returning detailed output of every object that account can modify

We see we have writeable permissions on tony dalton. This user is member of the software maintenance group and certificate enrollment users. This seems like a high value target.


With the writeable permissions we disable Kerberos pre-authentication. Enabled us to perfrom an ASREP Roast.

We use NetExec for AS-REP Roasting and are able to extract the blob from t.dalton also.

Next, we try to crack the blob and are successful.

With the credentials recovered we are able to authenticate as t.dalton against SMB using NetExec. But there are also no new shares available.

Shell as t.dalton
The user t.dalton is also member of the certificate enrollment users group. We enumerate for vulnerable certificates using the current version of Certipy.

We do find a template called TemporaryWinRM that is vulnerable to ESC13. Due to this misconfiguration, any user who can enroll a certificate using this template will automatically be granted the privileges of the linked group. Meaning we could obtain privileges to get a WinRM session as the user t.dalton.
A deep dive to ESC13 can be found in the following article:
Besides that the enrollable principals are NORTHSTONE.LOCAL\Certificate Enrollment Users which the user is member of.



We edit our /etc/hosts entry by adding the FQDN of the CA NORTHSTONE-CA.
Next, we request the vulnerable certificate and retrieve the PFX, granting us the permissions of the template's linked group as t.dalton.

Now we authenticate as t.dalton and retrieve the ccache file.

We still need to configure /etc/krb5.conf so the Kerberos libraries can use our ccache, allowing evil-winrm to authenticate via Kerberos. For this we will use the following script:
We run the script by providing the domain FQDN and the DC name and get the contents directly written to our /etc/krb5.conf file.

We export KRB5CCNAME=t.dalton.ccache so the Kerberos libraries know which credential cache to use when authenticating...
... and connect via evil-winrm. But still no flag.

Access as c.white
On the users Desktop we find an email about the WindowsUpdateChecker test setup.
Carls updates Tony that the WindowsUpdateChecker tool is being tested through a scheduled task running every minute under the c.white user context, performing update checks and closing afterward to provide a controlled execution loop. He noted that the tool still needs structural improvements, the previous DLL failed, and requested a new x64 DLL integrated into the application's directory with a flexible design for future functionality.
So this may imply that we could possible abuse the scheduled task via DLL hijacking to get a shell as c.white.

We do find the WindowsUpdateChecker executable at C:\Program Files\WindowsUpdateChecker. We download the file for further investigation decompiling it.

To decompile the binary we could try dnSpy.exe a .NET decompiler.
It is probably possible to use dnSpy.exe via Wine, but this did not work properly on my machine. If you still want to try it, you can do this as follows: WINEPREFIX=$HOME/.<INSERT YOUR PREFIX> wine dnSpy.exe. The executable can be obtained from the following resource:
There is an alternative to running dnSpy on a Windows VM.
We can use the plugin ILSpy which is not only available on Visual Studio but also on Visual Studio Code to decompile .NET binaries.
If you have not setup Visual Studio Code yet checkout the following resource:
We are using the ILSpy extension on VSCode to decompile the binary
The ILSpy plugin can be easily installed via the marketplace.

After having the plugin installed hit CTRL+SHIFT+P and enter ILSpy: Pick assembly from file system to pick the executable.
Here we see the wuaclt.dll loaded from C:\Program Files\WindowsUpdateChecker\modules\wuaclt.dll.

Preparation of DLL
We try a simple DLL hijack. We'll use the source code we assembled for the Dismay machine.
The idea is to download and execute a Sliver C2 stager to get a remote session.
When the DLL is loaded, it silently launches PowerShell, downloads stager.exe from our web server into the victim's %APPDATA% directory, and then executes it.
We compile the DLL...

Preparation Of Stager
Next, we need to prepare the stager.
The stager fetches raw shellcode from a chosen URL and loads it directly into memory as bytes. The payload is not embedded in the binary, allowing it to be changed without recompiling.
It calls VirtualAlloc to reserve and commit memory with execute, read, and write permissions, then copies the downloaded shellcode into that memory using unsafe pointer operations.
The execution is transferred to the allocated memory address using syscall.Syscall, handing control to the shellcode.
We compile the stager as follows on our exegol instance:
The addition of -ldflags="-H windowsgui" ensures that we compile it as an application and not a console app, so it wont spawn a terminal.
Since the stager got caught due to sample submission, but want to reuse it, we use a simple trick and use the -s -w ldflags for compilation. Using -s -w strips debug symbols and DWARF metadata from the Go binary, changing its hash and reducing recognizable signatures, which can help avoid detection because antivirus engines that previously flagged the original sample submission may no longer match the modified compiled file exactly. We might see this neat trick later again.

Generate shell code
Next, we need to generate the Sliver shell code.
During generation without the -G tag, which disables the encoder, no shellcode could be successfully generated. The resulting shellcode was always empty. This may be related to the underlying architecture on which I am operating, namely ARM:
We do this as follows:

Execution
We run a web server from which the stager and the shellcode can be fetched.
Setup listener
We set up the listener in Sliver as follows:

Next, we place our malicious DLL into the modules folder and wait.

Our stager gets feteched and executed which then fetches and executes our generate shell code.

After a short duration we retrive a session. We can interact with it via sessions -i ....
We are c.white.

We do find the users flag at the Desktop of c.white.

Access as k.bennet
Now that we have compromised the user c.white we'll take a look at the group memberships and outbound object control of the user. We see that the user is memebr of the database backup operators.

We recall the empty auth_test_users table of the NorthstoneDB. Maybe we can restore the users here.

On the root folder we find a BackupDB folder containing a backup file and a note.

The note clearly states that the auth_test_users has been removed.

A way to read its content to restore it into a SQL Server instance.

We create a docker container running MSSQL to restore the backup.
Next, create a backup directory inside the container
And copy the backup to the container.

Next, we interact with the container...

... and open an interactive sqlcmd shell connected to the local SQL Server instance as the sa user.

We restore the backup... but made a slight mistake and forgot to adjust the permission after copying the backup to the container.

We adjust ownership and permission of the file.

And retry. We are able to restore the backup and query the database.

We restore the NorthStoneDB database from the .bak file using the MOVE clauses to map the backup's logical file names NorthStoneDB for the data file and NorthStoneDB_log for the transaction log to physical paths inside the container's data directory. which is necessary because the original paths baked into the backup likely Windows-style C:\ paths won't exist on the Linux container, so we redirect them to /var/opt/mssql/data/.

Now we can query for the databases.

We'll us the NorthStoneDB. And query for all entries of the auth_test_users table. We are able to retrive the credentials of three users.

We are able to authenticate as k.bennett.

Furthermore we found the MSSQL credentials in the powershell history of the user c.white. Which would have allowed us to restore the backup from the target machine...

Access as r.parker
As k.bennett we have the capability to change the password of three different users. This looks promising.

We mark the user k.bennett as owned query for the shortest path from owned objects.
There we can see that we could potentially move latterally to l.turner via r.parker. The user l.turner is member of the print services operators and remote management users that looks like another high value target. From r.parker we only have GenericWrite permissions over l.turner which would allow us a targetedKerberoast or maybe a ShadowCredentials attack.

We follow the depicted attack path by BloodHound and change the password of r.parker.

We have now access as r.parker.

Shell as l.turner
Next, we preform a targetdKerberoast and without specifying a user we are able to retrieve the Kerberos 5, etype 23, TGS-REP blobs of three users.

But they do not seem not crack.
Our last reort is a shadows credentials attack.
To perform the Shadow Credentials Attack we are using Certipy.
In short: If we can write to the msDS-KeyCredentialLink property of a user, we can retrieve the NT hash of that user.
With the following command we issue the attack and are succesful. We retrieve the NT hash of l.turner.

We are able to authenticate with the hash...

... and retrieve a remote management session using evil-winrm.

Shell as NT AUTHORITY\SYSTEM
We recall the group membership of l.turner.

Members of this group are responsible for managing printer-related operations. This includes access to printer service files, directories, and scheduled tasks used for maintenance and monitoring
We look for any print related service and actually find the PrintNotifyService.

The idea is to replace the binPath pointing to the PrintNotifyService executable located at C:\Program Files\PrintNotify\printer.exe with our stagers location - we crafted formerly - and restart the service to establish a Sliver C2 session. For now we upload the stager.

We are actually able to stop, start and configure the service. We change the binPath to our stagers location.

After running the service we get an error message...

... but also a short session that dies as NT AUTHORITY\SYSTEM.

This is due to the fact that our stager executable is not an actual service and does respond to start or control requests, it will receive a timeout and be terminated after running the shellcode. We face the same issue in the scenario Kiosk.
We grab the service stager we build for the Kiosk lab:
Compile it...

...and repeat our steps. But first we sop our stager processes and remove the stager to avoid confusion.
We upload the new service stager, but rename it this time and configure the binPath again.
We start the service...

... and receive a session. The service does not get terminated and we have a stable session. We are NT AUTHORITY\SYSTEM and are able to retrieve the root flag at C:\Users\Administrator\desktop\root.txt.

Last updated