19 abril 2015

Bloquear, banear las ips de atacantes al ssh en Raspberrypi con un script de Python

Los que tenemos una Raspberry pi y nos conectamos desde cualquier parte del mundo :-) a través de ssh, tenemos un problema con ciertos personajes que quieren acceder también a ella vía bruteforce. Si no sabes de lo que estoy hablando te aconsejo que accedas al fichero auth.log dentro del directorio /var/log/, aquí podrás ver los múltiples intentos de acceso que tienes.
Cansado de que se quisieran conectar a ella, decidí crearme un script en python que lee el fichero auth.log y mete las ips  en un conjunto y las añade al iptables. Con ello banneo o bloqueo todas las ips extrañas.
Antes de ejecutar el script deberás instalar la aplicación ipset y iptables si no las tienes ya instaladas, para ello deberás ejecutar los siguientes comandos:

  1. sudo apt-get update
  2. sudo apt-get install ipset
  3. sudo apt-get install iptables

Aquí os dejo el script pero podéis descargarlo desde github 

#!/usr/bin/env python3.4
 
"""
 sudo ipset create banthis hash:ip maxelem 1000000
 sudo ipset add banthis 1.1.1.1
 sudo iptables -I INPUT -m set --match-set banthis src -p tcp --destination-port 22 -j DROP


 $ sudo ipset save banthis > banthis.txt
 $ sudo ipset destroy banthis
 $ sudo ipset restore -f banthis.txt

"""

# IMPORTS
import hashlib
import re
import socket
import pprint
import subprocess
import commands
import os
import time
 
# VARS
log_path = '/var/log/auth.log'
hosts=[]
full_hosts_data=[]
previous_ip = ""
previous_host = ""

#Create ipset
def create_banthis():
 return subprocess.call("ipset create banthis hash:ip maxelem 1000000" ,shell=True);

#Save ipset
def save_banthis():
 return subprocess.call("ipset save banthis > banthis.txt" ,shell=True);

#Add ip to ipset
def anhade_ip(ip):
 return subprocess.call(["ipset", "add", "banthis", ip]);

#Add ipset to iptables
def anhade_iptables():
 subprocess.call("iptables -I INPUT -m set --match-set banthis src -p tcp --destination-port 22 -j DROP",shell=True);

def borra_iptables():
 p = subprocess.Popen(["iptables", "-L", "--line-numbers"], stdout=subprocess.PIPE);
 output , err = p.communicate();
 for line in output.split("\n"):
  check_1 = line.find("banthis");
  if check_1 != -1 :
   index= subprocess.call("iptables -D INPUT " + line[0],shell=True);

#Check requirements
def check_requirements():
  ipset_status = commands.getstatusoutput("hash ipset")
  iptables_status = commands.getstatusoutput("hash iptables")
  if ipset_status[0] != 0 or iptables_status[0] != 0:
    raise Exception("Iptables and/or ipset not found, please intstall these dependencies first")

#Adjust lines
def adjust_item( str, i ):
    if len(str) < i:
        for j in range(i-len(str)):
            str = str + " "
    return str
 
#Lookup ip by name
def get_ip_hostname(name):
 try:
            return socket.gethostbyname(name);
        except Exception:
            return "0";

#Date
def get_date( my_line ):
    date_words = my_line.split(":")
    date = date_words[0] +":"+ date_words[1] +":"+ ((date_words[2]).split(" "))[0]
    return date

try:
 start_time = time.time();
 check_requirements();
 if save_banthis() == 1:
  create_banthis();

 # READ FILE
 with open(log_path, 'rt') as log:
     text = log.read();

 # COLLECTING HOSTS AND IPS
 for line in text.split("\n"):
  if "sshd" in line:
   if len(line) > 5:
    check_1 = line.find("rhost=")
    if check_1 != -1 :
     words = line[check_1:len(line)].split(" ");
     if len(words) > 2 :
      if len(words[2]) > 5 :
       user = words[2].split("=")[1];
       ip = words[0].split("=")[1];
       host = ip;
       pat = re.compile("^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$");  
       test = pat.match(ip);
       if not test:
        ip = get_ip_hostname(ip);
        if ip != "0":
         host = ip;  
       exists_check = 0
       for my_host in hosts:
        if my_host["ip"] == ip:
         exists_check = 1;
       if exists_check == 0:
        if not "192.168." in ip :
         hosts.append({"ip":ip, "hostname":host , "accounts":user, "date":get_date( line )});

 # PRINT TABLE HEADERS
 print(
  adjust_item("DATE", 16 ),
  adjust_item("IP", 15),
  adjust_item("HOSTNAME", 40),
  adjust_item("ACCOUNTS", 30)
 )
 for item in hosts:
  anhade_ip(item["ip"])
  parsed_ip           = adjust_item( item["ip"],          15 )
  parsed_date         = adjust_item( item["date"],        16 )
  parsed_host         = adjust_item( item["hostname"] ,   40 )
  parsed_accounts     = adjust_item( item["accounts"],    30 )
  print(
   parsed_date[:16],
   parsed_ip, parsed_host[:40],
   parsed_accounts[:30],
  )
 borra_iptables();
 anhade_iptables();
 print("--- %s seconds ---" % (time.time() - start_time));
except Exception as e:
 print str(e);