How To Detect Password Spray Attacks
The password spray attack is a nasty variation of the brute force attack, but instead of targeting a single account with multiple passwords, like a traditional brute force attack, it attempts to brute force the user name by attacking multiple user names with a single password. The attacker finds a common password and then sprays it across your environment looking for one user name that it works with. They don’t care who they get, as long as it gives them a toehold in your environment.
For this experiment, I spun up a couple of Ubuntu servers, created a number of accounts on them, and then launched my attack. Unfortunately, one of my fake users really doesn’t like to abide by the corporate password policy and falls victim to the attack. What follows is the investigative phase of incident response and where I simulate trying to figure out if the attacker got into the network.
The first step, of course, is getting the access logs. Those are located at /var/log/auth.log and will show ssh connections. It actually shows a lot more, but for our purposes we’re only concerned with the ssh logs.
For this exercise, all connections were from private IP addresses within the 192.168.1.0/24 network. However, the techniques still apply to public IP addresses too.
So, I started by getting the logs from my two test servers and then I combined them together into a single file for ease of searching and uploaded the file into Gigasheet. While in this example we use a relatively small synthetic log, on a corporate network this could easily be tens of millions of rows of data; perfect for Gigasheet.
As you can see, I only ended up with a single column at first. I decided to use Gigasheet's Split Column function to make searching easier. There are several different delimiters I could split it on, but I thought the easiest here was the first “:” character. Of course if I split on just “:” then I’d split in other areas. I didn’t want that so I gave the function button “]:” as the delimiter to split on.
Column A now still existed, but it was split in two as well with some basic information in the one column and details on the right of that. Now I only want to see ssh connections. By applying a filter of “sshd” to the first split off column I removed everything not related to ssh.
This cleans up the data significantly, but how can I find a password spray?
As I mentioned before, a password spray attack uses a single common password against multiple accounts in an organization in hopes that someone will be using it. So, with that knowledge, we can assume that someone carrying out a password spray will have multiple failed logins, but each attempt will be against a single user account at a time. If you search by user account you’ll only see one or two failures for that account per day probably, and that’s normal. Someone will mistype their password and get one or two failures probably, or a user might forget their password or forget that they have caps-lock turned on. Any number of things can cause someone to have a few failures.
I decided to focus on failures first. By adding a filter to the right most column for the word “Failed” I got rid of all the other traffic. This narrowed down my logs to just failures but there were a number of different IPs and the column is still too busy.
So now I split the rightmost column on the word “from” and then again on “port” so that I just got the IP addresses. Then I grouped by IP address and I got a clear image of how many failures came from each IP address.
I could now see one host had the majority of the failures so now I had a suspect to chase. Backing up focused on seeing what this suspect did. I went back to just one split and then filtered on the IP address “192.168.1.31” and the word “Failed” to can see for sure that this was a password spray. There were invalid users showing up which told me that the failures weren’t innocent mistakes. Of course I knew this since I set up the attack but it’s fun to pretend it was a real attack.
I also want to know if the attackers succeeded too (he did but we need to prove it). I looked for the word “Accepted” to see if an account was successfully logged into with this password spray. After looking for this, I saw that our unfortunate user “rando” had apparently used a common password.
So, in summary, we've detected where a password spray came from and we’ve learned that one of our users was compromised. In a real world scenario we would now start looking at all of that user’s activity but that’s beyond the scope of this post.