1
0
mirror of https://github.com/Oxbian/SIDPS.git synced 2025-06-18 11:48:17 +02:00

feat: syn/tcpconnect flood / dos détection

This commit is contained in:
Oxbian 2024-11-20 21:38:37 -05:00
parent a1dcee53a1
commit d64f7283de
Signed by: Oxbian
GPG Key ID: 0E8F319FD43747E5
12 changed files with 147 additions and 18 deletions

@ -21,5 +21,11 @@
"nullscan_time": 180,
"nullscan_count": 5,
"xmasscan_time": 180,
"xmasscan_count": 5
"xmasscan_count": 5,
"synflood_time": 60,
"synflood_count": 100,
"tcpconnectflood_time": 60,
"tcpconnectflood_count": 100,
"syndos_time": 60,
"syndos_count": 100
}

@ -94,7 +94,7 @@ def packet_callback(packet, rules_functions, tcp_packets, db):
#print(packet)
if IP in packet and TCP in packet:
tcp_packets.add_packet(packet[IP].src, packet[TCP].sport, packet[IP].dst, packet[TCP].dport, packet[TCP].flags, time.time())
print(tcp_packets[packet[IP].src])
#print(tcp_packets[packet[IP].src])
check_frame_w_rules(packet, rules_functions['TCP'], tcp_packets, db)
tcp_packets.clean_old_packets()

@ -0,0 +1,36 @@
from datetime import datetime
import time
def rule(packet, tcp_packets, db):
"""
Règle SYN Dos:
Un SYN DOS va envoyer des requêtes TCP avec le flag SYN en très grand nombre afin de surcharger le serveur ou la cible avec des grosses quantités de données
- Si le port est ouvert, le serveur répond avec: SYN-ACK, puis le client RESET la connexion.
- Si le port est fermé, le serveur répond avec: RST-ACK.
"""
# Ne pas réagir si dans la période de cooldown
if (rule.cooldown + rule.time_window > time.time()):
return
# Initialisation des paramètres à partir de la configuration si nécessaire
if (rule.seuil == 0 and rule.time_window == 0):
rule.time_window = db.get_key("synsdos_time", 60)
rule.seuil = db.get_key("syndos_count", 100)
# Comptage des paquets TCP correspondant aux motifs spécifiques
syndeny_count = tcp_packets.count_packet_of_type(["S", "RA"], rule.time_window, True)
synaccept_count = tcp_packets.count_packet_of_type(["S", "SA", "R"], rule.time_window, True)
# Détection si le seuil est dépassé et que la charge utile des paquets est non nulle
if (syndeny_count + synaccept_count >= rule.seuil and len(packet['TCP'].payload) > 0):
db.send_alert(datetime.now(), 5, None, "Syn DOS", packet['IP'].src, packet['IP'].dst, proto="TCP", reason="Détection de nombreux patterns de Syn->SynACK->Reset et Syn->Reset ACK", act="Alerte")
print("Alerte, seuil dépassé, risque de Syn DOS détecté.")
rule.cooldown = time.time()
# Variables statiques
rule.cooldown = 0
rule.time_window = 0
rule.seuil = 0

@ -0,0 +1,36 @@
from datetime import datetime
import time
def rule(packet, tcp_packets, db):
"""
Règle SYN Flood:
Un SYN Flood va envoyer des requêtes TCP avec le flag SYN en très grand nombre afin de surcharger le serveur ou la cible
- Si le port est ouvert, le serveur répond avec: SYN-ACK, puis le client RESET la connexion.
- Si le port est fermé, le serveur répond avec: RST-ACK.
"""
# Ne pas réagir si dans la période de cooldown
if (rule.cooldown + rule.time_window > time.time()):
return
# Initialisation des paramètres à partir de la configuration si nécessaire
if (rule.seuil == 0 and rule.time_window == 0):
rule.time_window = db.get_key("synsflood_time", 60)
rule.seuil = db.get_key("synflood_count", 100)
# Comptage des paquets TCP correspondant aux motifs spécifiques
syndeny_count = tcp_packets.count_packet_of_type(["S", "RA"], rule.time_window, True)
synaccept_count = tcp_packets.count_packet_of_type(["S", "SA", "R"], rule.time_window, True)
# Détection si le seuil est dépassé
if (syndeny_count + synaccept_count >= rule.seuil):
db.send_alert(datetime.now(), 5, None, "Syn flood", packet['IP'].src, packet['IP'].dst, proto="TCP", reason="Détection de nombreux patterns de Syn->SynACK->Reset et Syn->Reset ACK", act="Alerte")
print("Alerte, seuil dépassé, risque de Syn Flood détecté.")
rule.cooldown = time.time()
# Variables statiques
rule.cooldown = 0
rule.time_window = 0
rule.seuil = 0

