Today I will show you how to set up simple bruteforce monitoring with Graylog.

The idea here is that an attacker logs in incorrectly several times before a correct logon occurs (the bruteforce attempt has succeeded).

The idea here is that an attacker logs in incorrectly several times before a correct logon occurs (the bruteforce attempt has succeeded).

The same approach works for RDP logins. Please keep in mind that the bruteforce check only makes sense for logins from outside the intranet.

I assume that logs are already aggregated. If not, you can have a look at my little howto.

Without much blah-blah, let's get down to business.

Create a new stream

Login to Graylog web and create a new stream called "SSH Logins". Apply the following rule to this stream:

application_name must match exactly sshd

Optionally: Check option "Remove matches from ‘All messages’ stream"

Graylog: Remote machtes from 'All messages' sream

Create a new pipeline

Go to System/Pipelines and add a new pipeline "SSH Bruteforce check"

Add the stream "SSH Logins" as connection for the pipeline.

Setup two new pipeline rules:

The first one checks for invalid SSH entries:

rule "check invalid user ssh logins"
when
	has_field("message")
then
	let message_field = to_string($message.message);
    let loginActions = grok(pattern:"%{WORD:successorfailed} password%{GREEDYDATA} user %{WORD:userssh} from %{IP:sourceipssh}", value:message_field, only_named_captures:true);
    set_fields(loginActions);
    debug(loginActions);
end

The second checks for valid unauthorized logins:

rule "check valid failed user ssh logins"
when
	has_field("message")
then
	let message_field = to_string($message.message);
    let loginActions = grok(pattern:"%{WORD:successorfailed} password%{GREEDYDATA} for %{WORD:userssh} from %{IP:sourceipssh}", value:message_field, only_named_captures:true);
    set_fields(loginActions);
    debug(loginActions);
end

Add both rules to the pipeline in Stage 0.

For explanation: Rule 1 checks for entries with an incorrect user name. Rule 2 checks for incorrect passwords. Both rules set the variable "successorfailed" to true or false.  Both rules store the IP and username in a new field.

Create a new alert/event

Go to "Alerts & Events".

Add a new event definition "SSH Bruteforce".
Select your newly created "SSH logins" as input stream.

Search within last 1 hour and execute search every 1 hour.
Create Events for Definition if Aggregation of results reaches a threshold.
Group by Field(s) userssh, sourceipssh, source
Create Events for Definition: card() of successorfailed = 2

card() is the cardinality.

If that's unclear, take a look at the image below:

Graylog Filter & Aggregation SSH Bruteforce

Click on next and create an create 3 key fields:

"${source.source}"require_values: false${source.source}
"${source.sourceipssh}"require_values: false
"${source.userssh}"require_values: false

Pictures say more than words:

Graylog event fields SSH bruteforce

Depending on how you need it at the moment, set up the notification (email, webhook, etc.)

In the end, it should look like this.

Graylog event summary SSH bruteforce

How does it work?

The pipeline stores the source IP, username and machine.

There are three scenarios:

1.) An attacker tries username through and is always saved as failed login. This is not observed further. However, the attempt is extracted and stored and can be easily researched via search (sourceipssh: AND userssh:root).

2.) An attacker tries to crack the password with a valid username udn is not successful. In this case, no alarm is raised because the attacker does not manage to break into the system.

3.) An attacker is successful. This means that within the past time there was a change from "fail" to "success" with the same IP and username. Here the alarm is raised.