×
CrowdSec is a proud participant in the Microsoft Copilot for Security Partner Private Preview
Read more
detect successful ssh brute force
Tutorial

Detecting Successful SSH Brute Force

CrowdSec Security Engine 1.5 in Action — Part I

Last month we announced the release of the CrowdSec Security Engine 1.5 — our biggest release since v1.0! Version 1.5 came packed with new features, and major enhancements, and offers more control over your security management. 

In this blog series, I want to walk you through some of the most interesting features and explore a few use cases. In the first installment, I will explore the new capability to detect multiple-step behaviors in a single scenario using the example of a successful SSH brute force attack. 

Requirements

Setup the acquisition (optional)
The CrowdSec Security runs in two modes — the service mode and the replay mode. In service mode (aka the default mode), the Security Engine monitors live logs while in replay mode you can run the Security Engine against a specified log file. The replay mode is mostly used when you want to test a parser or a scenario, or when you want to detect false positives.

The acquisition configuration defines which stream of information the Security Engine must process (log file path, S3 bucket, CloudWatch log stream, etc.). this is what the acquis.yaml would look like to monitor SSH logs in service mode.


#/etc/crowdsec/acquis.yaml
---
Filenames:
- /var/log/auth.log
Labels:
type: syslog
---

Install the SSHD collection

You can find the collection here.

sudo cscli collections install crowdsecurity/sshd

Parse successful authentication

To detect a successful brute force attack, CrowdSec needs to parse a successful authentication log. You can refer to this documentation article to understand how to write a parser. We can do this by adding this node in the crowdsecurity/sshd-logs parser:


#/etc/crowdsec/parsers/s01-parse/sshd-logs.yaml
---
- grok:
      pattern: 'Accepted password for %{USERNAME:sshd_valid_user} from %{IP_WORKAROUND:sshd_client_ip} port \d+'
      apply_on: message
      statics:
        - meta: log_type
          value: ssh_success-auth
        - meta: target_user
          expression: "evt.Parsed.sshd_valid_user"

Note: This may not cover all the SSH successful authentication messages.

The scenario

For this use case I am using the new type of scenario conditional

With this type of scenario, it is possible to access previous events that were poured into the bucket and determine where they sit on the timeline — i.e. which event happened when. Find more info about the conditional scenario here

To detect a successful brute force attack, we must check that our bucket contains at least five failed authentication logs and one successful authentication log.

Here is the condition that we will use for our conditional bucket:

