Should We Call it Quits for Passwords? Or, "Password Spraying for the Win!"
Last Updated: 2018-02-21 15:01:12 UTC
by Rob VandenBrink (Version: 1)
Ok, maybe that's a bit dramatic. But for most companies with web services, the answer is a serious "yes" for ditching passwords for those services. Why is that? Let's talk about how the typical external pentest might go.
After a quick scan of the customer's perimeter, usually we'll find a web server, somethink like an intranet, a Sharepoint server, something for folks to record their billable hours that day, something. If you don't find that, there's always a mail server with a web interface - either on that perimeter or in the cloud (Office 365 for instance). That being said, one or more of those servers will use a userid and password for authentication, and those credentials will almost always be sync'd up to an internal directory, usuall Active Directory.
So how do you go about attacking something like that? In most cases there is a "3 or 5 strikes and you're out" password lockout policy in play. If you are in a Penetration Test engagement, you definitely, absolutely don't want to be the person that locked out the entire company. So where do we go next? The answer of course is LinkedIn.
Normally we call this step Reconnaissance, "Open Source Intelligence", or OSINT for short. In penetration testing most organizations though, we can shorten this to just LinkedIn (for this step of the pentest anyway). What we need to start with is a list of folks who work in the organization, and where better to start than at that site? You can certainly use LinkedIn's API to simply query the site for a list of folks who work there - ReconNG does a good job of this (a tutorial is here: https://www.codemetrix.net/practical-osint-recon-ng/). However, whenever I try this I tend to find that LinkedIn has changed their API enough that my last code snip isn't re-usable anymore. Google will give you a decent list here, and Google always works - google for:
"Company Name Here" Profile site:linkedin.com
In most medium to large organizations, this will give you hundreds of pages of returns, more data than you want and more importantly in a format that's less than useful.
SearchDiggity (https://www.bishopfox.com/resources/tools/google-hacking-diggity/attack-tools/) will dump a "just the facts" result set for you, in a text format that you can parse out using grep, sed, awk or even Excel in a pinch.
Now that you have names, you want to convert them to userids - for most companies you want to convert "John Doe" to "jdoe" or "firstname.lastname@example.org" (or both). Note that some companies might truncate usernames, or have a different naming policy (doe.j, j.doe or maybe something else entirely) - if you can get that naming policy that will really save you some time in this step. It's worth looking at any corporate websites you might find, quite often you'll find that policy posted publically. Because information like that should be "free and open" says lots of HR departments (but no infosec person ever!)
What next? Now you are set for your password spray. You've got one or more target websites, and a list of userids. For passwords, you'll need a short-ish list of passwords, maybe a couple of hundred or two to start with. Googling for "worst passwords on the internet" is a good start. Add a few local sports teams, university sports teams, also add the perennial "Season" passwords (counting back). Let's see, it's the winter of 2018, so let's go with "Winter2018", Fall2017, Autumn2017, Summer2017. Do the same for months, starting again from Feb2018 and February2018. If there's a favourite restaurant, beer or food that people in the organization might have mentioned (you should ask), get that in your list too! Tools like CEWL can be also used to harvest organization-specific words from the corporate websites - things like internal contest names, the words margin, target or profit (in a sales driven company) and so on. The goal here is to collect obvious and obviously bad passwords - we'll get into why in a minute
Now run your list through something like hashcat's mask processor - you want to take that list, and duplicate it with things like "!" "!!" and "?" at the end of each word. Also create duplicates with the easy leet-speak substitutions (zero's for o's, "@" for a and so on), in different combinations. This is an important step, as most organizations will have a password policy that requires "special characters". However, keep in mind that you don't want an exhaustive list here, you want a list that's "good enough", that follows along with what a normal person would choose for. So don't go crazy with the special characters - folks usually end a word with an exclamation point, maybe add a number (quite often based on the month or year), and call it done - that's what you want in this list.
Now, we use a tool or program to take each password and try each user against that password, in turn. This approach is called a "Password Spray", the goal of this approach is to NOT trigger the "three failed attempts in 5 minutes locks the account" rule. With a decent user list and an OK password list, a password spray will generally take 5 minutes or so to cycle through 3 passwords. Just to be sure, add a "time elapsed" timer and a delay to the loop in your code.
You usually don't need to write code for this - tools like Hydra, Medusa or Patator are written exactly for this task. Burp can also be used if it's a more complex web interface. Tools like mailsniper are written specifically for OWA and EWS (Exchange Web Services). Some of these tools won't have that "wait" timer that you need - you can fake that by adding some dummy passwords to the list, or by using a simple CMD or Bash script around these tools.
In my last pentest I really wanted to write some code to do this for OWA (that code is here: https://github.com/robvandenbrink/owaspray). It's inefficient, but that's OK in this case, it still beat the "5 minute" limit for the client I was working with, so I did end up using the loop delay. You can mount this style of attack against websites, exposed RDP, telnet or SSH services, really anything that will take a userid/password. Be smart about picking your target though - Outlook Web Access will for instance be much more likely to be linked to Active Directory (or whatever the internal authentication source is) than an exposed router or switch might be.
If you want a faster piece of code to run against Exchange, look at the post on attacking the Exchange Web Services API on the BHIS site (https://www.blackhillsinfosec.com/introducing-mailsniper-a-tool-for-searching-every-users-email-for-sensitive-data/ and https://www.blackhillsinfosec.com/attacking-exchange-with-mailsniper/). The Web Services are WAY faster than the native HTTPS interface to Exchange.
The result? You will ALWAYS find valid credentials with this approach. You will ALMOST ALWAYS see that at least one of the credentials you find this way will get you Domain Administrator access to Active Directory.
So, after all that, aside from breaking in, what is the point of this exercise? What point are we making to our customer that has us running a penetration test against their infrastructure? The point you are making to your customer is that exposing AD userids and passwords to the internet is a TRULY BAD IDEA. Especially since in your penetration test you took the credentials you just gained and used them in the next step of your attack - which usually nets you even more domain credentials. If you are REALLY trying to make this point, try running your attack only with the passwords based on seasons and months!
Recommendations? Really there are two recommendations that come out of this. The main one of course is to use Two Factor or Multifactor Authentication. With a 2FA/MFA solution in place, it's much (much) more difficult to gain access. If you are looking at a new MFA solution, be sure that it doesn't use SMS - that seems to be a nice target this year!
Be sure to use MFA on everything that faces the internet! If you add MFA to your VPN service but leave your intranet or CRM running with userids and passwords, you've done half the job, and in some cases the service that was left with password authentication might not implement password lockout (yup, I have seen that in recent memory)
Another recommendation might be to use passphrases instead of passwords - getting those first factor passwords up above 15-20 characters makes this much more difficult. However, it doesn't make this impossible, not by a long shot - especially if $companyname or $firstname+$lastname length is be above 15 characters (as mine is :-) ) This is more a recommendation that should come out of the internal pentest than the external one (stay tuned).
Tools Referenced (many of these are pre-packaged on Kali Linux):
Hashcat maskprocessor: https://hashcat.net/wiki/doku.php?id=maskprocessor