When you come in contact with a Windows domain, you may want to try and leverage Password Spraying attacks (really, you should –they’re super effective). But how do you get a valid list of usernames to load into your password sprayer?
Downloading the Tool
You could leverage a tool called KerBrute to pull this off. A quick Google search on this tool returns the following Github page.
With the tool in hand, we can view the help documentation.
Now we just need to prepare a list of users to enumerate. If you’ve already started to find usernames around the network, you can make your own customer user list. Otherwise, you can leverage something from the seclists usernames list, which can be downloaded at the following page.
In a recent post, I showed you how to Brute-force Subdomains w/ WFuzz. This time, I’m going to show you how we can use the same tool to brute-force a list of valid users. This guide is going to use Falafel from Hack The Box as an example, but does not intend to serve as a walkthrough or write-up of the machine.
Setting the Stage
If we navigate to the web interface of the box, we can attempt to sign into a login page. We notice that when we type a valid username into the field, the error message states “Wrong identification“.
However, entering a username that doesn’t exist returns a message that states “Try again..” We can use this to enumerate valid usernames.
Looking at the request in Burp, we see that its being sent as a /POST request with two parameters; username and password.
Using WFuzz to Brute-Force Valid Users
To begin, we’ll need a wordlist that contains a list of usernames. Seclists has one that is great for this, which you can get from Github. I have mine downloaded already.
Let’s start piecing together our command! Let me break down all the pieces that we’ll use.
-c : Return output in color. -z file,<wordlist> : Specify our payload. In this case, a list of usernames. --sc 200 : Show responses that return a response code of 200. -d "username=FUZZ&password=anything" : Provide parameters for the /POST request.
Putting all of the above together, this is what our first command looks like!
Likely, the webserver you’re attacking is configured to always respond with a 200 response code. For example, let’s look at BART on Hack The Box.
Let’s see if we can extract anything with Curl. We’ll start by sending a request out to the default page. We see that it returns a 302 redirect to forum.bart.htb.
curl -vvv 10.10.10.81
Let’s try a request to a page we know doesn’t exist, and we are returned a success 200 message that displays an image. This explains why Gobuster was returning a 200 message on each directory.
We can confirm this by browsing to the page and looking at the image.
Armed with this information, we know that 200 response codes are bad, but other response codes (such as a 302) indicate a directory is present. Let’s rerun our Gobuster command, but we’ll specify which response codes we want returned.
Checking the help page, we can see that Gobuster accepts the following response codes; “200,204,301,302,307,401,403”.
So our command will look like this.
gobuster dir -u http://10.10.10.81 -w /usr/share/dirbuster/wordlists/directory-list-lowercase-2.3-medium.txt -s "204,301,302,307,401,403"
And with that command running, we eventually start to get some real results back.
This guide is going to use CMess from TryHack.me as an example, but does not intend to serve as a walkthrough or write-up of the machine.
Before we begin, make sure you can resolve the domain name that we’re targeting. If you’re doing this in a CTF-type environment, you may need to update your /etc/hosts file with the hostname/address of the target.
We can use a tool called wfuzz to bruteforce a list of subdomains, but first, we’ll need a list to use.
Now you may get a ton of output that shows valid subdomains depending on how the site is configured. If you notice a large amount of results that contain the same word count, this may just be an indication that the site returns a 200 response, but it just displays a “Not found” error.
To remove results with a specific word count, you can append your command w/ --hw <value>. For example, our new command that removes results that respond w/ a word count of 290 would look like the following:
This will return a list of subdomains that do not contain a word count of 290. If you get a successful result, make sure you’re able to resolve the subdomain as well before trying to browse to it. If you’re in a CTF-type environment, you may need to update your /etc/hosts file.
With our /etc/hosts file updated, we should be able to browse to the page.
Encrypt and Anonymize Your Internet Connection for as Little as $3/mo with PIA VPN. Learn More
While working through NINEVAH on HackTheBack (Write-Up on this coming in a future post), I came across a couple web forms that I needed to break into. In my opinion, using the Intruder feature within BurpSuite is an easier way to run brute-force attacks, but the effectiveness of the tool is greatly reduced when using the free community version. Instead of dealing with slow brute-force attempts, I decided to give Hydra a try.
Hydra is a fairly straight forward tool to use, but we have to first understand what it needs to work correctly. We’ll need to provide the following in order to break in:
Login or Wordlist for Usernames
Password or Wordlist for Passwords
IP address or Hostname
HTTP Method (POST/GET)
Directory/Path to the Login Page
Request Body for Username/Password
A Way to Identify Failed Attempts
Let’s start piecing together all the necessary flags before finalizing our command.
In our particular case, we know that the username Admin exists, which will be my target currently. This means we’ll want to use the -l flag for Login. -l admin
Note: If you don’t know the username, you could leverage -L to provide a wordlist and attempt to enumerate usernames. This will only be effective if the website provides a way for you to determine correct usernames, such as saying “Incorrect Username” or “Incorrect Password”, rather than a vague message like “Invalid Credentials”.
We don’t know the password, so we’ll want to use a wordlist in order to perform a Dictionary Attack. Let’s try using the common rockyou.txt list (by specifying a capital -P) available on Kali in the /usr/share/wordlists/ directory. -P /usr/share/wordlists/rockyou.txt
IP Address to Attack
This one is easy! 10.10.10.43
This is where we need to start pulling details about the webpage. Let’s head back into our browser, right-click, and Inspect Element.
A window should pop-up on the bottom of the page. Go ahead and select the Network tab.
Right away, we see a couple GET methods listed here, but let’s see what happens if we attempt a login. Go ahead and type in a random username/password, and click Log In.
Of course our login attempt will fail, but we’re able to see that this website is using a POST method to log-in by looking at the requests.
Easy enough, now we know what method to specify in our command! http-post-form Note: You’ll need to enter https if you’re attacking a site on port 443.
Specifying the Path to Attack
So far, we’ve only told the tool to attack the IP address of the target, but we haven’t specified where the login page lives. Let’s prepare that now. /department/login.php
Finding & Specifying Location of Username/Password Form(s)
This is the hardest part, but it’s actually surprisingly simple. Let’s head back over to our browser window. We should still have the Inspect Element window open on the Network Tab. With our Post request still selected, let’s click Edit and Resend.
Now we see a section called Request Body that contains the username and password you entered earlier! We’ll want to grab this entire request for Hydra to use.
In my case, the unmodified request looks like this: username=InfiniteLogins&password=Password
Because we know the username we’re after is “admin”, I’m going to hardcode that into the request. I’ll also replace the “Password” I entered with ^PASS^. This will tell Hydra to enter the words from our list in this position of the request. My modified request that I’ll place into my Hydra command looks like this: username=admin&password=^PASS^
Note: If we desired, we could also brute-force usernames by specifying ^USER^ instead of admin.
Identifying & Specifying Failed Attempts
Finally, we just need a way to let Hydra know whether or not we successfully logged-in. Since we can’t see what the page looks like upon a successful login, we’ll need to specify what the page looks like on a failed login.
Let’s head back to our browser and attempt to login using the username of admin and password of password.
As we saw before, we’re presented with text that reads “Invalid Password!” Let’s copy this, and paste it into our command: Invalid Password!
Piecing the Command Together
Let’s take all of the components mentioned above, but place them into a single command. Here’s the syntax that we’re going to need.
After filling in the placeholders, here’s our actual command! sudo hydra -l admin -P /usr/share/wordlists/rockyou.txt 10.10.10.43 http-post-form "/department/login.php:username=admin&password=^PASS^:Invalid Password!"
Note: I ran into issues later on when trying to execute this copied command out of this WordPress site. You may need to delete and re-enter your quotation marks within the terminal window before the command will work properly for you.
After a few minutes, we uncover the password to sign in! admin:1q2w3e4r5t
Using Hydra to Brute-Force Our Second Login Page
Go through the exact same steps as above, and you should end up with a command that looks like this. sudo hydra -l admin -P /usr/share/wordlists/rockyou.txt 10.10.10.43 https-post-form "/db/index.php:password=^PASS^&remember=yes&login=Log+In&proc_login=true:Incorrect password"
So what’s different between this command and the one we ran earlier? Let’s make note of the things that changed.
Method was switched to https-post-form
Path was updated to /db/index.php
Request Body is completely different, but we still hard-code admin and replace the password with ^PASS^
Finally, the text returned for a failed attempt reads Incorrectpassword
After running the command, we uncover the password after just a couple minutes. admin:password123
Let me know if you found this at all helpful, or if something didn’t quite work for you!