We are looking at the auth.log file in /var/log/auth.log.
All the login attempts were captured in a time frame of ~3 Hours.
Get all Ips from logfile.
sudo cat /var/log/auth.log | grep "Failed password" | awk -F 'from' '{print $2}' | cut -d" " -f2 > failed-login-ips.txt
cat failed-login-ips.txt | uniq > ips.txtCompare total amount of IPs to uniq number:
cat failed-login-ips.txt | wc -l && cat failed-login-ips.txt | uniq | wc -lExample Output:
5807
4689
The configuration of fail2ban is really simple.
If not already there create a local jail file:
sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.localAdd this to the config file under the SSH section.
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 4
Restart the service.
sudo service fail2ban restartThe problem with Fail2Ban is from 5807 login attempts in 3 hours, 4689 came from unique IPs.
So there was only one login attempt from this IP and our blockade of the IP will not take place.
To solve the problem, we simply change the default port of SSH.
sudo nano /etc/ssh/sshd_configChange Entry
# Port 22
to
Port 1337
Do not use an assigned port!
Restart the Service.
sudo service sshd restart
Script:
#!/bin/bash
cat /var/log/auth.log | grep "Failed password" | awk -F 'from' '{print $2}' | cut -d" " -f2 | \
uniq 2>&1 > /home/vgrimmeisen/log/$(date +%d-%m-%y-%H:%M:%S)_ips.txt
cp /var/log/auth.log /home/vgrimmeisen/log/$(date +%d-%m-%y-%H:%M:%S)_auth.logAdd to crontab to execute one time per day at 3am.
crontab -eInsert
0 3 * * * /path/to/script/monitor.sh
To test crontab you can execute it every minute:
*/1 * * * * /path/to/script/monitor.sh
Be aware that this will be executed with the User permissions of the User you are currently. Only root can read /var/log/auth.log!
First script uses the ip-api to create json data files for every ip.
The API has a batch endpoint were you can query up to 100 Ip adresses in one post request.
Result:
[{
"as": "AS4837 CHINA UNICOM China169 Backbone",
"city": "Hefei",
"country": "China",
"countryCode": "CN",
"isp": "CNC Group CHINA169 AnHui province network",
"lat": 31.8206,
"lon": 117.227,
"org": "",
"query": "58.242.83.30",
"region": "AH",
"regionName": "Anhui",
"status": "success",
"timezone": "Asia/Shanghai",
"zip": ""
}]#! python
import requests
import json
import codecs
def getInfo(ip):
resp = requests.get('http://ip-api.com/json/' + ip)
if resp.status_code != 200:
data_formated = "Error while getting Data for ", ip
else:
data = resp.json()
# "ctry": data["country"], "isp": data["isp"],"org": data["org"]
data_formated = {"ip": ip, "lon": data["lon"], "lat": data["lat"], "country": data["country"], "isp": data["isp"],"org": data["org"] }
return data_formated
def getIps():
f = open('ips.txt','r')
ips = []
for line in f:
ips.append(line.rstrip("\n"))
#print(line.rstrip("\n"))
return ips
def generatePayload(ips):
payload = []
for ip in ips:
payload.append({"query": ip})
return payload
def batchRequest(ips):
payload = generatePayload(ips)
resp = requests.post('http://ip-api.com/batch', data=json.dumps(payload))
if resp.status_code != 200:
data_formated = "Error while getting Data for ", ip
if resp.status_code == 422:
data_formated = "Too much IPs in request"
else:
data = resp.json()
return data
def main():
ips = getIps()
ip_arry = []
# Cut array in chunks because of the api limitation
chunks = [ips[x:x+100] for x in range(0, len(ips), 100)]
for c,l in enumerate(chunks):
data = batchRequest(l)
s = str(c)
s += "_output.json"
with open(s, "wb") as outfile:
json.dump(data,codecs.getwriter('utf-8')(outfile), ensure_ascii=False)Visualization Script
#! python
import json
import itertools
from collections import Counter
import matplotlib.pyplot as plt
import numpy as np
def readIps():
data = {}
for i in range(0,47):
s = str(i)
s += "_output.json"
varForI = i
with open(s,"r", encoding="utf8") as infile:
raw = json.load(infile)
for c,i in enumerate(raw):
#print(i)
s = str(varForI)
s += "-"
s += str(c)
data[s] = i
return data
def createBarGraph(data, xlabel, ylabel, title):
label = []
no = []
for i in data:
label.append(i[0])
no.append(i[1])
index = np.arange(len(label))
plt.bar(index, no)
plt.xlabel(xlabel, fontsize=10)
plt.ylabel(ylabel, fontsize=10)
plt.xticks(index, label, fontsize=10, rotation=30)
plt.title(title)
plt.figure(figsize=(10,6))
plt.plot()
return plt
def main():
# ToDo
# - Save to PDF
# - Create World Map
data = readIps()
countrys = []
lonlat = []
isps = []
# Prepare Data
for i in data:
countrys.append(data[i]["country"])
lonlat.append((data[i]["lon"],data[i]["lat"]))
isps.append(data[i]["isp"])
# Count Data
ispsCount = Counter(isps).most_common()
countrysCount = Counter(countrys).most_common()
# Top Ten
countryTop10 = countrysCount[:10]
ispsTop10 = ispsCount[:10]
# Create Bar Graph
countryPlt = createBarGraph(countryTop10, 'Countrys', 'No of Countrys', 'Source of IP adresses')
ispPlt = createBarGraph(ispsTop10, 'ISP', 'No of ISP', 'ISP of IP adresses')
# Save to PDF
# Create World Map
if __name__ == "__main__":
main()