2025-12-14 19:08:01 +01:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
Main server module for the deception honeypot.
|
|
|
|
|
Run this file to start the server.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
import sys
|
|
|
|
|
from http.server import HTTPServer
|
|
|
|
|
|
2026-01-04 22:20:10 +01:00
|
|
|
from config import get_config
|
2025-12-14 19:08:01 +01:00
|
|
|
from tracker import AccessTracker
|
2026-01-04 19:12:23 +01:00
|
|
|
from analyzer import Analyzer
|
2025-12-14 19:08:01 +01:00
|
|
|
from handler import Handler
|
2025-12-27 19:17:27 +01:00
|
|
|
from logger import initialize_logging, get_app_logger, get_access_logger, get_credential_logger
|
2025-12-28 10:43:32 -06:00
|
|
|
from database import initialize_database
|
2025-12-14 19:08:01 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def print_usage():
|
|
|
|
|
"""Print usage information"""
|
|
|
|
|
print(f'Usage: {sys.argv[0]} [FILE]\n')
|
|
|
|
|
print('FILE is file containing a list of webpage names to serve, one per line.')
|
|
|
|
|
print('If no file is provided, random links will be generated.\n')
|
2026-01-04 22:20:10 +01:00
|
|
|
print('Configuration:')
|
|
|
|
|
print(' Configuration is loaded from a YAML file (default: config.yaml)')
|
|
|
|
|
print(' Set CONFIG_LOCATION environment variable to use a different file.\n')
|
|
|
|
|
print(' Example config.yaml structure:')
|
|
|
|
|
print(' server:')
|
|
|
|
|
print(' port: 5000')
|
|
|
|
|
print(' delay: 100')
|
|
|
|
|
print(' timezone: null # or "America/New_York"')
|
|
|
|
|
print(' links:')
|
|
|
|
|
print(' min_length: 5')
|
|
|
|
|
print(' max_length: 15')
|
|
|
|
|
print(' min_per_page: 10')
|
|
|
|
|
print(' max_per_page: 15')
|
|
|
|
|
print(' canary:')
|
|
|
|
|
print(' token_url: null')
|
|
|
|
|
print(' token_tries: 10')
|
|
|
|
|
print(' dashboard:')
|
|
|
|
|
print(' secret_path: null # auto-generated if not set')
|
|
|
|
|
print(' database:')
|
|
|
|
|
print(' path: "data/krawl.db"')
|
|
|
|
|
print(' retention_days: 30')
|
|
|
|
|
print(' behavior:')
|
|
|
|
|
print(' probability_error_codes: 0')
|
2025-12-14 19:08:01 +01:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
"""Main entry point for the deception server"""
|
|
|
|
|
if '-h' in sys.argv or '--help' in sys.argv:
|
|
|
|
|
print_usage()
|
|
|
|
|
exit(0)
|
|
|
|
|
|
2026-01-04 22:20:10 +01:00
|
|
|
config = get_config()
|
|
|
|
|
|
2025-12-28 17:07:18 +01:00
|
|
|
# Get timezone configuration
|
|
|
|
|
tz = config.get_timezone()
|
2026-01-04 22:20:10 +01:00
|
|
|
|
2025-12-28 17:07:18 +01:00
|
|
|
# Initialize logging with timezone
|
|
|
|
|
initialize_logging(timezone=tz)
|
2025-12-26 08:23:38 -06:00
|
|
|
app_logger = get_app_logger()
|
|
|
|
|
access_logger = get_access_logger()
|
2025-12-27 19:17:27 +01:00
|
|
|
credential_logger = get_credential_logger()
|
2025-12-26 08:23:38 -06:00
|
|
|
|
2025-12-28 10:43:32 -06:00
|
|
|
# Initialize database for persistent storage
|
|
|
|
|
try:
|
|
|
|
|
initialize_database(config.database_path)
|
|
|
|
|
app_logger.info(f'Database initialized at: {config.database_path}')
|
|
|
|
|
except Exception as e:
|
|
|
|
|
app_logger.warning(f'Database initialization failed: {e}. Continuing with in-memory only.')
|
|
|
|
|
|
2025-12-28 17:07:18 +01:00
|
|
|
tracker = AccessTracker(timezone=tz)
|
2026-01-04 19:12:23 +01:00
|
|
|
analyzer = Analyzer(timezone=tz)
|
2025-12-26 08:23:38 -06:00
|
|
|
|
2025-12-14 19:08:01 +01:00
|
|
|
Handler.config = config
|
|
|
|
|
Handler.tracker = tracker
|
2026-01-04 19:12:23 +01:00
|
|
|
Handler.analyzer = analyzer
|
2025-12-14 19:08:01 +01:00
|
|
|
Handler.counter = config.canary_token_tries
|
2025-12-26 08:23:38 -06:00
|
|
|
Handler.app_logger = app_logger
|
|
|
|
|
Handler.access_logger = access_logger
|
2025-12-27 19:17:27 +01:00
|
|
|
Handler.credential_logger = credential_logger
|
2025-12-14 19:08:01 +01:00
|
|
|
|
|
|
|
|
if len(sys.argv) == 2:
|
|
|
|
|
try:
|
|
|
|
|
with open(sys.argv[1], 'r') as f:
|
|
|
|
|
Handler.webpages = f.readlines()
|
|
|
|
|
|
|
|
|
|
if not Handler.webpages:
|
2025-12-26 08:23:38 -06:00
|
|
|
app_logger.warning('The file provided was empty. Using randomly generated links.')
|
2025-12-14 19:08:01 +01:00
|
|
|
Handler.webpages = None
|
|
|
|
|
except IOError:
|
2025-12-26 08:23:38 -06:00
|
|
|
app_logger.warning("Can't read input file. Using randomly generated links.")
|
2025-12-14 19:08:01 +01:00
|
|
|
|
|
|
|
|
try:
|
2025-12-26 08:23:38 -06:00
|
|
|
app_logger.info(f'Starting deception server on port {config.port}...')
|
2025-12-28 17:07:18 +01:00
|
|
|
app_logger.info(f'Timezone configured: {tz.key}')
|
2025-12-26 08:23:38 -06:00
|
|
|
app_logger.info(f'Dashboard available at: {config.dashboard_secret_path}')
|
2025-12-14 19:08:01 +01:00
|
|
|
if config.canary_token_url:
|
2025-12-26 08:23:38 -06:00
|
|
|
app_logger.info(f'Canary token will appear after {config.canary_token_tries} tries')
|
2025-12-14 19:08:01 +01:00
|
|
|
else:
|
2025-12-26 08:23:38 -06:00
|
|
|
app_logger.info('No canary token configured (set CANARY_TOKEN_URL to enable)')
|
|
|
|
|
|
2025-12-14 19:08:01 +01:00
|
|
|
server = HTTPServer(('0.0.0.0', config.port), Handler)
|
2025-12-26 08:23:38 -06:00
|
|
|
app_logger.info('Server started. Use <Ctrl-C> to stop.')
|
2025-12-14 19:08:01 +01:00
|
|
|
server.serve_forever()
|
|
|
|
|
except KeyboardInterrupt:
|
2025-12-26 08:23:38 -06:00
|
|
|
app_logger.info('Stopping server...')
|
2025-12-14 19:08:01 +01:00
|
|
|
server.socket.close()
|
2025-12-26 08:23:38 -06:00
|
|
|
app_logger.info('Server stopped')
|
2025-12-14 19:08:01 +01:00
|
|
|
except Exception as e:
|
2025-12-26 08:23:38 -06:00
|
|
|
app_logger.error(f'Error starting HTTP server on port {config.port}: {e}')
|
|
|
|
|
app_logger.error(f'Make sure you are root, if needed, and that port {config.port} is open.')
|
2025-12-14 19:08:01 +01:00
|
|
|
exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
main()
|