HSM Defense
Challenge Lab (Hard) - by 2ubZ3r0
The following post by 0xb0b is licensed under CC BY 4.0
Scenario
Objective
HSM Defense is a defense contractor, and is required to have an in-depth penetration test done against their internal Domain Controller. You have been hired to perform a comprehensive penetration test and, if possible, elevate your privileges to Domain Admin to demonstrate impact.
Initial Access
You have been provided credentials for a low-privileged Active Directory user.
Username: kelly.johnson Password: Lordofwar
There is also a way to solve this lab from a "blackbox" perspective with no credentials. If you'd like an added challenge... give it a shot!
Summary
Recon
We use rustscan -b 500 -a 10.1.87.19 --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.1.87.19 is a Domain Controller, DC.hsm-defense.local, in the hsm-defense.local domain. 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. Remote management and access are available through RDP on port 3389 and WinRM on ports 5985 and 47001. The host also exposes AD Web Services on port 9389, RPC over HTTP on port 593, and several MSRPC endpoints on ports 135, 49664–49724. An IIS 10.0 web server on port 80 serves a site titled "Office Careers | HSM Defense", suggesting a career portal or web application. Notably, the DC is also running hMailServer, providing SMTP on ports 25 and 587, POP3 on port 110, and IMAP on port 143.


SMB
We will generate a hosts file entry with the following command and see that NTLM authentication is not supported, meaning we may need to use Kerberos authentication via the -k flag if we find any credentials.

We add the following entry to our /etc/hosts file.
We generate the krb5.conf file using NetExec so that Kerberos knows which domain controller to contact for authentication in all future Kerberos-based requests.

WEB
We will continue with the enumeration of the website hosted on the DC. We start a directory scan, but do not find any interesting endpoints.

However, the VHOST enumeration returned one match; we found a support vhost..

We add the following entry to our /etc/hosts file.
We visit the support page, but it requires credentials. Since our approach does not involve using the assumed breach credentials, we'll start by looking at the main page, which didn't turn up anything of interest during the directory scan.

We visit the page and only find a static site infront of us.

Access as kelly.johnson
But if we scroll down a bit further, we'll find a call for applications at careers@hsm-defense.local. We can apply by sending a resume in ODT or ODP format.
So we could try to establish a reverse shell using a macro document or one that, when opened, establishes an unsecured connection to an external network share in order to intercept NetNTLM hashes.
From our port scan, we know that a mail server is indeed running. So we'll try this approach.

We'll prepare the ODT document. Metasploit offers a wide range of options.

We'll search for the odt modules and test the results from each one. We'll succeed in this lab with odt_badodt. This is the one.when opened, establishes an unsecured connection to an external network share in order to intercept NetNTLM hashes.
We use the module.
Set the LHOST to our tun0 interface...
... and run the exploit. We end up with a bad.odt file.

Next, we setup responder to retrieve the NTLM hash of the user opening the file.

Now, we only need to send a mail to careers@hsm-defense.local with the bad.odt file attached. For this we are using swaks.

After sending the file we might end up with a hash in responder.

We can then crack this hash using hashcat and the rockyou.txt file.

We test the credentials of kelly.johnson using NetExec and receive the same error message STATUS_NOT_SUPPORTED as in our initial enumeration phase using the guest account. We need to use the -k flag in NetExec to authenticate via Kerberos instead of NTLM, since the target does not support NTLM authentication.

If not already done, we generate the krb5.conf file using NetExec so that Kerberos knows which domain controller to contact for authentication in all future Kerberos-based requests.
We test the credentails of kelly.johnson using with the -k parameter and successfully authenticate via Kerberos. At first glance, we don't see any notable shares.

With the credentials, we'll enumerate the domain using BloodHound. Fortunately, the bloodhound-ce ingestor supports Kerberos authentication by default, allowing us to enumerate the domain without any issues.

We'll mark the user kelly.johnson as owned and take a look at permissions the user has an the group memberships. We see that the user is a member of the it-ticket-handlers group. Perhaps we can log in with that user on the support page we found earlier.

The only Domain Admin is the Administrator user.

We visit the support page again and enter the credentials of kelly.johnson.

We gain access to the support page, which contains several tickets with highly sensitive information that we might be able to use to our advantage.
Ticket 2417 is one of those. It states that a password was apparently set manually for the HELPDESK01$ machine account for troubleshooting purposes and now needs to be reset. We may be able to use timeroasting to obtain the credentials for HELPDESK01$ since manually set passwords tend to be weaker and crackable compared to the auto-generated random passwords that machine accounts normally have.

