├── VERSION ├── images ├── logo.PNG └── dashboard.png ├── utils ├── __init__.py ├── packet_capture.py ├── load.py ├── reporter.py └── packet_filter.py ├── base_attack.py ├── .gitignore ├── attacks_templates ├── __init__.py ├── lfi_detector.py ├── xxs_detector.py ├── ssti_detector.py ├── sql_injection.py ├── crlf_detector.py ├── csrf_detector.py ├── icmp_packet_detector.py ├── ddos_attack.py ├── mac_flooding.py ├── arp_attack.py └── port_scan.py ├── webserver ├── search_ip.php ├── delete_reports.php ├── report.php ├── styles.css └── view_reports.php ├── LICENSE ├── Setup.sh ├── eye_of_snake.py ├── config.json └── README.md /VERSION: -------------------------------------------------------------------------------- 1 | 1.0 2 | -------------------------------------------------------------------------------- /images/logo.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0Xdarkday/Snake-Eye/HEAD/images/logo.PNG -------------------------------------------------------------------------------- /images/dashboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/0Xdarkday/Snake-Eye/HEAD/images/dashboard.png -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | from .packet_filter import PacketFilter 2 | from .reporter import Reporter 3 | from .packet_capture import start_packet_capture 4 | from .load import load_config 5 | -------------------------------------------------------------------------------- /base_attack.py: -------------------------------------------------------------------------------- 1 | class BaseAttack: 2 | def __init__(self, reporter): 3 | self.reporter = reporter 4 | 5 | def detect(self, packet): 6 | raise NotImplementedError("This method should be overridden by subclasses") 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # Distribution / packaging 7 | build/ 8 | dist/ 9 | *.egg-info/ 10 | .installed.cfg 11 | *.egg 12 | 13 | # Logs and databases 14 | logs/ 15 | *.log 16 | 17 | # Virtual environment 18 | .env/ 19 | venv/ 20 | 21 | # OS-specific files 22 | .DS_Store 23 | Thumbs.db 24 | -------------------------------------------------------------------------------- /utils/packet_capture.py: -------------------------------------------------------------------------------- 1 | import pyshark 2 | import logging 3 | 4 | def start_packet_capture(interface: str, packet_filter): 5 | logging.info(f"Starting packet capture on interface {interface}") 6 | capture = pyshark.LiveCapture(interface=interface) 7 | 8 | try: 9 | for packet in capture.sniff_continuously(): 10 | packet_filter.filter(packet) 11 | except Exception as e: 12 | logging.error(f"Error during packet capture: {e}") 13 | -------------------------------------------------------------------------------- /attacks_templates/__init__.py: -------------------------------------------------------------------------------- 1 | from .arp_attack import ARPAttackDetector 2 | from .crlf_detector import CRLFDetector 3 | from .csrf_detector import CSRFDetector 4 | from .ddos_attack import DDOSAttackDetector 5 | from .icmp_packet_detector import ICMPPingDetector 6 | from .mac_flooding import MACFloodingDetector 7 | from .port_scan import PortScanDetector 8 | from .sql_injection import SQLInjectionDetector 9 | from .ssti_detector import SSTIDetector 10 | from .xxs_detector import XSSDetector 11 | from .lfi_detector import LFIDetector 12 | -------------------------------------------------------------------------------- /attacks_templates/lfi_detector.py: -------------------------------------------------------------------------------- 1 | from base_attack import BaseAttack 2 | 3 | class LFIDetector(BaseAttack): 4 | def __init__(self, reporter, config): 5 | super().__init__(reporter) 6 | self.patterns = config['patterns']['lfi'] 7 | 8 | def detect(self, packet): 9 | if hasattr(packet, 'http') and hasattr(packet.http, 'request_uri'): 10 | request_uri = packet.http.request_uri 11 | for pattern in self.patterns: 12 | if pattern in request_uri: 13 | self.reporter.report_attack('LFI', packet.ip.src, packet.ip.dst, 'HTTP', {'uri': request_uri, 'pattern': pattern}) 14 | return True 15 | return False 16 | -------------------------------------------------------------------------------- /attacks_templates/xxs_detector.py: -------------------------------------------------------------------------------- 1 | from base_attack import BaseAttack 2 | 3 | class XSSDetector(BaseAttack): 4 | def __init__(self, reporter, config): 5 | super().__init__(reporter) 6 | self.patterns = config['patterns']['xss'] 7 | 8 | def detect(self, packet): 9 | if hasattr(packet, 'http') and hasattr(packet.http, 'request_uri'): 10 | request_uri = packet.http.request_uri 11 | for pattern in self.patterns: 12 | if pattern in request_uri: 13 | self.reporter.report_attack('XSS', packet.ip.src, packet.ip.dst, 'HTTP', {'uri': request_uri, 'pattern': pattern}) 14 | return True 15 | return False 16 | -------------------------------------------------------------------------------- /attacks_templates/ssti_detector.py: -------------------------------------------------------------------------------- 1 | from base_attack import BaseAttack 2 | 3 | class SSTIDetector(BaseAttack): 4 | def __init__(self, reporter, config): 5 | super().__init__(reporter) 6 | self.patterns = config['patterns']['ssti'] 7 | 8 | def detect(self, packet): 9 | if hasattr(packet, 'http') and hasattr(packet.http, 'request_uri'): 10 | request_uri = packet.http.request_uri 11 | for pattern in self.patterns: 12 | if pattern in request_uri: 13 | self.reporter.report_attack('SSTI', packet.ip.src, packet.ip.dst, 'HTTP', {'uri': request_uri, 'pattern': pattern}) 14 | return True 15 | return False 16 | -------------------------------------------------------------------------------- /attacks_templates/sql_injection.py: -------------------------------------------------------------------------------- 1 | from base_attack import BaseAttack 2 | 3 | class SQLInjectionDetector(BaseAttack): 4 | def __init__(self, reporter, config): 5 | super().__init__(reporter) 6 | self.patterns = config['patterns']['sql_injection'] 7 | 8 | def detect(self, packet): 9 | if hasattr(packet, 'http') and hasattr(packet.http, 'request_uri'): 10 | request_uri = packet.http.request_uri 11 | for pattern in self.patterns: 12 | if pattern in request_uri: 13 | self.reporter.report_attack('SQL Injection', packet.ip.src, packet.ip.dst, 'HTTP', {'uri': request_uri, 'pattern': pattern}) 14 | return True 15 | return False 16 | 17 | -------------------------------------------------------------------------------- /attacks_templates/crlf_detector.py: -------------------------------------------------------------------------------- 1 | from base_attack import BaseAttack 2 | 3 | class CRLFDetector(BaseAttack): 4 | def __init__(self, reporter, config): 5 | super().__init__(reporter) 6 | self.crlf_patterns = config['patterns']['crlf'] 7 | 8 | def detect(self, packet): 9 | if hasattr(packet, 'http'): 10 | http_payload = getattr(packet.http, 'file_data', '') 11 | for pattern in self.crlf_patterns: 12 | if pattern in http_payload: 13 | src_ip = packet.ip.src 14 | dst_ip = packet.ip.dst 15 | protocol = packet.transport_layer 16 | self.reporter.report_attack('CRLF', src_ip, dst_ip, protocol, {'payload': http_payload}) 17 | break 18 | -------------------------------------------------------------------------------- /attacks_templates/csrf_detector.py: -------------------------------------------------------------------------------- 1 | from base_attack import BaseAttack 2 | 3 | class CSRFDetector(BaseAttack): 4 | def __init__(self, reporter, config): 5 | super().__init__(reporter) 6 | self.csrf_patterns = config['patterns']['csrf'] 7 | 8 | def detect(self, packet): 9 | if hasattr(packet, 'http'): 10 | http_payload = getattr(packet.http, 'file_data', '') 11 | for pattern in self.csrf_patterns: 12 | if pattern in http_payload: 13 | src_ip = packet.ip.src 14 | dst_ip = packet.ip.dst 15 | protocol = packet.transport_layer 16 | self.reporter.report_attack('CSRF', src_ip, dst_ip, protocol, {'payload': http_payload}) 17 | break 18 | -------------------------------------------------------------------------------- /utils/load.py: -------------------------------------------------------------------------------- 1 | import json 2 | import logging 3 | 4 | def load_config(config_file: str) -> dict: 5 | try: 6 | with open(config_file, 'r') as file: 7 | config = json.load(file) 8 | validate_config(config) 9 | return config 10 | except FileNotFoundError: 11 | logging.error(f"Config file {config_file} not found.") 12 | raise 13 | except json.JSONDecodeError: 14 | logging.error(f"Error decoding JSON from {config_file}.") 15 | raise 16 | 17 | def validate_config(config: dict): 18 | required_keys = ['api_server', 'logging', 'detection_thresholds', 'patterns', 'interfaces'] 19 | for key in required_keys: 20 | if key not in config: 21 | raise ValueError(f"Missing required config key: {key}") 22 | -------------------------------------------------------------------------------- /webserver/search_ip.php: -------------------------------------------------------------------------------- 1 | 'Invalid IP address or could not fetch data.']); 11 | } else { 12 | $result = [ 13 | 'ip' => $data['ip'] ?? 'N/A', 14 | 'country' => $data['country'] ?? 'N/A', 15 | 'country_code' => $data['country_code'] ?? 'N/A', 16 | 'region' => $data['region'] ?? 'N/A', 17 | 'city' => $data['city'] ?? 'N/A' 18 | ]; 19 | echo json_encode($result); 20 | } 21 | } else { 22 | echo json_encode(['error' => 'IP address not provided.']); 23 | } 24 | ?> 25 | -------------------------------------------------------------------------------- /webserver/delete_reports.php: -------------------------------------------------------------------------------- 1 | 28 | -------------------------------------------------------------------------------- /webserver/report.php: -------------------------------------------------------------------------------- 1 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 mahmoud shaker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Define variables 4 | WEB_ROOT="/var/www/html" 5 | LOG_FILE="/var/log/apache2/report_log.json" 6 | LOG_DIR=$(dirname "$LOG_FILE") 7 | TOOL_WEB_DIR="webserver" 8 | 9 | 10 | echo "Creating necessary directories..." 11 | sudo mkdir -p "$LOG_DIR" 12 | sudo chmod 755 "$LOG_DIR" 13 | 14 | 15 | if [ ! -f "$LOG_FILE" ]; then 16 | echo "Creating log file..." 17 | sudo touch "$LOG_FILE" 18 | fi 19 | sudo chmod 666 "$LOG_FILE" 20 | 21 | 22 | echo "Moving PHP and CSS files from $TOOL_WEB_DIR to $WEB_ROOT..." 23 | sudo mv "$TOOL_WEB_DIR/report.php" "$WEB_ROOT/" 24 | sudo mv "$TOOL_WEB_DIR/view_report.php" "$WEB_ROOT/" 25 | sudo mv "$TOOL_WEB_DIR/delete_reports.php" "$WEB_ROOT/" 26 | sudo mv "$TOOL_WEB_DIR/styles.css" "$WEB_ROOT/" 27 | sudo mv "$TOOL_WEB_DIR/search_ip.php" "$WEB_ROOT/" 28 | 29 | 30 | echo "Setting permissions for the moved files..." 31 | sudo chmod 644 "$WEB_ROOT/report.php" 32 | sudo chmod 644 "$WEB_ROOT/view_report.php" 33 | sudo chmod 644 "$WEB_ROOT/delete_reports.php" 34 | sudo chmod 644 "$WEB_ROOT/styles.css" 35 | sudo chmod 644 "$WEB_ROOT/search_ip.php" 36 | 37 | 38 | echo "Setup completed successfully." 39 | -------------------------------------------------------------------------------- /attacks_templates/icmp_packet_detector.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from datetime import datetime, timedelta 3 | 4 | class ICMPPingDetector: 5 | def __init__(self, reporter, config): 6 | self.reporter = reporter 7 | self.threshold = config['detection_thresholds']['icmp']['threshold'] 8 | self.window = timedelta(seconds=config['detection_thresholds']['icmp']['window']) 9 | self.icmp_tracker = defaultdict(list) 10 | 11 | def detect(self, packet): 12 | if hasattr(packet, 'icmp'): 13 | src_ip = packet.ip.src 14 | current_time = datetime.now() 15 | 16 | self.icmp_tracker[src_ip].append(current_time) 17 | 18 | # Remove outdated timestamps 19 | self.icmp_tracker[src_ip] = [timestamp for timestamp in self.icmp_tracker[src_ip] if current_time - timestamp <= self.window] 20 | 21 | if len(self.icmp_tracker[src_ip]) > self.threshold: 22 | self.reporter.report_attack('ICMP Ping Flood', src_ip, packet.ip.dst, 'ICMP', {'count': len(self.icmp_tracker[src_ip])}) 23 | return True 24 | return False 25 | 26 | 27 | -------------------------------------------------------------------------------- /attacks_templates/ddos_attack.py: -------------------------------------------------------------------------------- 1 | from collections import defaultdict 2 | from datetime import datetime, timedelta 3 | from base_attack import BaseAttack 4 | 5 | class DDOSAttackDetector(BaseAttack): 6 | def __init__(self, reporter, config): 7 | super().__init__(reporter) 8 | self.threshold = config['detection_thresholds']['ddos']['threshold'] 9 | self.window = timedelta(seconds=config['detection_thresholds']['ddos']['window']) 10 | self.ip_tracker = defaultdict(list) 11 | 12 | def detect(self, packet): 13 | if hasattr(packet, 'ip'): 14 | src_ip = packet.ip.src 15 | current_time = datetime.now() 16 | self.ip_tracker[src_ip].append(current_time) 17 | 18 | # Remove outdated timestamps 19 | self.ip_tracker[src_ip] = [timestamp for timestamp in self.ip_tracker[src_ip] if current_time - timestamp <= self.window] 20 | 21 | if len(self.ip_tracker[src_ip]) > self.threshold: 22 | self.reporter.report_attack('DDoS Attack', src_ip, packet.ip.dst, 'IP', {'count': len(self.ip_tracker[src_ip])}) 23 | return True 24 | return False 25 | -------------------------------------------------------------------------------- /webserver/styles.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap'); 2 | 3 | body { 4 | font-family: 'Roboto', Arial, sans-serif; 5 | margin: 0; 6 | padding: 0; 7 | background-color: #f4f4f4; 8 | } 9 | 10 | .container { 11 | width: 80%; 12 | margin: 0 auto; 13 | background: #fff; 14 | padding: 20px; 15 | box-shadow: 0 0 15px rgba(0,0,0,0.2); 16 | border-radius: 10px; 17 | } 18 | 19 | h1 { 20 | text-align: center; 21 | color: #333; 22 | } 23 | 24 | table { 25 | width: 100%; 26 | border-collapse: collapse; 27 | margin-top: 20px; 28 | } 29 | 30 | table, th, td { 31 | border: 1px solid #ddd; 32 | } 33 | 34 | th, td { 35 | padding: 12px; 36 | text-align: left; 37 | } 38 | 39 | th { 40 | background-color: #007bff; 41 | color: #fff; 42 | } 43 | 44 | tr:nth-child(even) { 45 | background-color: #f9f9f9; 46 | } 47 | 48 | tr:hover { 49 | background-color: #f1f1f1; 50 | } 51 | 52 | .ip-search input[type="text"] { 53 | padding: 10px; 54 | width: calc(100% - 120px); 55 | border: 1px solid #ddd; 56 | border-radius: 5px; 57 | } 58 | 59 | .ip-search .btn { 60 | width: 100px; 61 | } 62 | -------------------------------------------------------------------------------- /attacks_templates/mac_flooding.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta 2 | 3 | from collections import defaultdict 4 | 5 | from base_attack import BaseAttack 6 | 7 | 8 | 9 | class MACFloodingDetector(BaseAttack): 10 | 11 | def __init__(self, reporter, config): 12 | 13 | super().__init__(reporter) 14 | 15 | self.mac_tracker = defaultdict(int) 16 | 17 | self.mac_threshold = config['detection_thresholds']['mac_flooding']['threshold'] 18 | 19 | self.mac_window = timedelta(seconds=config['detection_thresholds']['mac_flooding']['window']) 20 | 21 | 22 | 23 | def detect(self, packet): 24 | 25 | if hasattr(packet, 'eth'): 26 | 27 | src_mac = packet.eth.src 28 | 29 | dst_mac = packet.eth.dst 30 | 31 | protocol = 'Ethernet' 32 | 33 | self.mac_tracker[src_mac] += 1 34 | 35 | 36 | 37 | if self.mac_tracker[src_mac] >= self.mac_threshold: 38 | 39 | first_attempt_time = datetime.now() - self.mac_window 40 | 41 | self.reporter.report_attack('mac_flooding', src_mac, dst_mac, protocol, {'count': self.mac_tracker[src_mac]}) 42 | 43 | self.mac_tracker[src_mac] = 0 44 | 45 | -------------------------------------------------------------------------------- /attacks_templates/arp_attack.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta 2 | from collections import defaultdict 3 | from base_attack import BaseAttack 4 | 5 | 6 | class ARPAttackDetector(BaseAttack): 7 | def __init__(self, reporter, config): 8 | super().__init__(reporter) 9 | self.threshold = config['detection_thresholds']['arp']['threshold'] 10 | self.window = config['detection_thresholds']['arp']['window'] 11 | self.arp_counter = defaultdict(int) 12 | 13 | def detect(self, packet): 14 | if hasattr(packet, 'arp'): 15 | src_ip = packet.arp.src_proto_ipv4 16 | self.arp_counter[src_ip] += 1 17 | if self.arp_counter[src_ip] > self.threshold: 18 | # Check if the ARP requests exceed the threshold within the window 19 | if self.check_threshold_exceeded(src_ip): 20 | self.reporter.report_attack('arp_flooding', src_ip, packet.arp.dst_proto_ipv4, 'ARP', {'count': self.arp_counter[src_ip]}) 21 | return True # Attack detected 22 | return False # No attack detected 23 | 24 | def check_threshold_exceeded(self, src_ip): 25 | window_start = datetime.now() - timedelta(seconds=self.window) 26 | for ip, count in self.arp_counter.items(): 27 | if count >= self.threshold and ip != src_ip: 28 | first_attempt_time = datetime.now() - timedelta(seconds=self.window) 29 | if self.arp_counter[src_ip] >= self.threshold and window_start <= first_attempt_time: 30 | return True 31 | return False 32 | -------------------------------------------------------------------------------- /attacks_templates/port_scan.py: -------------------------------------------------------------------------------- 1 | from datetime import datetime, timedelta 2 | from collections import defaultdict 3 | from base_attack import BaseAttack 4 | 5 | class PortScanDetector(BaseAttack): 6 | def __init__(self, reporter, config): 7 | super().__init__(reporter) 8 | self.threshold = config['detection_thresholds']['port_scan']['threshold'] 9 | self.window = timedelta(seconds=config['detection_thresholds']['port_scan']['window']) 10 | self.special_threshold = config['detection_thresholds']['port_scan'].get('special_threshold', 1000) 11 | self.special_window = timedelta(seconds=config['detection_thresholds']['port_scan'].get('special_window', 10)) 12 | self.ip_tracker = defaultdict(lambda: defaultdict(list)) 13 | 14 | def detect(self, packet): 15 | if hasattr(packet, 'ip') and hasattr(packet, 'tcp'): 16 | src_ip = packet.ip.src 17 | dst_port = packet.tcp.dstport 18 | current_time = datetime.now() 19 | self.ip_tracker[src_ip][dst_port].append(current_time) 20 | 21 | # Remove outdated timestamps 22 | self.ip_tracker[src_ip][dst_port] = [timestamp for timestamp in self.ip_tracker[src_ip][dst_port] if current_time - timestamp <= self.window] 23 | 24 | # Normal ports 25 | if dst_port not in [443, 53]: 26 | if len(self.ip_tracker[src_ip][dst_port]) > self.threshold: 27 | self.reporter.report_attack('Port Scanning', src_ip, packet.ip.dst, 'TCP', {'port': dst_port, 'count': len(self.ip_tracker[src_ip][dst_port])}) 28 | return True 29 | else: 30 | # Special handling for ports 443 and 53 31 | self.ip_tracker[src_ip][dst_port] = [timestamp for timestamp in self.ip_tracker[src_ip][dst_port] if current_time - timestamp <= self.special_window] 32 | if len(self.ip_tracker[src_ip][dst_port]) > self.special_threshold: 33 | self.reporter.report_attack('Potential DDoS on Port 443/53', src_ip, packet.ip.dst, 'TCP', {'port': dst_port, 'count': len(self.ip_tracker[src_ip][dst_port])}) 34 | return True 35 | return False 36 | -------------------------------------------------------------------------------- /utils/reporter.py: -------------------------------------------------------------------------------- 1 | import json 2 | import base64 3 | import requests 4 | import logging 5 | import os 6 | from datetime import datetime 7 | 8 | class Reporter: 9 | def __init__(self, ip, port, report_endpoint='report.php', use_https=False, log_file='logs/reporter.log'): 10 | self.ip = ip 11 | self.port = port 12 | self.protocol = 'https' if use_https else 'http' 13 | self.report_endpoint = report_endpoint 14 | self.reports = [] # Store reports 15 | # Ensure log directory exists 16 | log_dir = os.path.dirname(log_file) 17 | if not os.path.exists(log_dir): 18 | os.makedirs(log_dir, exist_ok=True) 19 | 20 | # Set up logging 21 | logging.basicConfig(level=logging.INFO, filename=log_file, format='%(asctime)s - %(levelname)s - %(message)s') 22 | self.logger = logging.getLogger(__name__) 23 | 24 | def report(self, message): 25 | try: 26 | json_payload = base64.b64encode(json.dumps(message).encode('ascii')).decode('utf8') 27 | self.logger.info(f"Reporting packet: {json_payload}") 28 | url = f'{self.protocol}://{self.ip}:{self.port}/{self.report_endpoint}' 29 | response = requests.post(url, data=json_payload) 30 | response.raise_for_status() 31 | self.logger.info(f"Report sent successfully: {response.text}") 32 | print(f"Report sent successfully: {response.text}") 33 | except requests.RequestException as e: 34 | self.logger.exception(f"Error while sending report: {e}") 35 | print(f"Error while sending report: {e}") 36 | 37 | def report_attack(self, attack_type, src_ip, dst_ip, protocol, details): 38 | report_data = { 39 | 'timestamp': datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 40 | 'attack_type': attack_type, 41 | 'src_ip': src_ip, 42 | 'dst_ip': dst_ip, 43 | 'protocol': protocol, 44 | 'details': details 45 | } 46 | self.logger.info(f"Reporting attack: {attack_type} from {src_ip} to {dst_ip} using {protocol}") 47 | print(f"Reporting attack: {attack_type} from {src_ip} to {dst_ip} using {protocol}") 48 | self.report(report_data) 49 | -------------------------------------------------------------------------------- /utils/packet_filter.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import ipaddress 3 | from pyshark.packet.packet import Packet 4 | from utils.reporter import Reporter 5 | from attacks_templates import ( 6 | PortScanDetector, DDOSAttackDetector, SQLInjectionDetector, 7 | MACFloodingDetector, ARPAttackDetector, ICMPPingDetector, 8 | XSSDetector, SSTIDetector, CSRFDetector, CRLFDetector , LFIDetector 9 | ) 10 | 11 | class PacketFilter: 12 | def __init__(self, reporter: Reporter, config): 13 | self.reporter = reporter 14 | self.config = config 15 | self.detectors = [ 16 | PortScanDetector(reporter, config), 17 | DDOSAttackDetector(reporter, config), 18 | SQLInjectionDetector(reporter, config), 19 | MACFloodingDetector(reporter, config), 20 | ICMPPingDetector(reporter, config), 21 | ARPAttackDetector(reporter, config), 22 | XXSDetector(reporter, config), 23 | SSTIDetector(reporter, config), 24 | CSRFDetector(reporter, config), 25 | CRLFDetector(reporter, config) 26 | ] 27 | 28 | def is_private_ip(self, ip_address: str) -> bool: 29 | """Check if the IP address is private.""" 30 | ip = ipaddress.ip_address(ip_address) 31 | return ip.is_private 32 | 33 | def is_api_server(self, packet: Packet) -> bool: 34 | """Check if the packet is directed to the API server.""" 35 | if hasattr(packet, 'ip') and hasattr(packet, 'tcp'): 36 | if ((packet.ip.src == self.reporter.ip) or (packet.ip.dst == self.reporter.ip)) and \ 37 | ((packet.tcp.dstport == self.reporter.port) or (packet.tcp.srcport == self.reporter.port)): 38 | return True 39 | return False 40 | 41 | def filter(self, packet: Packet): 42 | """Filter the packet and process it through various detectors.""" 43 | if self.is_api_server(packet): 44 | # Skip packets directed to the API server to avoid false positives. 45 | return 46 | 47 | # Process packet through all detectors 48 | for detector in self.detectors: 49 | try: 50 | if detector.detect(packet): 51 | # If a detector identifies a suspicious packet, report it 52 | self.report_packet(packet) 53 | except Exception as e: 54 | # Log any exception that occurs in a detector 55 | logging.error(f"Error in detector {detector.__class__.__name__}: {e}") 56 | 57 | def report_packet(self, packet: Packet): 58 | """Report a suspicious packet.""" 59 | if hasattr(packet, 'ip'): 60 | report_data = { 61 | 'ipSrc': packet.ip.src, 62 | 'ipDst': packet.ip.dst, 63 | 'sniff_timestamp': packet.sniff_timestamp, 64 | 'highest_layer': packet.highest_layer, 65 | 'layer': packet.transport_layer, 66 | 'srcPort': getattr(packet[packet.transport_layer.lower()], 'srcport', ''), 67 | 'dstPort': getattr(packet[packet.transport_layer.lower()], 'dstport', '') 68 | } 69 | self.reporter.report(report_data) 70 | -------------------------------------------------------------------------------- /eye_of_snake.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from colorama import Fore, Style, init 3 | from utils.packet_capture import start_packet_capture 4 | from utils.packet_filter import PacketFilter 5 | from utils.reporter import Reporter 6 | from utils.load import load_config 7 | 8 | def print_logo(): 9 | # Initialize colorama 10 | init(autoreset=True) 11 | 12 | logo = f""" 13 | {Fore.BLUE} 14 | /$$$$$$ /$$ /$$$$$$$$ 15 | /$$__ $$ | $$ | $$_____/ 16 | | $$ \__/ /$$$$$$$ /$$$$$$ | $$ /$$ /$$$$$$ | $$ /$$ /$$ /$$$$$$ 17 | | $$$$$$ | $$__ $$ |____ $$| $$ /$$/ /$$__ $$ /$$$$$$| $$$$$ | $$ | $$ /$$__ $$ 18 | \____ $$| $$ \ $$ /$$$$$$$| $$$$$$/ | $$$$$$$$|______/| $$__/ | $$ | $$| $$$$$$$$ 19 | /$$ \ $$| $$ | $$ /$$__ $$| $$_ $$ | $$_____/ | $$ | $$ | $$| $$_____/ 20 | | $$$$$$/| $$ | $$| $$$$$$$| $$ \ $$| $$$$$$$ | $$$$$$$$| $$$$$$$| $$$$$$$ 21 | \______/ |__/ |__/ \_______/|__/ \__/ \_______/ |________/ \____ $$ \_______/ 22 | /$$ /$$ | $$ /$$ | $$ 23 | | $$ |__/ | $$ | $$$$$$/ 24 | |__/ \__/ \______/ 25 | 26 | {Fore.BLUE}Made by Mahmoud Shaker{Style.RESET_ALL} 27 | {Fore.BLUE}Welcome to Snake-Eye Network Detector\n{Style.RESET_ALL} 28 | """ 29 | print(logo) 30 | def main(): 31 | print_logo() 32 | 33 | # Load the configuration 34 | try: 35 | config = load_config('config.json') 36 | print("Configuration loaded successfully.") 37 | except Exception as e: 38 | print(f"Failed to load configuration: {e}") 39 | exit(1) 40 | 41 | # Set up logging based on the configuration 42 | try: 43 | logging.basicConfig( 44 | level=getattr(logging, config['logging']['level'].upper(), 'INFO'), 45 | filename=config['logging'].get('file', 'logs/reporter.log'), 46 | format='%(asctime)s - %(levelname)s - %(message)s' 47 | ) 48 | print("Logging configured successfully.") 49 | logging.info("Logging configured successfully.") 50 | except Exception as e: 51 | print(f"Failed to configure logging: {e}") 52 | exit(1) 53 | 54 | # Create Reporter instance 55 | try: 56 | reporter = Reporter( 57 | ip=config['api_server']['ip'], 58 | port=config['api_server']['port'], 59 | report_endpoint=config['api_server']['report_endpoint'], 60 | use_https=config['api_server']['use_https'], 61 | log_file=config['logging']['file'] 62 | ) 63 | print("Reporter instance created successfully.") 64 | logging.info("Reporter instance created successfully.") 65 | except Exception as e: 66 | print(f"Failed to create Reporter instance: {e}") 67 | logging.error(f"Failed to create Reporter instance: {e}") 68 | exit(1) 69 | 70 | # Create PacketFilter instance 71 | try: 72 | packet_filter = PacketFilter(reporter, config) 73 | print("PacketFilter instance created successfully.") 74 | except Exception as e: 75 | print(f"Failed to create PacketFilter instance: {e}") 76 | logging.error(f"Failed to create PacketFilter instance: {e}") 77 | exit(1) 78 | 79 | # Start packet capture 80 | try: 81 | interface = config['interfaces']['default'] 82 | print(f"Starting packet capture on interface {interface}") 83 | logging.info(f"Starting packet capture on interface {interface}") 84 | start_packet_capture(interface, packet_filter) 85 | except Exception as e: 86 | print(f"Failed to start packet capture: {e}") 87 | logging.error(f"Failed to start packet capture: {e}") 88 | exit(1) 89 | 90 | if __name__ == '__main__': 91 | main() 92 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "api_server": { 3 | "ip": "127.0.0.1", 4 | "port": 80, 5 | "report_endpoint": "report.php", 6 | "use_https": false 7 | }, 8 | "logging": { 9 | "level": "INFO", 10 | "file": "logs/reporter.log" 11 | }, 12 | "detection_thresholds": { 13 | "port_scan": { 14 | "threshold": 50, 15 | "window": 60, 16 | "special_threshold": 1000, 17 | "special_window": 10 18 | }, 19 | "ddos": { 20 | "threshold": 1000, 21 | "window": 10 22 | }, 23 | "mac_flooding": { 24 | "threshold": 100, 25 | "window": 10 26 | }, 27 | "arp": { 28 | "threshold": 10, 29 | "window": 60 30 | }, 31 | "icmp": { 32 | "threshold": 20, 33 | "window": 10 34 | }, 35 | "sql_injection": { 36 | "threshold": 5, 37 | "window": 60 38 | } 39 | }, 40 | "patterns": { 41 | "sql_injection": [ 42 | "' OR '1'='1", 43 | "' OR '1'='1' --", 44 | "' OR '1'='1' /*", 45 | "' OR 1=1", 46 | "' OR 'a'='a", 47 | "' OR ''='", 48 | "' OR '1'='1' -- -", 49 | "' OR 1=1 --", 50 | "' OR 1=1#", 51 | "' OR 1=1/*", 52 | "admin' --", 53 | "admin' #", 54 | "admin'/*", 55 | "' OR 'a'='a", 56 | "') OR ('a'='a", 57 | "') OR '1'='1", 58 | "' OR 'text'='text", 59 | "' OR 'x'='x", 60 | "' OR 1=1 LIMIT 1 OFFSET 1 --", 61 | "' UNION SELECT 1, 'anotheruser', 'doesnotmatter', 1--", 62 | "UNION SELECT 1, 'anotheruser', 'doesnotmatter', 1--", 63 | "' OR '' = '", 64 | "' OR 'x' = 'x", 65 | "%27+OR+%271%27%3D%271", 66 | "%27+OR+%271%27%3D%271%27+--+", 67 | "%27+OR+%271%27%3D%271%27+/*", 68 | "%27+OR+1%3D1", 69 | "%27+OR+%27a%27%3D%27a", 70 | "%27+OR+%27%27%3D%27", 71 | "%27+OR+%271%27%3D%271%27+--+-", 72 | "%27+OR+1%3D1+--+", 73 | "%27+OR+1%3D1%23", 74 | "%27+OR+1%3D1%2F*", 75 | "admin%27+--+", 76 | "admin%27+%23", 77 | "admin%27%2F*", 78 | "%27+OR+%27a%27%3D%27a", 79 | "%27%29+OR+%28%27a%27%3D%27a", 80 | "%27%29+OR+%271%27%3D%271", 81 | "%27+OR+%27text%27%3D%27text", 82 | "%27+OR+%27x%27%3D%27x", 83 | "%27+OR+1%3D1+LIMIT+1+OFFSET+1+--+", 84 | "%27+UNION+SELECT+1%2C+%27anotheruser%27%2C+%27doesnotmatter%27%2C+1--", 85 | "UNION+SELECT+1%2C+%27anotheruser%27%2C+%27doesnotmatter%27%2C+1--", 86 | "%27+OR+%27%27+%3D+%27", 87 | "%27+OR+%27x%27+%3D+%27x" 88 | ], 89 | "xss": [ 90 | "", 92 | "onerror=", 93 | "onload=", 94 | "alert", 95 | "" 96 | ], 97 | "ssti": [ 98 | "{{", 99 | "{%", 100 | "}}", 101 | "%}" 102 | ], 103 | "csrf": [ 104 | " 2 | 3 |
4 | 5 | 6 || Timestamp | 125 |Attack Type | 126 |Source IP | 127 |Destination IP | 128 |Protocol | 129 |Details | 130 |" . htmlspecialchars($report['timestamp']) . " | "; 141 | echo "" . htmlspecialchars($report['attack_type']) . " | "; 142 | echo "" . htmlspecialchars($report['src_ip']) . " | "; 143 | echo "" . htmlspecialchars($report['dst_ip']) . " | "; 144 | echo "" . htmlspecialchars($report['protocol']) . " | "; 145 | echo "" . htmlspecialchars(json_encode($report['details'])) . " | "; 146 | echo ""; 147 | } 148 | } 149 | } else { 150 | echo "
|---|---|---|---|---|---|
| No reports available. | |||||