@ -0,0 +1,34 @@
from datetime import datetime
import time
def rule(packet, tcp_packets, db):
"""Règle TCPConnect Flood:
Un flood TCP connect va effectuer une connexion TCP en très grand nombre
Si le port est ouvert le serveur acceptera la connexion SYN -> SYN ACK -> ACK -> Reset ACK
Sinon le port est fermé et le serveur refusera la connexion SYN -> Reset ACK
"""
if (rule.cooldown + rule.time_window > time.time()):
return
# Vérification si nécessaire de récupérer les variables depuis la config
if (rule.seuil == 0 and rule.time_window == 0):
rule.time_window = db.get_key("tcpconnectflood_time", 60)
rule.seuil = db.get_key("tcpconnectflood_count", 100)
# Comptage du nombre de scan tcp connect acceptés et refusés
tcpconnectdeny_count = tcp_packets.count_packet_of_type(["S", "RA"], rule.time_window, True)
tcpconnectaccept_count = tcp_packets.count_packet_of_type(["S", "SA", "A", "RA"], rule.time_window, True)
if (tcpconnectaccept_count + tcpconnectdeny_count >= rule.seuil):
db.send_alert(datetime.now(), 5, None, "TCPConnect Flood", packet['IP'].src, packet['IP'].dst, proto="TCP", reason="Détection de nombreux patterns de Syn->SynACK->ACK->Reset ACK et Syn->Reset ACK", act="Alerte")
print(f"Alerte, seuils dépassés, risque de TCPconnect Flood")
rule.cooldown = time.time()
# Variables statiques
rule.cooldown = 0
rule.time_window = 0
rule.seuil = 0

@ -16,7 +16,11 @@ def rule(packet, tcp_packets, db):
rule.time_window = db.get_key("ackscan_time", 180)
rule.seuil = db.get_key("ackscan_count", 5)
if tcp_packets.count_packet_of_type(["A", "R"], rule.time_window, True) + tcp_packets.count_packet_of_type(["A"], rule.time_window, True) >= rule.seuil:
# Comptage nombre de scan ack acceptés et refusés
ackdeny_count = tcp_packets.count_packet_of_type(["A", "R"], rule.time_window, True)
ackaccept_count = tcp_packets.count_packet_of_type(["A"], rule.time_window, True)
if (ackaccept_count + ackdeny_count >= rule.seuil):
db.send_alert(datetime.now(), 5, None, "ACK scan", packet['IP'].src, packet['IP'].dst, proto="TCP", reason="Détection de nombreux patterns de Ack->Reset et Ack pas de réponse", act="Alerte")
print(f"Alerte, seuil dépassés, risque d'Ack scan")
rule.cooldown = time.time()

