Si vous suivez Hackademics sur Twitter, vous savez probablement que nous avons subit une attaque DDOS hier soir.
Les admins et moi même avons rapidement réglé le soucis et la situation est bien vite rentrée dans l'ordre malgré un filtrage d'adresse IP un tout petit peu trop restrictif entre hier 23h et ce matin 6h.
Je ferai dans les quelques jours à venir un article plus détaillé sur le déroulement de l'attaque, sa découverte et sa mitigation mais aujourd'hui, j'aimerais vous présenter le programme que j'ai écrit pour éviter de re-mettre en place des blocages trop restrictifs dans le cas d'une future occurence.
Je définirais ce code comme un outils de mitigation d'attaque DDOS dans la mesure où il est capable de :
Un exemple d'utilisation lors d'une attaque serait alors de :
Voici de plus le manuel du programme (qui est écrit en Python 3 et sans dépendances) :
Le code du programme
Notez que le code pourrait être modifié sur GitHub mais ne le sera dans ce cas pas sur cette page
Cet article est apparu en primeur sur mon site web : spidermind.be
Les admins et moi même avons rapidement réglé le soucis et la situation est bien vite rentrée dans l'ordre malgré un filtrage d'adresse IP un tout petit peu trop restrictif entre hier 23h et ce matin 6h.
Je ferai dans les quelques jours à venir un article plus détaillé sur le déroulement de l'attaque, sa découverte et sa mitigation mais aujourd'hui, j'aimerais vous présenter le programme que j'ai écrit pour éviter de re-mettre en place des blocages trop restrictifs dans le cas d'une future occurence.
Je définirais ce code comme un outils de mitigation d'attaque DDOS dans la mesure où il est capable de :
- Grouper les logs de connexion sur un serveur NGINX en série temporelle pour définir quand l'attaque à commencé (à partir de cette tranche temporelle, le nombre de connexion devrait augmenter très significativement)
- Retrouver les adresses IP s'étant connecté à votre serveur dans une tranche temporelle que vous définissez
Un exemple d'utilisation lors d'une attaque serait alors de :
- Découvrir le début de l'attaque via le premier point de la liste précédente
- Relever les IPs attaquantes via le second point de la liste précédente tout en fixant le début au début de l'attaque et la fin à un moment que vous choisissez. Remarquez quand même que mettre un point de fin éloigné du point de début augmente le nombre d'IPs attaquantes que vous allez sélectionner mais augmente également le nombre d'IPs légitimes que vous prendrez avec
- Créer des règles firewall de banissement sur les IPs découvertes
Voici de plus le manuel du programme (qui est écrit en Python 3 et sans dépendances) :
Code:
usage: mitigate_DDOS.py [-h] -f NGINX_LOG_FILE [-a] [-t TIME] [-i] [-b BEGIN_TIMESTAMP] [-e END_TIMESTAMP] Analyzes web server logs to find begin and mitigate DDOS attack optional arguments: -h, --help show this help message and exit -f NGINX_LOG_FILE The nginx log file -a Analysis task -t TIME Time split for log blocks (default 10) -i Get IPs between two timestamps -b BEGIN_TIMESTAMP Begin timestamp (in seconds) for IP gathering -e END_TIMESTAMP Begin timestamp (in seconds) for IP gathering
Notez que le code pourrait être modifié sur GitHub mais ne le sera dans ce cas pas sur cette page
Code:
"""Script to mitigate a ddos attack by analyzing web log log file""" import os import sys from collections import namedtuple import datetime import argparse LogLine = namedtuple("LogLine", "ip time") class NginxLogDao(): """Data access object for NginxLog""" def __init__(self, filename): """Initialises this with given filename""" assert filename is not None assert os.path.exists(filename) self.filename = filename def log_lines(self): """Reads logs lines and returns them as named tuples""" with open(self.filename) as f: for line in f: ip = line.split("-")[0].strip() date_str = line.split("[")[1].split("]")[0].split(" ")[0] date = datetime.datetime.strptime( date_str, '%d/%b/%Y:%H:%M:%S') yield LogLine(ip=ip, time=date) def time_grouped(self, time_size=10): """Returns log lines grouped in time groups with blocks of time_size seconds""" block = None block_begin = None for log_line in self.log_lines(): if block_begin is None or log_line.time > block_begin \ + datetime.timedelta(seconds=time_size): if block_begin is not None: yield block block_begin = log_line.time block = list() block.append(log_line) def ips_between(self, dt1, dt2): """Returns set of ip addresses between two timestamps""" ips = set() for log_line in self.log_lines(): if dt1 <= log_line.time <= dt2: ips.add(log_line.ip) elif log_line.time > dt2: break return list(ips) if __name__ == '__main__': parser = argparse.ArgumentParser( description='Analyzes web server logs to find begin and mitigate DDOS attack') parser.add_argument('-f', action="store", dest="nginx_log_file", help="The nginx log file", required=True) parser.add_argument('-a', action="store_true", dest="analyze", help="Analysis task") parser.add_argument('-t', action="store", dest="time", help="Time split for log blocks (default 10)", default=10) parser.add_argument('-i', action="store_true", dest="get_ip", help="Get IPs between two timestamps") parser.add_argument('-b', action="store", dest="begin_timestamp", help="Begin timestamp (in seconds) for IP gathering") parser.add_argument('-e', action="store", dest="end_timestamp", help="Begin timestamp (in seconds) for IP gathering") params = parser.parse_args() if params.analyze: time = int(params.time) blocks = NginxLogDao( params.nginx_log_file).time_grouped(time_size=time) for block in blocks: block_start = block[0].time timestamp = int(block_start.timestamp()) print("{} - {} - {}".format(block_start, timestamp, len(block))) elif params.get_ip: if params.begin_timestamp is None or params.end_timestamp is None: print("With option -i you must provide option -b and -e") sys.exit(1) begin_timestamp = datetime.datetime.fromtimestamp(int(params.begin_timestamp)) end_timestamp = datetime.datetime.fromtimestamp(int(params.end_timestamp)) ips = NginxLogDao(params.nginx_log_file).ips_between(begin_timestamp, end_timestamp) for ip in ips: print(ip)
Commentaire