We also take note of the ticket 2422. The user jason.caldwell has the status KDC_ERROR_CLIENT_REVOKED and can no longer log in. This may be due to incorrectly set logon hours. A user with write permissions on the jason.caldwell user object could correct these logon hours if the credentials for that user can be obtained.

Furthermore there is an enigneering console we can open which looks like a sandboxed terminal. But we cannot leverage anything from it to compromise the target.

Access as HELPDESK01$
We recall the ticket 2417 and attempt to gain access to the HELPDESK01$ machine account using the aformentiond Timeroasting attack.

In BloodHound, we can see that the HELPDESK01$ machine account might be a valuable target since it has WriteOwner permissions on the servicedesk group. Specifically, once we obtain the credentials for HELPDESK01$, we can set it as the owner of the servicedesk group, grant ourselves GenericAll on the group, and then add a user we control to the group, thereby gaining all the permissions of the servicedesk group.

We perform the timeroasting attack.

Timeroasting is an attack technique that abuses Microsoft's proprietary NTP extension to extract password-equivalent hashes for computer and trust accounts from domain controllers without requiring authentication. These hashes can subsequently be cracked offline.
Domain-joined computers synchronize their system clocks using NTP, with domain controllers acting as authoritative time sources. To address NTP's lack of authentication, Microsoft implemented a custom extension that cryptographically authenticates NTP responses using computer account credentials.
When a computer requests time synchronization, it includes its computer account's RID (Relative Identifier) in the NTP request. The domain controller responds with a Message Authentication Code (MAC) computed using the computer account's NTLM hash as the key. This design allows unauthenticated clients to request salted password hashes for any computer account in the domain by specifying different RID values.
A nice article about Timeroasting can be found here:
Via Timeroasting we are able to retrieve three SNTP hashes that can we try to crack using Hashcat mode 31300.


Unfortunately my version installed was too old and did not support the mode.
For convinience I switched to my Windows host wich had hashcat v7.1.2 already present. We are able to crack the hash for the user with the RID 1105.

We try to authenticate as HELPDESK01$ with the recovered password and are successful.

Let's take a closer look at the BloodHound data and see that we can change the passwords for the accounts jason.caldwell, ethan.mercer, and luke.harrison through the service desk group. So we can take over these accounts.
The user jason.caldwell is particularly interesting because that user is a member of the remote management users group, which allows us to get an interactive session on the domain controller. However, we also know from the support tickets that this user may have set the logon hours incorrectly, and we may not be able to authenticate with that account.

Furthermore, the user luke.harrison is also of interest because the user is a member of the account administration group; it's possible that we have additional permissions through this group, but we don't see them directly in our Bloodhound data.

Access as jason.caldwell
We follow the path analyzed from our Bloodhound data and take over the service desk group to gain control of the user jason.caldwell and thereby establish a remote session to the DC.
So, we set the HELPDESK01$ machine account as the owner of the servicedesk group, grant ourselves GenericAll on the group, and then add a user we control to the group, thereby gaining all the permissions of the servicedesk group. After that we change that password of the desired users.
WriteOwner -> change ourself to owner
We change the ownership of the target Active Directory object servicedesk to our controlled machine account HELPDESK01$ so we gain full control over it.

Grant us GenericAll over the Group
We grant the account junior.analyst GenericAll permissions over the target group servicedesk, giving us full control over the object and its attributes.

AddMember: Add HELPDESK01$ to the group
We add the account HELPDESK01$ as a member of the servicedesk group to inherit its privileges.
This abuse can be carried out when controlling an object that has a GenericAll, GenericWrite, Self, AllExtendedRights or Self-Membership, over the target group.

ForceChangePassword
We reset the password of the jason.caldwell account to a known value, allowing us to authenticate as that user.

We test the credentials using NetExec and are not able to authenticate, we get the error KDC_ERR_CLIENT_REVOKED.

Like mentioned in ticket no. 2422. So let's see if we can adjust the logon hours.

Access as luke.harrison
We try to gain access as luke.harrison then. The group account administration looks very promising.

We reset the password of the luke.harrison account to a known value, allowing us to authenticate as that user.

We test the credentials using NetExec and are able to authenticate.

