Detecting Suspicious IP Behavior and Impossible Travel

 




In this installment, we’ll demonstrate how you can leverage the same feature to detect impossible travel — aka an account connecting from two different locations, far from each other, in a short amount of time.

We will use the SSHD service again as an example for this article, but this feature can be used for any service logging authentication.

Requirements

Setup the acquisition (optional)

Same as in part one, in this article,we running the CrowdSec Security Engine in replay mode. If you want to use service mode, you need to set up the acquisition.


#/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

As already seen in part one, this is the parser node to parse successful SSH authentication:


#/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"
          

Enrich event with IP geolocation

To detect that an account connected from two different locations in a short amount of time, we need information on the geolocation of the source IP address.

We can get this info by installing the geoip-enrich parser.


sudo cscli parsers install crowdsecurity/geoip-enrich

Note: You can skip this step if you have already installed this parser.

The scenario

Now we need to check that the IPs filled in our buckets are more than 1000km away from each other.

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


condition: |
  len(queue.Queue) >= 2 
  and Distance(queue.Queue[-1].Enriched.Latitude, queue.Queue[-1].Enriched.Longitude,
  queue.Queue[-2].Enriched.Latitude, queue.Queue[-2].Enriched.Longitude) > 1000
  

This condition checks that the buckets contain at least two events and that the distance between the IPs in those events is more than 1000km away. We can achieve that using the Distance() helper, which uses the Haversine formula to determine the distance between two points with their longitude and latitude.

Here is the full scenario that detects an account connecting from more than 1000km away since its last connection in 4 hours:


#/etc/crowdsec/scenarios/impossible-travel.yaml
---
type: conditional
name: crowdsecurity/impossible-travel
description: "Detect impossible travel"
filter: "evt.Meta.log_type == 'ssh_success-auth'"
leakspeed: "4h"
distinct: evt.Meta.source_ip
capacity: -1
condition: |
  len(queue.Queue) >= 2 
  and Distance(queue.Queue[-1].Enriched.Latitude, queue.Queue[-1].Enriched.Longitude,
  queue.Queue[-2].Enriched.Latitude, queue.Queue[-2].Enriched.Longitude) > 1000
groupby: evt.Meta.target_user
blackhole: 1m
labels:
  service: ssh
  type: bruteforce
  remediation: true
scope:
  type: user
  expression: evt.Meta.target_user
  

To make this scenario work, we must group the events by targeted user and only look at distinct IP addresses in the bucket.

Note: we set user as the scope for this scenario. If your profile configuration generates a decision only for alert with scope IP, triggering this scenario will not lead to any decision.  

Bonus: Add context to the alert

With this scenario, the CrowdSec Security Engine will only log the user targeted by the attack. But it is also interesting to know from which IPs and countries the user logged in. To do that, I will use the new CrowdSec feature, called Alert Context. See more about this feature here.

To add the source IP addresses and the source countries, we need to run the following commands:


sudo cscli lapi context add --key source_ip --value evt.Meta.source_ip
sudo cscli lapi context add --key country --value evt.Enriched.IsoCode

When you inspect an alert, you will be able to see all the source IPs and countries that have been poured into the bucket. 

 Test with CrowdSec replay mode

We can test this scenario with the CrowdSec replay mode to ensure everything works properly.

Here are some logs that represent two successful authentications from two different IPs, in 2 different countries, and in 2 hours intervals:


#ssh_auth.log
---
Apr 11 15:53:54 myvps sshd[835241]: Accepted password for root from 1.2.3.4 port 1042 ssh2
Apr 11 17:53:54 myvps sshd[835241]: Accepted password for root from 8.8.8.8 port 1042 ssh2

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


#$ sudo crowdsec -dsn file://ssh_auth.log -type syslog -no-api
---
INFO[14-04-2023 18:14:24] single file mode : log_media=stdout daemonize=false 
INFO[14-04-2023 18:14:24] Enabled feature flags: [none]                
INFO[14-04-2023 18:14:24] Crowdsec v1.5.0-rc3-6-g169b8442-linux-169b84421227a4a2cab1c680863df958862bc615 
WARN[14-04-2023 18:14:24] MaxOpenConns is 0, defaulting to 100         
INFO[14-04-2023 18:14:24] Loading prometheus collectors                
WARN[14-04-2023 18:14:24] Exprhelpers loaded without database client.  
INFO[14-04-2023 18:14:24] Loading grok library /etc/crowdsec/patterns  
INFO[14-04-2023 18:14:25] Loading enrich plugins                       
INFO[14-04-2023 18:14:25] Successfully registered enricher 'GeoIpCity' 
INFO[14-04-2023 18:14:25] Successfully registered enricher 'GeoIpASN'  
INFO[14-04-2023 18:14:25] Successfully registered enricher 'IpToRange' 
INFO[14-04-2023 18:14:25] Successfully registered enricher 'reverse_dns' 
INFO[14-04-2023 18:14:25] Successfully registered enricher 'ParseDate' 
INFO[14-04-2023 18:14:25] Successfully registered enricher 'UnmarshalJSON' 
INFO[14-04-2023 18:14:25] Loading parsers from 5 files                 
INFO[14-04-2023 18:14:25] Loaded 2 parser nodes                         file=/etc/crowdsec/parsers/s00-raw/syslog-logs.yaml stage=s00-raw
INFO[14-04-2023 18:14:25] Loaded 1 parser nodes                         file=/etc/crowdsec/parsers/s01-parse/sshd-logs.yaml stage=s01-parse
INFO[14-04-2023 18:14:25] Loaded 1 parser nodes                         file=/etc/crowdsec/parsers/s02-enrich/dateparse-enrich.yaml stage=s02-enrich
INFO[14-04-2023 18:14:25] Loaded 1 parser nodes

Tada! The impossible travel from the user root has been detected by CrowdSec!

 

 Reference link

A.K

Comments

Popular posts from this blog

CISA and ENISA enhance their Cooperation

Top Five Most Exploited Vulnerabilities in January 2024

SmartScreen Vulnerability: CVE-2024-21412 Facts and Fixes