HTB Module: Login Brute Forcing
For my first module on HTB, I chose the Login Brute Forcing module. It just felt like the most “hacker” module I could reasonably do without needing an insane amount of technical knowledge. As a disclaimer, I have done password cracking CTFs before, but they were all done with John the Ripper and did not have any web components, they were all cracking PDFs.
Basic Brute Force Attacks
The module starts with a brute force login attack, which tries every possible combination until there’s a successful login. What can go wrong with that? Well, if we remove every countermeasure to prevent repeated login attempts, nothing can go wrong, but nothing will go right either, for a very, very long time. If your password was 12 alphanumeric characters long, it would take 30,000 years to guess. Thankfully, this HTB lab limited it to a 4-digit pin, and we used a Python script that sent every possible pin to the target machine’s IP address and port until we got a response with status code 200 (success) from the server.
Wordlists
The next part of the module covers wordlists, which use the same approach of trying multiple possible passwords, but limit the possible password inputs to likely ones. The first wordlist problem required us to download rockyou.txt, which is a document that contains millions of the most common passwords found in breaches. So instead of incrementing a password, every attempt comes from rockyou.txt.
One of the password cracking CTFs I have done in the past was one offered in MasonCCs TCTF challenges, labelled “Gotta crack them all”, where you were given a PDF and the only hint you had was that the PDF owner loves pokemon. I tried obtaining a wordlist of every pokemon in existence and ran it through John the Ripper’s incremental mode, which added numbers and made small adjustments to each entry such as incorporating digits in place of characters and changing cases of some characters. I was fortunate to remember a website that can give you a list of pokemons that fill a certain category for competitive pokemon use, otherwise I would have asked ChatGPT only for it to miss like 150 pokemons. This was my first foray into using OSINT to crack a password and making a custom wordlist. Thankfully, this HTB module introduced me to a tool specifically made to incorporate OSINT into custom wordlists.
CUPP (Common User Passwords Profiler)
CUPP (Common User Passwords Profiler) is a tool that creates multiple possible passwords by feeding it several pieces of information relating to the target. Pieces of information include:
- Name
- Nickname
- Birthdate
- Pet
- Company
- Interests
- Favorite colors
- And custom information
It creates multiple combinations of these fields and tries a list of string operations such as reversing a string, concatenations, special character inserting, leetspeak substitutions and much more. It also lets you specify the specific password requirements to downsize the possible pool of passwords to attempt.
Basic Authentication
The first defensive mechanism presented in this module is Basic Auth, which is a rudimentary yet common method for protecting resources on the web. Basic Auth transports credentials by concatenating the username and password, encoding them in base64, and requiring authentication whenever an attacker or user tries to access a protected resource.
GET /protected_resource HTTP/1.1
Host: www.example.com
Authorization: Basic YWxpY2U6c2VjcmV0MTIz
Basic Auth in an HTTP GET request
Hydra is used to brute force the basic authentication target using the HTTP-GET hydra service and will use a given wordlist:
hydra -l basic-auth-user -P passwords.txt 127.0.0.1 http-get / -s 81
Using Hydra to brute force Basic Auth
Custom Login Forms
Websites employ custom login forms as an authentication mechanism. While one might think, “Ok, if it’s just a form asking for a username and password, surely we can have a tool that automates brute force attempts using the same form on every website that uses login forms,” this is actually not the case since websites customize their login forms. These forms are HTML forms embedded within a webpage and contain other features such as a submit button, which can vary in implementation across different websites.
<form action="/login" method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username"><br><br>
<label for="password">Password:</label>
<input type="password" id="password" name="password"><br><br>
<input type="submit" value="Submit">
</form>
An example of login form that has a submit button
When this form is sent via a POST request to the /login endpoint on the server with the credentials entered:
POST /login HTTP/1.1
Host: www.example.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 29
username=john&password=secret123
POST request with form credentials
/loginspecifies the URL endpoint which handles the login requestContent-typeindicates how data is encodedContent-Lengthstates the size of the data being sent- The credentials are present in the request body and contain the username & password as an encoded key-value pair.
Previously when we used Hydra, we specified the service to be HTTP-GET, but for this POST form we will be using HTTP-POST-FORM to enable the automation of POST requests. The difference with this service is that it now includes a condition string. Hydra relies on either failure conditions or success conditions to determine a successful login. It determines the success of an attempt by comparing the response from the server to its condition string. If the server returns an error message such as “Invalid username or password,” that obviously means the attack was not successful, so if we put this as a fail condition in our Hydra command, it can determine the attack’s success. Login attempt responses vary between websites, and sometimes you want to use a success condition instead of a fail condition, such as receiving an HTTP 302 redirect status code, or even HTTP results containing the word “Dashboard”.
hydra ... http-post-form "/login:user=^USER^&pass=^PASS^:S=302"
Hydra command with success condition (HTTP 302 redirect)
hydra ... http-post-form "/login:user=^USER^&pass=^PASS^:S=Dashboard"
Hydra command with success condition (Dashboard keyword)
To start this attack, the form structure and the target path must be obtained. Inspecting the website and selecting the “Network” tab will display the POST request sent to the server when submitting the form. This shows the form data, headers, and server response.
The server uses a basic form with a username and password field which is submitted to the root path. When an incorrect submission is sent, an error message “Invalid credentials” is displayed. Therefore, the parameter string would be:
/:username=^USER^&password=^PASS^:F=Invalid credentials
Hydra parameter string with failure condition
This leads to the complete command:
hydra -L top-usernames-shortlist.txt -P 2023-200_most_used_passwords.txt -f IP -s 5000 http-post-form "/:username=^USER^&password=^PASS^:F=Invalid credentials"
Complete Hydra command for brute forcing a custom login form
Medusa
The last tool we are presented with is Medusa, which provides users with a wide variety of services that allow remote authentication and is designed to be used as a modular and parallel login brute forcer. It supports multiple modules such as FTP, HTTP, IMAP, MySQL, SSH, and others. In this lab, we are tasked with targeting an SSH server and are provided a list of potential passwords, IP, port, and a confirmed username sshuser. We launch a brute-force attack against the SSH server with the following command:
medusa -h <IP> -n <PORT> -u sshuser -P 2023-200_most_used_passwords.txt -M ssh -t 3
Medusa command for brute forcing SSH
Once we obtain the password, we connect to the SSH service and enter the password when prompted. We’re in—now what? Let’s see what we can do now that we have access. We run the netstat and nmap localhost commands within the SSH session to see if there are any open ports. We see that there’s an active service on port 21, and thanks to the nmap command we can identify that the service is an FTP service. We could install a common username list and try to brute force our way in, but let’s do some recon to see if there’s any trace of a username or perhaps a password. We are able to locate an FTPUser folder which indicates that the username might be ftpuser.
Thankfully, we are able to use medusa on this SSH session (which probably should not be possible in a realistic setting), and we run a medusa command targeting this FTP server using a common password list. Upon getting the FTP password, we establish an FTP connection and use the get command to download a flag.txt file present and obtain the flag.
With that, we are finished the learning labs for this module, you can find the assesment writeup here.