Internal network password spraying is something I’ve always approached with a lot of caution.
If not done correctly, you have the potential for:
- Exorbitant network activity and alerts
- Compromised ability for employees to do their job
- And most of all, locked out accounts (scary)
Talon, written by the extremely talented Tylous, is a really cool tool that helps eliminate some of the blind spots encountered when spraying Active Directory services on an internal network engagement. When combined with the treasure-trove that is LinkedIn, it makes for a really great experience during testing.
Talon is especially great because it:
- Is written in Go
- Supports Kerberos and LDAPS
- Is highly flexible
- Rotates traffic between targets
- Can enumerate if users exist without locking them out
Check out the associated blog post for more info on how it works and all the hard work put into it.
Let’s Get a User List
We’ll assume we’ve been dropped on a network with little to no knowledge and we need a list of employee accounts that we can password spray.
I like to use linkedin2username by initstring, which scrapes all the employees attached to an organization’s LinkedIn page to collect information. This information comes in the form of neatly structured lists of employee names in a couple different permutations. For example, if
John Doe works at a target company I’ll get a listing of him (and all his coworkers) in the format of
johnd, and so on.
To begin, grab the company name from the target company’s LinkedIn profile page. It should look something like
https://linkedin.com/company/contoso12345/. That last bit (
contoso12345) is what we’re looking for.
Next, clone a fresh copy of linkedin2username and scrape the company’s page:
git clone https://github.com/initstring/linkedin2username cd linkedin2username ## Note <username> is your LinkedIn username python3 linkedin2username.py -u <username> -c <company> ## Output is here cd li2u-output
Here’s me running the tool on our target
The complete output will produce a couple lists in different formats that we can use internally.
So, full disclosure, LinkedIn is weird. I had issues running this from a host I usually don’t access LinkedIn on, and you might experience a series of different errors using the tool. You’re ultimately at the mercy of how LinkedIn governs its platform.
I wouldn’t expect a given enumeration tool to work for an extensive period, so it’s probably a good idea to keep tabs on tooling as it’s released and things change.
One can always use alternate toolsets to achieve the same result. This may require some bash magic to get things in the correct format, which is why I currently prefer linkedin2username. Here are some additional tools to look at:
Now I’ll typically grab my generated user lists and begin enumeration with Talon.
Talon will take a list of users and do two things:
- Enumerate if they exist
- Perform a password spray
I added some additional logic that allows a list of passwords to be specified along with some timing controls I’ll explain later. That way you can setup the tool and let it go, making sure to periodically check back between cycles, thus protecting your precious fingers from the strain of strenuously running a spray one-by-one.
You can grab my forked version here. Almost all of the functionality overlaps (I’ll tell you when it doesn’t).
Update: My changes have been merged into the master version of Talon.
To install Talon, perform the following (with Go already installed):
git clone https://github.com/Optiv/Talon cd Talon ## Install Dependencies go get github.com/fatih/color go get gopkg.in/jcmturner/gokrb5.v7/client go get gopkg.in/jcmturner/gokrb5.v7/config go get gopkg.in/jcmturner/gokrb5.v7/iana/etypeID go get gopkg.in/ldap.v2 ## Build go build Talon.go
Talon’s functionality includes the ability to specify multiple domain controllers to target for enumeration. This will distribute any generated alerts between hosts. You can control this via the
-Hostfile argument, which takes a file containing a newline-delimited list of hosts as an argument.
How you get this information is up to you, and will likely vary, but a good place to start is by enumerating hosts using CrackMapExec and looking for hostnames containing
crackmapexec smb <targets> >> crackmapexec_enum.txt
For our purposes I’ve setup the following users in my lab:
Let’s say that these users are somewhere within our linkedin2username output, along with some other false entries. We will take our list of target domain controllers, and begin detecting valid users:
./Talon -E -D <domain> -Userfile <username_file> -Hostfile <DC_list> -O <output_file> -sleep 1
Note: I would heavily recommend always running Talon with an output file specified with the
In my lab this looks like the following:
As you can see it detected the valid users from our listing. We can generate a new list of valid users with the following bash command:
grep "User Exist" <output_file> | cut -d '\' -f 2 | cut -d ":" -f 1
With our generated list of valid users, let’s run a single password spray with
./Talon -D <domain> -Userfile <username_file> -Hostfile <DC_list> -O <output_file> -sleep 1 -P 'Password1!'
And in the lab environment:
Each password spraying attempt was successful, as each account used a password of
Note: You can instruct Talon to only utilize Kerberos or LDAPS for enumeration. This can be performed via:
-L for LDAPS
-K for Kerberos
Here are the additional options within Talon to automate this process:
Extra Usage of ./Talon: -A float Authentication attempts per lockout period (default 3) -Lockout float Account lockout period in minutes (default 60) -Passfile string File containing the list of passwords
This allows you to give the tool a list of passwords it will iterate through every defined number of minutes specified by the
-Lockout parameter. You can control the number of authentication attempts made per period of testing via the
-A (attempts) parameter.
So let’s say we have our list of valid users, a password list, and we want to perform three password attempts every 70 minutes. We can now automate the entire process of password spraying through the following:
./Talon -D <domain> -Userfile <username_file> -Passfile <password_file> -A 3 -Lockout 70 -Hostfile <DC_list> -O <output_file> -sleep 1
In my lab:
You’ll notice additional timestamping within the output, as well as a notification of when the next attempt cycle will occur.
As we progressed through a password list, eventually we hit the same password found earlier, and achieved a successful login to the target accounts.
Meanwhile if we look at the logs on the DC we can see a series of 4625: An account failed to log on. events. Not exactly quiet behavior.
It’s recommended to talk about the process of password spraying with whoever you’ll be testing before performing any of this activity. It’s also a good idea to get their password policy from them if they are onboard so you can tailor testing to not lockout anyone/anything out. If password spraying isn’t something your target is comfortable with, you shouldn’t perform it :)
Also huge thanks to Tylous for not only writing the tool but also making it public. It’s really great.