We enumerate the writable objects to identify an alternative path that is not covered in the BloodHound data. The user luke.harrison has write premissions overthe user jason.cadwell, which means we can modify that user's attributes. Bingo, we might be able to fix the logonhours.

Querying for a detailed report we see we have write permissions over the logonHours.

The Write permission lets us clear it outright with bloodyAD's set object module.

We try to authenticate as jason.caldwell using NetExec again, and we authenticate successfully.

Now to get a session via evil-winrm we request a TGT and export the ccache file.

We are able to login, but do not find the user flag yet.

Shell as caleb.turner
We enumerate the system and we see that MySQL appears to be running internally on port 3306.

We find the intallation folder at C:\Program Files\MariaDB 10.6.

Inside the .ini file we find the database credentials which would allow us to authenticate agains the service.

We enumerate the database and find a new_employees databases.

We query for the entries insied the employees table and do find three MD5 hashes.

Using hashcat, we can actually crack a hash that appears twice. Perhaps the password is also used for onboarding in Active Directory.

We enumerate the domain users using NetExec...

... and sparay the password against every user and we get two hits. We have now access to the user accounts aaron.pierce and caleb.turner.

We'll look those users up in our BloodHound data. The user aaron.pierce just seems to be a new user without any special permissions.

But, the user caleb.turner seems to be a very interesting one. Still a new employed but also in the remote management users group and in the IT OU operators group. So maybe we are able to play arround with the OUs present in the domain.

We see we have GenericAll permission over several users and IT-TIER2 to IT-TIER4 OUs. Unfortunately not to IT-TIER1 which seems to be more valuable, but more on that later.

Now to get a session via evil-winrm we request a TGT and export the ccache file.

And we are able to log in as caleb.turner.

We do find the users flag at C:\Users\caleb.turner\Desktop\user.txt.

Shell as oscar.mazerath
Let's take a look at the TIER-1 group...

It includes three users, of whom oscar.mazerath is the most interesting. With the GenericWrite on those three users we might be able to pull of a shadow credentials attack or a targeted Kerberoast to gain control of such accounts.

Of these three, ryan.cole stands out because that user is the only one inthe remote desktop group of those three. Perhaps this user has more to offer. So the path looks like this: with caleb.turner in the IT OU operators group, we somehow (still unclear) gain access to the Tier 1 group, obtain access as oscar.mazerath, and from there we take over the user ryan.cole to continue enumerating the target via the Remote Desktop session.

We request a TGT and export the ccache file.

We enumerate the writable objects and see that we have write permissions over oscar.mazerath in the IT-Tier1 OU.

To understand what we can actually do with our IT OU operators membership, we dump the ACLs on each IT-Tier OU using bloodyAD.

The results reveal the following ACL configuration across the four OUs:
IT-Tier1: caleb.turner has a DELETE_CHILD permission, but the IT OU operators group has no ACEs here. This means we can remove objects from this OU but cannot write to them through group membership alone.
IT-Tier2: The IT OU operators group has GenericAll with CONTAINER_INHERIT, but two Deny ACEs override it. CREATE_CHILD for User objects and WRITE_PROP are both denied. Since Deny always wins over Allow, this OU is locked down for us.
IT-Tier3: The IT OU operators has also a GenericAll with CONTAINER_INHERIT and no Deny ACEs. This is the target, full, unrestricted control over this OU and any objects within it.
IT-Tier4: IT OU operators has GenericAll with CONTAINER_INHERIT, but CREATE_CHILD for User objects is denied. Similar to Tier2 but slightly less restrictive.
Moving an AD object between OUs requires DELETE_CHILD on the source OU and CREATE_CHILD on the destination OU. We have both: DELETE_CHILD on IT-Tier1 through caleb.turner's direct ACE, and CREATE_CHILD on IT-Tier3 through IT OU Operators' GenericAll (which includes CREATE_CHILD) with no Deny ACEs blocking it. Once oscar.mazerath lands in IT-Tier3, the CONTAINER_INHERIT flag on the GenericAll ACE kicks in, granting us full control over the user object.
DELETE_CHILD on Tier1 (source) — as caleb.turner directly
CREATE_CHILD on Tier3 (destination) — via IT OU Operators membership
We move oscar.mazerath from IT-Tier1 to IT-Tier3.

Now, we can change the password of oscar.mazerath through the GenericAll we have on IT-Tier3

