This repository has been archived on 2026-03-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
oubliette/PLAN.md
Torjus Håkestad d655968216 feat: add SQLite storage for login attempts and sessions
Adds persistent storage using modernc.org/sqlite (pure Go). Login
attempts are deduplicated by (username, password, ip) with counts.
Sessions and session logs are tracked with UUID IDs. Includes embedded
SQL migrations, configurable retention with background pruning, and
an in-memory store for tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 17:33:45 +01:00

7.3 KiB

Oubliette - SSH Honeypot

A fun SSH honeypot that logs login attempts, presents fake shells to "successful" logins, and tries to detect when a real human is poking around.

The name comes from the medieval dungeon concept - a place you throw people into and forget about them.

Tech Stack

  • Language: Go
  • SSH: golang.org/x/crypto/ssh
  • Database: SQLite
  • Web UI: Go templates + htmx
  • Deployment: Single binary with embedded assets

Core Concepts

Shell Profiles

Logins that "succeed" are routed to a fake shell. Shells are selected by weighted random from a registry. Each shell implements a common interface, making it easy to add new ones.

type Shell interface {
    Name() string
    Description() string
    Handle(ctx context.Context, ch ssh.Channel) error
}

Smart Storage

To avoid the database growing unbounded on a small VPS:

  • Deduplication: Store unique (username, password, IP) combinations with a count + first_seen/last_seen timestamps instead of one row per attempt.
  • Retention policy: Configurable auto-pruning of records older than N days.
  • Aggregation: Optionally roll up old raw data into daily summary tables before pruning.

Human Detection

Score sessions based on signals that distinguish humans from bots:

  • Keystroke timing (variable delays vs instant paste)
  • Typos and backspace usage
  • Tab completion and arrow key usage
  • Adaptive behavior (commands that respond to previous output)
  • Command diversity
  • Session duration

Sessions crossing a human-likelihood threshold get flagged for review and can trigger webhook notifications.

Login Realism

  • Don't accept every attempt. Most attempts should fail. Bots commonly try thousands of combinations from a single IP (20k+ is not unusual), so the acceptance threshold should be high and configurable.
  • Credential memory: When a credential is accepted, store it as a "valid" credential for a configurable TTL (e.g. 24-72 hours). If the same bot returns with the same username/password, it gets in immediately - making the credential appear legitimate and encouraging further interaction.
  • Acceptance strategy is configurable: after N failed attempts from an IP, accept the next attempt (whatever the credentials are) and remember that combo.
  • Optionally also support a static list of always-accepted credentials for testing.

Phase 1 - Foundation

Goal: A working SSH honeypot that logs attempts, stores them in SQLite, and can present a basic fake shell. Minimal but functional.

1.1 Project Setup

  • Go module, directory structure, basic configuration (YAML or TOML)
  • Configuration for: listen address, SSH host key path/auto-generation, database path, web UI listen address
  • Nix flake with devshell and package output
  • NixOS module for easy deployment (listen address, config path, state directory, etc.)

1.2 SSH Server

  • Listen for SSH connections using x/crypto/ssh
  • Handle authentication callbacks
  • Log all login attempts (username, password, source IP, timestamp)
  • Configurable credential list that triggers "successful" login
  • Basic login realism: reject first N attempts before accepting

1.3 SQLite Storage

  • Schema: login_attempts table with deduplication (username, password, ip, count, first_seen, last_seen)
  • Schema: sessions table for successful logins (id, ip, username, shell_name, connected_at, disconnected_at, human_score)
  • Schema: session_logs table for command logging (session_id, timestamp, input, output)
  • Retention policy: background goroutine that prunes old records on a schedule
  • Database migrations: Version-tracked migrations using embedded SQL files. Store current schema version in a schema_version table, apply pending migrations on startup. Keep it simple - no external migration tool, just sequential numbered .sql files embedded in the binary.

1.4 Shell Interface & Registry

  • Shell interface definition
  • Registry with weighted random selection
  • Shells receive a configuration struct with common settings from the config file: hostname, banner/MOTD, fake username, and any shell-specific options
  • Basic bash-like shell:
    • Prompt that looks like user@hostname:~$
    • Handful of commands: ls, cd, cat, pwd, whoami, uname, id, exit
    • Fake filesystem with a few interesting-looking files
    • Log all input/output to the session_logs table

1.5 Minimal Web UI

  • Embedded static assets (Go embed)
  • Dashboard: total attempts, attempts over time, unique IPs
  • Tables: top usernames, top passwords, top source IPs
  • List of active/recent sessions

Phase 2 - Detection & Notification

Goal: Detect likely-human sessions and make the system smarter.

2.1 Human Detection Scoring

  • Keystroke timing analysis
  • Track backspace, tab, arrow key usage
  • Command diversity scoring
  • Compute per-session human score, store in sessions table
  • Flag sessions above configurable threshold

2.2 Notifications

  • Webhook support (generic HTTP POST, works with Slack/Discord/ntfy)
  • Trigger on: human score threshold crossed, new session started, configurable
  • Include session details in payload

2.3 Session Replay

  • Store keystroke-by-keystroke data with timing information
  • Web UI: replay a session in a terminal-like viewer, watching commands play back in real-time
  • Filter/sort sessions by human score

2.4 Adaptive Shell Routing

  • If early keystrokes suggest a bot, route to basic shell or disconnect
  • If keystrokes suggest a human, route to a more interesting shell

Phase 3 - Fun Shells

Goal: Add the entertaining shell implementations.

3.1 Bash Shell Variations

  • Infinite sudo: always asks for password, never works, logs every attempt
  • Slow decay: shell gets progressively slower, commands take longer and longer
  • Haunted: commands gradually return stranger output, files appear/disappear, whoami returns different users
  • Bread crumbs: fake .bash_history, id_rsa files, database configs pointing to other honeypots

3.2 Cisco IOS Shell

  • Realistic > and # prompts
  • Common commands: show running-config, show interfaces, enable, configure terminal
  • Fake device info that looks like a real router

3.3 Smart Fridge Shell

  • Samsung FridgeOS boot banner
  • Inventory management commands
  • Temperature warnings
  • "WARNING: milk expires in 2 days"
  • Easter eggs

3.4 Text Adventure

  • Zork-style dungeon crawler
  • "You are in a dimly lit server room."
  • Navigation, items, puzzles
  • The dungeon is the oubliette itself

3.5 Other Shell Ideas (Future)

  • Banking TUI: 80s-style green-on-black bank terminal
  • Nuclear launch terminal: "ENTER LAUNCH AUTHORIZATION CODE"
  • ELIZA therapist: every response is a therapy question
  • Pizza ordering terminal: "Welcome to PizzaNet v2.3"
  • Haiku shell: every response is a haiku

Phase 4 - Polish

Goal: Make the web UI great and add operational niceties.

4.1 Enhanced Web UI

  • GeoIP lookups and world map visualization of attack sources
  • Charts: attempts over time, hourly patterns, credential trends
  • Session detail view with full command log
  • Filtering and search

4.2 Operational

  • Prometheus metrics endpoint
  • Structured logging (slog)
  • Graceful shutdown
  • Systemd unit file / deployment docs

4.3 GeoIP

  • Embed a lightweight GeoIP database or use an API
  • Store country/city with each attempt
  • Aggregate stats by country