From 72f729399567004463d8ebdfb0b2a359cee49168 Mon Sep 17 00:00:00 2001 From: Phillip Tarrant Date: Wed, 24 Dec 2025 10:25:00 -0600 Subject: [PATCH] added attack classification, added attack types to stats and dashboard, also added a tiny curl script to simulate attacks for testing purposes --- src/dashboard_template.py | 214 ---------------------------- src/handler.py | 11 +- src/templates/dashboard_template.py | 24 ++++ src/tracker.py | 42 +++++- tests/sim_attacks.sh | 20 +++ 5 files changed, 90 insertions(+), 221 deletions(-) delete mode 100644 src/dashboard_template.py create mode 100755 tests/sim_attacks.sh diff --git a/src/dashboard_template.py b/src/dashboard_template.py deleted file mode 100644 index 4bcde8b..0000000 --- a/src/dashboard_template.py +++ /dev/null @@ -1,214 +0,0 @@ -#!/usr/bin/env python3 - -""" -Dashboard template for viewing honeypot statistics. -Customize this template to change the dashboard appearance. -""" - - -def generate_dashboard(stats: dict) -> str: - """Generate dashboard HTML with access statistics""" - - top_ips_rows = '\n'.join([ - f'{i+1}{ip}{count}' - for i, (ip, count) in enumerate(stats['top_ips']) - ]) or 'No data' - - # Generate paths rows - top_paths_rows = '\n'.join([ - f'{i+1}{path}{count}' - for i, (path, count) in enumerate(stats['top_paths']) - ]) or 'No data' - - # Generate User-Agent rows - top_ua_rows = '\n'.join([ - f'{i+1}{ua[:80]}{count}' - for i, (ua, count) in enumerate(stats['top_user_agents']) - ]) or 'No data' - - # Generate suspicious accesses rows - suspicious_rows = '\n'.join([ - f'{log["ip"]}{log["path"]}{log["user_agent"][:60]}{log["timestamp"].split("T")[1][:8]}' - for log in stats['recent_suspicious'][-10:] - ]) or 'No suspicious activity detected' - - return f""" - - - - Krawl Dashboard - - - -
-

🕷️ Krawl Dashboard

- -
-
-
{stats['total_accesses']}
-
Total Accesses
-
-
-
{stats['unique_ips']}
-
Unique IPs
-
-
-
{stats['unique_paths']}
-
Unique Paths
-
-
-
{stats['suspicious_accesses']}
-
Suspicious Accesses
-
-
- -
-

⚠️ Recent Suspicious Activity

- - - - - - - - - - - {suspicious_rows} - -
IP AddressPathUser-AgentTime
-
- -
-

Top IP Addresses

- - - - - - - - - - {top_ips_rows} - -
#IP AddressAccess Count
-
- -
-

Top Paths

- - - - - - - - - - {top_paths_rows} - -
#PathAccess Count
-
- -
-

Top User-Agents

- - - - - - - - - - {top_ua_rows} - -
#User-AgentCount
-
-
- - -""" diff --git a/src/handler.py b/src/handler.py index 2768c6b..01d1f11 100644 --- a/src/handler.py +++ b/src/handler.py @@ -197,15 +197,18 @@ class Handler(BaseHTTPRequestHandler): """Handle POST requests (mainly login attempts)""" client_ip = self._get_client_ip() user_agent = self._get_user_agent() - - self.tracker.record_access(client_ip, self.path, user_agent) - + post_data = "" + print(f"[LOGIN ATTEMPT] {client_ip} - {self.path} - {user_agent[:50]}") content_length = int(self.headers.get('Content-Length', 0)) if content_length > 0: - post_data = self.rfile.read(content_length).decode('utf-8') + post_data = self.rfile.read(content_length).decode('utf-8', errors="replace") + print(f"[POST DATA] {post_data[:200]}") + + # send the post data (body) to the record_access function so the post data can be used to detect suspicious things. + self.tracker.record_access(client_ip, self.path, user_agent, post_data) time.sleep(1) diff --git a/src/templates/dashboard_template.py b/src/templates/dashboard_template.py index d4c6421..3f5524d 100644 --- a/src/templates/dashboard_template.py +++ b/src/templates/dashboard_template.py @@ -39,6 +39,12 @@ def generate_dashboard(stats: dict) -> str: for ip, paths in stats.get('honeypot_triggered_ips', []) ]) or 'No honeypot triggers yet' + # Generate attack types rows + attack_type_rows = '\n'.join([ + f'{log["ip"]}{log["path"]}{", ".join(log["attack_types"])}{log["user_agent"][:60]}{log["timestamp"].split("T")[1][:8]}' + for log in stats.get('attack_types', [])[-10:] + ]) or 'No attacks detected' + return f""" @@ -188,6 +194,24 @@ def generate_dashboard(stats: dict) -> str: +
+