@ -16,7 +16,11 @@ def rule(packet, tcp_packets, db):
rule.time_window = db.get_key("finscan_time", 180)
rule.seuil = db.get_key("finscan_count", 5)
if tcp_packets.count_packet_of_type(["F", "RA"], rule.time_window, True) + tcp_packets.count_packet_of_type(["F"], rule.time_window, True) >= rule.seuil:
# Comptage du nombre de scan fin acceptés et refusés
findeny_count = tcp_packets.count_packet_of_type(["F", "RA"], rule.time_window, True)
finaccept_count = tcp_packets.count_packet_of_type(["F"], rule.time_window, True)
if (findeny_count + finaccept_count >= rule.seuil):
db.send_alert(datetime.now(), 5, None, "Fin scan", packet['IP'].src, packet['IP'].dst, proto="TCP", reason="Détection de nombreux patterns de Fin->Reset Ack et Fin->rien", act="Alerte")
print(f"Alerte, seuil dépassés, risque de Fin Scan")
rule.cooldown = time.time()

@ -16,7 +16,11 @@ def rule(packet, tcp_packets, db):
rule.time_window = db.get_key("nullscan_time", 180)
rule.seuil = db.get_key("nullscan_count", 5)
if tcp_packets.count_packet_of_type([""], rule.time_window, True) + tcp_packets.count_packet_of_type(["", "RA"], rule.time_window, True) >= rule.seuil:
# Comptage du nombre de scan null acceptés et refusés
nulldeny_count = tcp_packets.count_packet_of_type(["", "RA"], rule.time_window, True)
nullaccept_count = tcp_packets.count_packet_of_type([""], rule.time_window, True)
if (nulldeny_count + nulldeny_count >= rule.seuil):
db.send_alert(datetime.now(), 5, None, "Null scan", packet['IP'].src, packet['IP'].dst, proto="TCP", reason="Détection de nombreux patterns de None->Reset Ack et None -> rien", act="Alerte")
print(f"Alerte, seuil dépassés, risque de Null Scan")
rule.cooldown = time.time()

@ -3,7 +3,7 @@ import time
def rule(packet, tcp_packets, db):
"""Règle SYNScan:
"""Règle SYN Scan:
Un SYNScan va envoyer des requêtes TCP avec le flag SYN
Si le port est ouvert alors le serveur répondra: Syn ACK, puis le client Reset la connexion
Sinon le port est fermé et le serveur répondra: Reset ACK
@ -16,7 +16,11 @@ def rule(packet, tcp_packets, db):
rule.time_window = db.get_key("synscan_time", 180)
rule.seuil = db.get_key("synscan_count", 5)
if tcp_packets.count_packet_of_type(["S", "RA"], rule.time_window, True) + tcp_packets.count_packet_of_type(["S", "SA", "R"], rule.time_window, True) >= rule.seuil:
# Comptage du nombre de scan syn acceptés et refusés
syndeny_count = tcp_packets.count_packet_of_type(["S", "RA"], rule.time_window, True)
synaccept_count = tcp_packets.count_packet_of_type(["S", "SA", "R"], rule.time_window, True)
if (synaccept_count + syndeny_count >= rule.seuil):
db.send_alert(datetime.now(), 5, None, "Syn scan", packet['IP'].src, packet['IP'].dst, proto="TCP", reason="Détection de nombreux patterns de Syn->SynACK->Reset et Syn->Reset ACK", act="Alerte")
print(f"Alerte, seuil dépassés, risque de SynScan")
rule.cooldown = time.time()

@ -17,7 +17,11 @@ def rule(packet, tcp_packets, db):
rule.time_window = db.get_key("tcpconnectscan_time", 180)
rule.seuil = db.get_key("tcpconnectscan_count", 5)
if tcp_packets.count_packet_of_type(["S", "SA", "A", "RA"], rule.time_window, True) + tcp_packets.count_packet_of_type(["S", "RA"], rule.time_window, True) >= rule.seuil:
# Comptage du nombre de scan tcp connect acceptés et refusés
tcpconnectdeny_count = tcp_packets.count_packet_of_type(["S", "RA"], rule.time_window, True)
tcpconnectaccept_count = tcp_packets.count_packet_of_type(["S", "SA", "A", "RA"], rule.time_window, True)
if (tcpconnectaccept_count + tcpconnectdeny_count >= rule.seuil):
db.send_alert(datetime.now(), 5, None, "TCPConnect Scan", packet['IP'].src, packet['IP'].dst, proto="TCP", reason="Détection de nombreux patterns de Syn->SynACK->ACK->Reset ACK et Syn->Reset ACK", act="Alerte")
print(f"Alerte, seuils dépassés, risque de TCPConnectScan")
rule.cooldown = time.time()
@ -25,5 +29,5 @@ def rule(packet, tcp_packets, db):
# Variables statiques
rule.cooldown = 0
rule.time_window = 180
rule.seuil = 5
rule.time_window = 0
rule.seuil = 0

