Which country is trying to illegally access my server via SSH!

8 min

language: ja bn en es hi pt ru zh-cn zh-tw

Hello, I'm Incompetent. I'm publicly exposing my Vultr FreeBSD server, and I was curious about who exactly is trying to attempt SSH connections, so I'm looking into it. By the way, in the case of FreeBSD, it delivers a "security run output" to my domain, informing me of any attempts. image Like this. So, let's use geoip to peek at which countries' global IP addresses these people attempting connections are from. By the way, the geoiplookup command can be installed as follows:

sudo pacman -S geoip  
  

This is the command:

$ geoiplookup IP_address  
GeoIP Country Edition: RU, Russian Federation  
  

Text Formatting with Bash

First, let's bring the original "security run output" string to my ThinkPad (any way is fine) and then format it.

cat vultr | grep -oP "from.*port" | awk '{print $(NF-1)}' | sort | uniq > grepip  
  

In the above case, from the 'security run output' description named 'vultr', we extract descriptions containing 'from' up to 'port' using grep -o for matching values and -P for Perl regular expressions.
It will look something like the following string:

from IP_address port  
  

The reason I didn't use awk at this point is that if spaces were used as delimiters, the error output would change depending on whether the password was incorrect or if the target user didn't exist on my server, so I extracted the string from 'from' to 'port' to capture everything. Next, I use awk to extract only the IP address from the last record, remove duplicate IPs with sort and uniq, and then write it to a file named grepip. Then, let's have bash perform geoiplookup on these IPs and do a quick count by country.

$ cat country.sh  
#!/bin/bash  
  
# File of IP addresses  
INPUT="grepip"  
  
# Output file  
OUTPUT="countries.log"  
  
# Initialization  
> $OUTPUT  
  
# Execute geoiplookup for each IP address and get country information  
while IFS= read -r ip; do  
    geoiplookup "$ip" | awk -F: '{print $2}' >> $OUTPUT  
done < "$INPUT"  
  
# Aggregate and display country information  
sort $OUTPUT | uniq -c | sort -tr  
  

Now, grant execution permission.

chmod +x ./country.sh  
  

Just execute it now:

$ ./country.sh  
      1  BE, Belgium  
      1  BG, Bulgaria  
      1  BR, Brazil  
      1  CH, Switzerland  
      1  HK, Hong Kong  
      1  HU, Hungary  
      1  IR, Iran, Islamic Republic of  
      1  IT, Italy  
      1  LT, Lithuania  
      1  MT, Malta  
      1  MX, Mexico  
      1  MY, Malaysia  
      1  NO, Norway  
      1  PA, Panama  
      1  PE, Peru  
      1  SE, Sweden  
      1  SK, Slovakia  
      1  TH, Thailand  
      1  TM, Turkmenistan  
      1  TZ, Tanzania, United Republic of  
      1  UZ, Uzbekistan  
      1  ZA, South Africa  
      2  RO, Romania  
      2  UA, Ukraine  
      3  PL, Poland  
      6  GB, United Kingdom  
      7  VN, Vietnam  
      8  CA, Canada  
      8  ID, Indonesia  
      9  RU, Russian Federation  
      9  SG, Singapore  
     10  FR, France  
     10  KR, Korea, Republic of  
     11  DE, Germany  
     11  NL, Netherlands  
     16  CN, China  
     18  IN, India  
     43  US, United States  
  

Hmm, I see...

Displaying Charts Clearly with Matplotlib

Well, it's understandable as text, but it becomes hard to read when the number is large, so we want to display it as a chart, right?
Also, if it's scripted, it can be generated as a cron job. Therefore, we will display charts using Matplotlib, a convenient Python library. Installation and code:

pip install matplotlib  
  
cat AreYouFrom.py  
#!/usr/bin/python3  
  
import matplotlib.pyplot as plt  
import collections  
  
# Read the file and aggregate access counts by country  
country_counts = collections.Counter()  
  
with open('countries.txt', 'r') as file:  
    for line in file:  
        # Get country information  
        country = line.strip().split(",")[1]  
        country_counts[country] += 1  
  
# Sort the data  
countries, counts = zip(*country_counts.most_common())  
  
# Create the graph  
plt.figure(figsize=(10, 6))  
plt.bar(countries, counts, color='skyblue')  
plt.xlabel('Country')  
plt.ylabel('Accesses')  
plt.title('Accesses by Country')  
plt.xticks(rotation=90)  
plt.tight_layout()  
  
# Output as a PNG image file  
plt.savefig('accesses.png')  
  

This allows chart output and image output.

chmod +x AreYouFrom.py  
  

(What a filename, sounds like middle school English!)

image

Ta-da! It seems the most attempts are from the United States.

Aggregating by Port Being Attempted for SSH

Now, let's investigate by the port being attempted for access.
With this, I was able to grep only the ports.

cat vultr | grep -oP "port [123456789].*ssh2$" | grep -oP "[123456789].* "  
  

Output this as ports.txt.
However, since all port numbers are different, let's separate them into blocks for plot output.

$ cat AreYouPort.py  
#!/usr/bin/python3  
import matplotlib.pyplot as plt  
from collections import Counter  
  
# Read port numbers from file  
with open('ports.txt', 'r') as file:  
    ports = [int(line.strip()) for line in file]  
  
# Calculate frequency distribution of port numbers  
counter = Counter(ports)  
  
blocks = {}  
for port, count in counter.items():  
    block = (port // 10000) * 10000  
    if block not in blocks:  
        blocks[block] = 0  
    blocks[block] += count  
  
# Create the graph  
x = list(blocks.keys())  
y = list(blocks.values())  
  
plt.figure(figsize=(12, 6))  
plt.bar(x, y, width=6000, color='skyblue', edgecolor='black')  
plt.xlabel('Port Number')  
plt.ylabel('Frequency')  
plt.title('Port Numbers by Frequency')  
plt.xticks(x, [f'{i}-{i+9999}' for i in x], rotation=45)  
plt.grid(True, axis='y', linestyle='--', alpha=0.7)  
plt.tight_layout()  
  
# Save to PNG file  
plt.savefig('port_numbers.png')  
  

And then... image
Why are there so many attempts on unlikely port numbers with values over 30,000...? Well, that's all for today. See you next time.

Related Posts