From 03f8754c1db64fa5b34c11e3c62b4f62afc4ad56 Mon Sep 17 00:00:00 2001 From: "Popal, Massi" <massi.popal@studium.uni-hamburg.de> Date: Sun, 23 Mar 2025 21:01:10 +0000 Subject: [PATCH] Upload New File --- gbac_server.py | 156 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 gbac_server.py diff --git a/gbac_server.py b/gbac_server.py new file mode 100644 index 0000000..b574811 --- /dev/null +++ b/gbac_server.py @@ -0,0 +1,156 @@ +#!/usr/bin/python3 + +from flask import Flask, request, jsonify +import ssl +import sqlite3 +from typing import List, Dict +import logging +import requests +import json +import networkx as nx +import os + +logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') + +app = Flask(__name__) + +conn = sqlite3.connect("iocs.db", check_same_thread=False) +conn.execute("CREATE TABLE IF NOT EXISTS iocs (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT)") + +def gac_connect(time_window: float = 300.0) -> List[Dict]: + """Identify multi-step attacks by constructing a directed graph of IoCs based on time and entity overlap.""" + cursor = conn.execute("SELECT data FROM iocs") + iocs = [json.loads(row[0]) for row in cursor.fetchall()] + if not iocs: + return [] + + G = nx.DiGraph() + for ioc in iocs: + G.add_node(ioc["timestamp"], data=ioc) + + for i, ioc1 in enumerate(iocs): + for ioc2 in iocs[i+1:]: + time_diff = float(ioc2["timestamp"]) - float(ioc1["timestamp"]) + if time_diff <= time_window and (set(ioc1["attackers"]) & set(ioc2["attackers"]) or set(ioc1["victims"]) & set(ioc2["victims"])): + G.add_edge(ioc1["timestamp"], ioc2["timestamp"]) + + multi_step_attacks = [] + for component in nx.weakly_connected_components(G): + nodes = sorted([G.nodes[n]["data"] for n in component], key=lambda x: float(x["timestamp"])) + if len(nodes) <= 1: + continue + attackers, victims, details = set(), set(), [] + attack_type = nodes[0]["pattern"] + for i, node in enumerate(nodes): + attackers.update(node["attackers"]) + victims.update(node["victims"]) + details.append(node) + if i > 0: + prev_type, curr_type = nodes[i-1]["pattern"], node["pattern"] + if "Portscan" in prev_type and "Exploitation" in curr_type: + attack_type = "Portscan followed by Exploitation" + elif "Exploitation" in prev_type and "DDoS" in curr_type: + attack_type = "Exploitation followed by DDoS" + elif "Portscan" in prev_type and "DDoS" in curr_type: + attack_type = "Portscan followed by DDoS" + elif "Exploitation" in prev_type and "Worm Propagation" in curr_type: + attack_type = "Exploitation followed by Worm Propagation" + else: + attack_type = f"{attack_type} and {curr_type}" + multi_step_attacks.append({ + "type": attack_type, + "attackers": list(attackers), + "victims": list(victims), + "details": details, + "network_id": nodes[0]["network_id"] + }) + + for attack in multi_step_attacks: + logging.info(f"Multi-Step Attack in {attack['network_id']} detected: {attack['type']}") + return multi_step_attacks + +@app.route('/submit_ioc', methods=['POST']) +def submit_ioc(): + """Process incoming IoCs, store them, and trigger alert generation.""" + ioc_data = request.json + for ioc in ioc_data: + conn.execute("INSERT INTO iocs (data) VALUES (?)", (json.dumps(ioc),)) + conn.commit() + logging.info(f"Received IoCs: {len(ioc_data)} from Network {ioc_data[0]['network_id']}") + + network_ids = set(ioc["network_id"] for ioc in ioc_data) + multi_step_attacks = gac_connect() + messages = [] + + if multi_step_attacks: + messages = send_alerts(multi_step_attacks, multi_step=True, network_ids=network_ids) + else: + cursor = conn.execute("SELECT data FROM iocs") + iocs = [json.loads(row[0]) for row in cursor.fetchall()] + if iocs: + messages = send_alerts(iocs, multi_step=False, network_ids=network_ids) + + # Print messages at the end + if messages: + print("\n=== Nachrichten an Netzwerke ===") + for msg in messages: + print(msg) + print("====================\n") + + return jsonify({"status": "success"}), 200 + +def send_alerts(attacks_or_iocs, multi_step: bool, network_ids: set) -> List[str]: + """Transmit alerts to client networks via HTTPS and return tailored messages.""" + messages = [] + for item in attacks_or_iocs: + source_network = item["network_id"] + alert_type = item["type"] if multi_step else item["pattern"] + attackers, victims = item["attackers"], item["victims"] + + if "Portscan" in alert_type: + recommendation = "Blockiere die Quell-IPs und überprüfe die Zielsysteme auf Scan-Aktivitäten." + elif "Exploitation" in alert_type: + recommendation = "Isoliere die betroffenen Systeme und überprüfe sie auf Kompromittierung." + elif "DDoS" in alert_type: + recommendation = "Erhöhe die Netzwerksicherheit und blockiere die Angreifer-IPs." + elif "Worm Propagation" in alert_type: + recommendation = "Quarantäne infizierte Systeme und führe eine Netzwerkbereinigung durch." + else: + recommendation = "Blockiere Angreifer-IPs und überprüfe Zielsysteme auf Kompromittierung." + + for network_id in network_ids: + if network_id == source_network: + message = f"In deinem Netzwerk wurde ein {alert_type} erkannt." + else: + message = f"Im angebundenen Netzwerk {source_network} wurde ein {alert_type} erkannt." + + alert_plus = { + "type": alert_type, + "attackers": attackers, + "victims": victims, + "source_network": source_network, + "current_network": network_id, + "recommendation": recommendation, + "message": message # Include the tailored message in the alert + } + network_url = f"https://{network_id.lower()}.local:8080/alert" + try: + response = requests.post(network_url, json=alert_plus, verify=False) + if response.status_code == 200: + logging.info(f"Alert Plus sent to {network_id}: {message}") + messages.append(f"An {network_id}: {message} Empfehlung: {recommendation}") + else: + logging.error(f"Error sending to {network_id}: {response.status_code}") + except Exception as e: + logging.error(f"Connection error sending to {network_id}: {e}") + + return messages + +if __name__ == "__main__": + context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + cert_path = "cert.pem" + key_path = "key.pem" + if not (os.path.exists(cert_path) and os.path.exists(key_path)): + raise FileNotFoundError("SSL certificates (cert.pem, key.pem) not found. Generate them with OpenSSL.") + context.load_cert_chain(cert_path, key_path) + app.run(host='0.0.0.0', port=443, ssl_context=context, threaded=False) \ No newline at end of file -- GitLab