We test the credentials and are able to authenticate.

Shell as ryan.cole
We request a TGT and export the ccache file for oscar.mazerath.

And perform now the aformentioned targetedKerberoast attack on ryan.cole. But the resulting blob is to strong to crack.

We perform a downgrade like performed in NovaForge. Using our GenericWrite over ryan.cole, we downgrade the account's supported encryption types by setting msDS-SupportedEncryptionTypes to 4, which forces the KDC to issue RC4-encrypted $krb5tgs$23$ tickets instead of AES:

We perform the targetedKerberoast attack again and retrieve a weaker blob...

... which we are able to crack.

And we are able to authenticate with the credentials gathered.

We request a TGT to authenticate via xfreerdp using Kerberos.

We get a remote session thorugh RDP and do find a mail and a shortcut to a SSH application.

Access as itops01$
In that mail we see that the SSH Remote Tool we found on the desktop of the user is used to get SSH sessions against legacy system that do not support modern encryption standards. The user is tasked to only use that tool internally due to security concerns.

We start the app and see that we are able to adjust the target host and port.

We try a simple test and start a listener on our attacker machine on port 22 and make a conection to our host via establish connection.

We see that the connection is being made but no credentials are leaked.

We make use ao SSH-LOG a tool written in go to capture SSH credentiasls and log client commands.
SSH-Log is a tool to capture SSH credentials and log client commands. It uses the private key of a valid SSH daemon to appear legitimate. It is not a high interaction honeypot. If a client uses valid credentials SSHlog can spawn a real shell and record the input and output of client commands. SSHlog-mini is a simplified version of SSHlog that only captures SSH credentials.
We build the binary and run it. After we esablish a connection we see the cleartext credentials leaked of the machine account ITOPS01$.

Next, we test the credentials and are able to authenticate.

Access as svc_delegate
The machine account ITOPS01$ holds WriteDACL over svc_delegate, which allows full rights to be granted over the account and control of svc_delegate to be taken.

ITOPS01$ has WriteDACL on svc_delegate. We grant ourselves FullControl and reset the password.

With full control established, we reset the password of svc_delegate to take over the account:

We test the credentials and are able to authenticate.

Shell as Administrator
The user svc_delegate has GenericWrite on HELPDESK01$. Since GenericWrite allows us to modify nearly any attribute on the target object, we can configure Kerberos constrained delegation with protocol transition on HELPDESK01$. This allows HELPDESK01$ to impersonate any user, including the Administrator, to a service of our choosing on the DC. We target the machine account specifically because the S4U2Self step in the delegation chain requires the delegating account to have a Service Principal Name. Machine accounts receive SPNs automatically when they join the domain (e.g., HOST/HELPDESK01$), so the delegation works out of the box. A normal user account would not have an SPN by default, and the S4U2Self request would fail.

We request a TGT for svc_delegate and export the ccache file.

So we follow the approach to configure Kerberos constrained delegation with protocol transition, allowing HELPDESK01$ to impersonate any user to the LDAP service on the DC.
We configure the delegation in two steps. First, we set the msDS-AllowedToDelegateTo attribute on HELPDESK01$ to target the LDAP service on the DC. This tells Active Directory that HELPDESK01$ is allowed to delegate credentials to ldap/DC.hsm-defense.local.
Second, we enable protocol transition by setting the TRUSTED_TO_AUTH_FOR_DELEGATION UAC flag. Without this flag, the delegation would require the impersonated user to authenticate to HELPDESK01$ first. With protocol transition enabled, HELPDESK01$ can request a service ticket on behalf of any user without that user's involvement.

Now we exploit the delegation. We request a TGT for HELPDESK01$ with the credentials we cracked earlier.

Using getST.py, we request a service ticket for ldap/DC.hsm-defense.local while impersonating the Administrator account. Due to protocol transition, this works without the Administrator's password. HELPDESK01$ performs S4U2Self to obtain a forwardable ticket and then S4U2Proxy to delegate it to the LDAP service.

We export the resulting ccache file and use secretsdump.py to perform a DCSync attack over LDAP as Administrator, dumping all domain hashes.

With the Administrator's NTLM hash, we request a TGT using pass-the-hash and log in to the DC via evil-winrm.

We are now able to get a remote session as Administrator on the DC...

... and find the final flag at C:\Users\Administrator\Desktop\root.txt.

Last updated