@ -16,7 +16,11 @@ def rule(packet, tcp_packets, db):
rule.time_window = db.get_key("xmasscan_time", 180)
rule.seuil = db.get_key("xmasscan_count", 5)
if tcp_packets.count_packet_of_type(["FPU", "RA"], rule.time_window, True) + tcp_packets.count_packet_of_type(["FPU"], rule.time_window, True) >= rule.seuil:
# Comptage du nombre de scan XMAS acceptés et refusés
xmasdeny_count = tcp_packets.count_packet_of_type(["FPU", "RA"], rule.time_window, True)
xmasaccept_count = tcp_packets.count_packet_of_type(["FPU"], rule.time_window, True)
if (xmasaccept_count + xmasdeny_count >= rule.seuil):
db.send_alert(datetime.now(), 5, None, "XMAS scan", packet['IP'].src, packet['IP'].dst, proto="TCP", reason="Détection de nombreux patterns de Fin Push Urg -> rien et Fin Push Urg->Reset ACK", act="Alerte")
print(f"Alerte, seuil dépassés, risque de XMAS Scan")
rule.cooldown = time.time()

@ -34,7 +34,6 @@ class TCP:
i, ip = self.find_packet_to_replace(ip_src, port_src, ip_dst, port_dst, "S")
if i is not None:
print(f"i: {i}, {ip_src}:{port_src}->{ip_dst}:{port_dst}, paquets: \n{self.packets}")
self.packets[ip][i][3].append("SA")
self.packets[ip][i][4] = timestamp
return
@ -48,7 +47,6 @@ class TCP:
i, ip = self.find_packet_to_replace(ip_src, port_src, ip_dst, port_dst, "R")
if i is not None:
print(f"i: {i}, {ip_src}:{port_src}->{ip_dst}:{port_dst}, paquets: \n{self.packets}")
self.packets[ip][i][3].append("A")
self.packets[ip][i][4] = timestamp
return
@ -63,7 +61,6 @@ class TCP:
i, ip = self.find_packet_to_replace(ip_src, port_src, ip_dst, port_dst, "S")
if i is not None:
print(f"i: {i}, {ip_src}:{port_src}->{ip_dst}:{port_dst}, paquets: \n{self.packets}")
self.packets[ip][i][3].append("RA")
self.packets[ip][i][4] = timestamp
return
@ -78,7 +75,6 @@ class TCP:
i, ip = self.find_packet_to_replace(ip_src, port_src, ip_dst, port_dst, "S")
if i is not None:
print(f"i: {i}, {ip_src}:{port_src}->{ip_dst}:{port_dst}, paquets: \n{self.packets}")
self.packets[ip][i][3].append("R")
self.packets[ip][i][4] = timestamp
return
@ -90,7 +86,6 @@ class TCP:
i, ip = self.find_packet_to_replace(ip_src, port_src, ip_dst, port_dst, "A")
if i is not None:
print(f"i: {i}, {ip_src}:{port_src}->{ip_dst}:{port_dst}, paquets: \n{self.packets}")
self.packets[ip][i][3].append("F")
self.packets[ip][i][4] = timestamp
return
@ -98,8 +93,6 @@ class TCP:
self.packets[ip_src].append([port_src, ip_dst, port_dst, ["F"], timestamp])
return
# TODO: ajout flag fin, none, fin urg push
def find_packet_to_replace(self, ip_src, port_src, ip_dst, port_dst, flags):
"""Cherche l'indice et le port de source du paquet dont le flag doit être remplacé"""