Brute Force and SQL Injection on Logins

by Vince
in Blog
Hits: 7094

Hacking is doing something that wasn't meant to be done.  Or perhaps a better way of putting it is to say that when the designer designed their product, they were not thinking of our method of interaction. 

When the login form below was designed, the idea was that a decent person would visit this site with the intention of logging in with their credentials.




And if a decent person were to mistype their username and / or password, there would be a response to allow that decent person an attempt to resolve that issue.





But we can't have nice things so when we see this form, we wonder -- what is behind this form?  Is it SQL?  So we poke it with a single quote, daring it to do SOMETHING:




Sometimes we don't get a response other than a return back to the original login but sometimes we get an error which gives us a clue:




This kind of poking around isn't exact and there's a bit of messing around to be done.  

In a previous post, if you scroll down about half way, you'll find a SQL injection cheat sheet of sorts.  It's not the end all be all.  In fact, it doesn't show you this one but it gives you ideas for blind SQL injection.

In some cases, we get a response back which includes our query where we have an opportunity to see maybe where we messed up with our guess.  The above injection cheat sheet is more for blind SQL injection but when I first came across it, it gave me new ideas which is what you see below.  Not listed on the sheet in this form but listed in part for a password injection, we take admin and we append ' or '1'='1 for our username.  

This login form closes out the statement with a trailing single quote so we're basically saying my login name is admin or 1=1.  My math skills aren't perfect but I think 1=1.

If we take a look at what we're doing, we're essentially stopping the process before we hit the password because we've ended the statement and 1=1 is a true statement.  Game over.




We put this into the box above and we get:




Again, we've stopped it at 1=1 and we're not processing anything beyond that now:




The above is literally what I typed into the Username field after closing off '1'='1' and adding to it.

On a simple login, I might just try poking around rather than pulling out bigger guns.  But maybe I don't get anywhere so then I fire up Burp and grab the transaction:




hydra 192.168.90.47 http-get-form "/dvwa/vulnerabilities/brute/index.php:username=^USER^&password=^PASS^&Login=Login:Username and/or password
incorrect." -L users.txt -P /usr/share/wordlists/top1000.txt


We execute hydra, we give it the IP address, this is a GET request instead of a POST request so notice the change from the typical http-form-post vs http-get-form, we're giving it the remaining portion of the URL past the address, we populate the names of a form fields (username and password), we're putting the placeholders for our brute force (^USER and ^PASSWORD), and we're also adding in the remaining part of the request which we find in Burp.  Without Login=Login, we're going to fail so we need to pay attention to the full request and perhaps tweak things accordingly if we're seeing unexpected results.  Continuing on, we see the response for an invalid login attempt and finally, we're referencing the users file and passwords file.

When we kick it off, hydra goes to work:




Hydra finds the username and password.  But what if it didn't and we suspect we have some sort of SQL injection.  We take that post request from Burp and we save it into a file titled:  post.txt

Now we go after the login with sqlmap.  Let's start off simple:




That's fantastic -- the GET parameter 'username' is vulnerable.  But now what?  If we would have added one more item, we would have retrieved some gold:




Adding --dbs fetches the databases.

Everything builds upon everything else.  Now that we have databases, we want tables:




Now that we have tables, we want to retrieve data from those tables:




In some situations, we don't go straight to passwords, sometimes we just get hashes or something else altogether.  Depends on that tables and what's in them.  But in this situation, we get hashes and it offers to crack them for us.  We point it to rockyou and now we have usernames and passwords.  

Maybe you're thinking I'm going after an application that's sole purpose is to be vulnerable.  You're correct but only because it's vulnerable on multiple fronts, not because newer, more secure products, aren't vulnerable.  This is a current stock WordPress install.  




Sidebar:  I like to know multiple products for the same vector.  Hydra is pretty awesome but sometimes your "go to" product doesn't work for whatever reason which is why we need more than one.  For web fuzzing, you'll see me use dirbuster, dirb, wfuzz, nikto, and gobuster -- to name a few.  Each has their advantages and disadvantages.  And sometimes one or more of them will just flat out break for the given situation.

While writing this up, I've been playing around with patator.  

From the author:  "Patator was written out of frustration from using Hydra, Medusa, Ncrack, Metasploit modules and Nmap NSE scripts for password guessing attacks.  I opted for a different approach in order to not create yet another brute-forcing tool and avoid repeating the same shortcomings."

So far, I'm unable to get it to work like I can get hydra to work.  

patator http_fuzz url=http://192.168.90.34/wp-login.php method=POST body='log=admin&pwd=FILE0' 0=/usr/share/wordlists/top1000.txt
accept_cookie=1 follow=1 -x ignore:fgrep='Invalid username'


Basically, we're doing the same thing as we're doing with hydra except that it's not ignoring the "Invalid username" response from WordPress:




Now that being said, take note of two things:

First, the size changes from all of the other invalid passwords.  Second, the column, num which stands for the position of that password in the file.  The response took longer which is why it's showing up further down in the order even though it's 7th in the password list.  So while not the greatest tool, we could output this to a file and find a correct response if one exists.

Double checking my theory, I change the password for WordPress and I run patator again:




Same deal.  Size changes and we're out of order.  

Perhaps I just haven't found the correct syntax to get this to work like I would like.  I'll keep playing with it.  But for now, I have another tool for performing the same task.  

Circling back to what works, we go after WordPress with Hydra without a hitch:




Maybe you think your WordPress site is safe but out of the box, a stock WordPress site is just as vulnerable to brute force attacks as the intentionally vulnerable site from above.

We manage and host a number of WordPress sites and the first step in preventing a successful brute force attack is to add in multi-factor authentication.  For some sites, we might use Duo which is pretty awesome, honestly.  Upon successful login, you're presented with the following:




At this point, you select "Send Me a Push" and the screen changes:






Meanwhile, there's a phone notification:





Pretty simple application and an excellent layer of protection.  Not the only one but a good first step.