😈 Detected Attack Types

+ + + + + + + + + + + + {attack_type_rows} + +
IP AddressPathAttack TypesUser-AgentTime
+
+

Top IP Addresses

diff --git a/src/tracker.py b/src/tracker.py index 8a73a4c..6e733f4 100644 --- a/src/tracker.py +++ b/src/tracker.py @@ -3,6 +3,7 @@ from typing import Dict, List, Tuple from collections import defaultdict from datetime import datetime +import re class AccessTracker: @@ -17,17 +18,35 @@ class AccessTracker: 'scanner', 'nikto', 'sqlmap', 'nmap', 'masscan', 'nessus', 'acunetix', 'burp', 'zap', 'w3af', 'metasploit', 'nuclei', 'gobuster', 'dirbuster' ] + + # common attack types such as xss, shell injection, probes + self.attack_types = { + 'path_traversal': r'\.\.', + 'sql_injection': r"('|--|;|\bOR\b|\bUNION\b|\bSELECT\b|\bDROP\b)", + 'xss_attempt': r'( 0: + attack_findings.extend(self.detect_attack_type(body)) + + is_suspicious = self.is_suspicious_user_agent(user_agent) or self.is_honeypot_path(path) or len(attack_findings) > 0 + # Track if this IP accessed a honeypot path if self.is_honeypot_path(path): @@ -39,9 +58,20 @@ class AccessTracker: 'user_agent': user_agent, 'suspicious': is_suspicious, 'honeypot_triggered': self.is_honeypot_path(path), + 'attack_types':attack_findings, 'timestamp': datetime.now().isoformat() }) + def detect_attack_type(self, data:str) -> list[str]: + """ + Returns a list of all attack types found in path data + """ + findings = [] + for name, pattern in self.attack_types.items(): + if re.search(pattern, data, re.IGNORECASE): + findings.append(name) + return findings + def is_honeypot_path(self, path: str) -> bool: """Check if path is one of the honeypot traps from robots.txt""" honeypot_paths = [ @@ -91,6 +121,11 @@ class AccessTracker: suspicious = [log for log in self.access_log if log.get('suspicious', False)] return suspicious[-limit:] + def get_attack_type_accesses(self, limit: int = 20) -> List[Dict]: + """Get recent accesses with detected attack types""" + attacks = [log for log in self.access_log if log.get('attack_types')] + return attacks[-limit:] + def get_honeypot_triggered_ips(self) -> List[Tuple[str, List[str]]]: """Get IPs that accessed honeypot paths""" return [(ip, paths) for ip, paths in self.honeypot_triggered.items()] @@ -110,5 +145,6 @@ class AccessTracker: 'top_paths': self.get_top_paths(10), 'top_user_agents': self.get_top_user_agents(10), 'recent_suspicious': self.get_suspicious_accesses(20), - 'honeypot_triggered_ips': self.get_honeypot_triggered_ips() + 'honeypot_triggered_ips': self.get_honeypot_triggered_ips(), + 'attack_types': self.get_attack_type_accesses(20) } diff --git a/tests/sim_attacks.sh b/tests/sim_attacks.sh new file mode 100755 index 0000000..d4a72b2 --- /dev/null +++ b/tests/sim_attacks.sh @@ -0,0 +1,20 @@ +#!/bin/bash +TARGET="http://localhost:5000" + +echo "=== Testing Path Traversal ===" +curl -s "$TARGET/../../etc/passwd" + +echo -e "\n=== Testing SQL Injection ===" +curl -s -X POST "$TARGET/login" -d "user=' OR 1=1--" + +echo -e "\n=== Testing XSS ===" +curl -s -X POST "$TARGET/comment" -d "msg=" + +echo -e "\n=== Testing Common Probes ===" +curl -s "$TARGET/.env" +curl -s "$TARGET/wp-admin/" + +echo -e "\n=== Testing Shell Injection ===" +curl -s -X POST "$TARGET/ping" -d "host=127.0.0.1; cat /etc/passwd" + +echo -e "\n=== Done ===" \ No newline at end of file