condition: |
  count(queue.Queue, #.Meta.log_type == 'ssh_failed-auth') > 5 and count(queue.Queue, #.Meta.log_type == 'ssh_success-auth') > 0

This checks that the buckets contain at least five failed authentication logs and one successful authentication log.

And here is the full scenario that detects successful SSH brute force:


#/etc/crowdsec/scenarios/successful-ssh-bf.yaml
---
type: conditional
name: crowdsecurity/successful-ssh-bf
description: "Detect successful ssh bruteforce"
filter: "evt.Meta.service == 'ssh'"
leakspeed: "10s"
cache_size: 15
capacity: -1
condition: |
  count(queue.Queue, #.Meta.log_type == 'ssh_failed-auth') > 5 and count(queue.Queue, #.Meta.log_type == 'ssh_success-auth') > 0
groupby: evt.Meta.source_ip
blackhole: 1m
labels:
  remediation: true

Test with CrowdSec replay mode

To check that everything works properly, we can now test this scenario with the CrowdSec replay mode.

Here are some logs that represent a successful brute force:


#ssh_bf.log
---
Apr 11 15:53:50 myvps sshd[834901]: Failed password for root from 1.2.3.4 port 1042 ssh2
Apr 11 15:53:51 myvps sshd[834901]: Failed password for root from 1.2.3.4 port 1042 ssh2
Apr 11 15:53:51 myvps sshd[834901]: Failed password for root from 1.2.3.4 port 1042 ssh2
Apr 11 15:53:52 myvps sshd[835121]: Failed password for root from 1.2.3.4 port 1042 ssh2
Apr 11 15:53:53 myvps sshd[835121]: Failed password for root from 1.2.3.4 port 1042 ssh2
Apr 11 15:53:54 myvps sshd[835121]: Failed password for root from 1.2.3.4 port 1042 ssh2
Apr 11 15:53:54 myvps sshd[835241]: Accepted password for root from 1.2.3.4 port 1042 ssh2

We can run the CrowdSec Replay mode with the following command:

$ sudo crowdsec -dsn file://ssh_bf.log -type syslog -no-api
INFO[11-04-2023 19:23:41] single file mode : log_media=stdout daemonize=false 
INFO[11-04-2023 19:23:41] Enabled feature flags: none                
INFO[11-04-2023 19:23:41] Crowdsec v1.5.0-rc3-6-g169b8442-linux-169b84421227a4a2cab1c680863df958862bc615 
WARN[11-04-2023 19:23:41] MaxOpenConns is 0, defaulting to 100         
INFO[11-04-2023 19:23:41] Loading prometheus collectors                
WARN[11-04-2023 19:23:41] Exprhelpers loaded without database client.  
INFO[11-04-2023 19:23:41] Loading grok library /etc/crowdsec/patterns  
INFO[11-04-2023 19:23:41] Loading enrich plugins                       
INFO[11-04-2023 19:23:41] Successfully registered enricher 'GeoIpCity' 
INFO[11-04-2023 19:23:41] Successfully registered enricher 'GeoIpASN'  
INFO[11-04-2023 19:23:41] Successfully registered enricher 'IpToRange' 
INFO[11-04-2023 19:23:41] Successfully registered enricher 'reverse_dns' 
INFO[11-04-2023 19:23:41] Successfully registered enricher 'ParseDate' 
INFO[11-04-2023 19:23:41] Successfully registered enricher 'UnmarshalJSON' 
INFO[11-04-2023 19:23:41] Loading parsers from 5 files                 
INFO[11-04-2023 19:23:41] Loaded 2 parser nodes                         file=/etc/crowdsec/parsers/s00-raw/syslog-logs.yaml stage=s00-raw
INFO[11-04-2023 19:23:41] Loaded 1 parser nodes                         file=/etc/crowdsec/parsers/s01-parse/sshd-logs.yaml stage=s01-parse
INFO[11-04-2023 19:23:41] Loaded 1 parser nodes                         file=/etc/crowdsec/parsers/s02-enrich/dateparse-enrich.yaml stage=s02-enrich
INFO[11-04-2023 19:23:41] Loaded 1 parser nodes                         file=/etc/crowdsec/parsers/s02-enrich/geoip-enrich.yaml stage=s02-enrich
INFO[11-04-2023 19:23:41] Loaded 1 parser nodes                         file=/etc/crowdsec/parsers/s02-enrich/whitelists.yaml stage=s02-enrich
INFO[11-04-2023 19:23:41] Loaded 6 nodes from 3 stages                 
INFO[11-04-2023 19:23:41] No postoverflow parsers to load              
INFO[11-04-2023 19:23:41] Loading 1 scenario files                     
INFO[11-04-2023 19:23:41] Adding conditional bucket                     cfg=proud-resonance file=/etc/crowdsec/scenarios/successfull-ssh-bf.yaml name=crowdsecurity/successful-ssh-bf
WARN[11-04-2023 19:23:41] Loaded 1 scenarios                           
INFO[11-04-2023 19:23:41] Adding file ssh_bf.log to filelist            type="file://ssh_bf.log"
INFO[11-04-2023 19:23:41] Starting processing data                     
INFO[11-04-2023 19:23:41] reading ssh_bf.log at once                    type="file://ssh_bf.log"
WARN[11-04-2023 19:23:41] prometheus: listen tcp 127.0.0.1:6060: bind: address already in use 
WARN[11-04-2023 19:23:41] Acquisition is finished, shutting down       
INFO[11-04-2023 19:23:42] Ip 1.2.3.4 performed 'crowdsecurity/successful-ssh-bf' (7 events over 1h29m51.947340934s) at 2023-04-11 15:53:54 +0000 UTC 
INFO[11-04-2023 19:23:42] Killing parser routines                      
INFO[11-04-2023 19:23:43] Bucket routine exiting                       
INFO[11-04-2023 19:23:44] crowdsec shutdown

And there you have it — CrowdSec detected the successful brute force!

Demo

Now it is time to check if our new scenario works in real-time. For this demo, I will use Hydra to perform the brute force and I will target the user demo using a server that I own.

Note: Before we get started with this step, please make sure to restart the Security Engine since we have edited some parsers and scenarios and added context to alerts.

Once you restart the Security Engine, run Hydra.

$ hydra -l demo -P pass.txt DEMO_IP ssh -t 4
Hydra v9.2 (c) 2021 by van Hauser/THC & David Maciejak - Please do not use in military or secret service organizations, or for illegal purposes (this is non-binding, these *** ignore laws and ethics anyway).

Hydra (https://github.com/vanhauser-thc/thc-hydra) starting at 2023-04-25 15:04:44
[DATA] max 4 tasks per 1 server, overall 4 tasks, 9 login tries (l:1/p:9), ~3 tries per task
[DATA] attacking ssh://DEMO_IP:22/
[22][ssh] host: DEMO_IP   login: demo   password: Password123
1 of 1 target successfully completed, 1 valid password found

We managed to find the password of the demo user, and we can see in the Security Engine logs that the scenario has been triggered:

time="25-04-2023 13:04:49" level=info msg="Ip demo_ip performed 'crowdsecurity/successful-ssh-bf' (10 events over 5.015762151s) at 2023-04-25 13:04:49.671649049 +0000 UTC"
time="25-04-2023 13:04:49" level=info msg="(ff7bfc7d3d8043188b90b8ca80edd29cEo2BtePh5aKyvESP/crowdsec) crowdsecurity/successful-ssh-bf by ip demo_ip (FR/5410) : 4h ban on Ip demo_ip"

Conclusion

As we saw in this article, the conditional bucket feature introduced in CrowdSec Security Engine 1.5 helps you detect more advanced behaviors. Check out part II of this series where I’ll show you how to use the same feature to detect the impossible travel behavior (same account connecting from two different countries within a short timeframe). 

No items found.