Sophisticated HTTP tarpit and honeypot stream designed to protect, delay and block malicious bots
Find a file
2025-05-02 06:01:17 +03:00
contrib meta: add contrib 2025-05-01 18:00:18 +03:00
nix nix: add missing config option 2025-05-01 21:19:03 +03:00
resources eris: move lua API to standalone module 2025-05-02 05:45:14 +03:00
src eris/lua: apply clippy lints 2025-05-02 06:01:17 +03:00
.envrc nix: init tooling 2025-05-01 05:04:43 +03:00
.gitignore meta: ignore artifact dirs 2025-05-01 05:08:07 +03:00
Cargo.lock eris: move lua API to standalone module 2025-05-02 05:45:14 +03:00
Cargo.toml eris: move lua API to standalone module 2025-05-02 05:45:14 +03:00
flake.lock nix: init tooling 2025-05-01 05:04:43 +03:00
flake.nix nix: export nixos module 2025-05-01 05:55:29 +03:00
README.md docs: add project readme 2025-05-01 18:00:19 +03:00

Eris

This is a sophisticated HTTP tarpit and honeypot stream designed to protect, delay, block and dare I say troll malicious scanners and vulnerability probes while protecting legitimate web traffic.

How Does It Work?

Eris works by sitting in front of your web server, intercepting all incoming HTTP requests and:

  • Allowing legitimate requests to pass through to your actual web server
  • Trapping and delaying malicious requests using a tarpit technique
  • Blocking repeat offenders at the firewall level (goodbye fail2ban)

Process Flow

  1. Eris receives all incoming HTTP requests
  2. It analyzes each request against its list of trap patterns
  3. Legitimate requests are proxied directly to your backend server
  4. Suspicious requests are tarpitted:
    • Response is sent painfully slowly, byte-by-byte with random delays
    • Deceptive content is generated to waste attacker time
    • Connections are held open for extended periods to consume attacker resources
  5. Repeat offenders are automatically blocked at the firewall level

Why Use Eris?

Traditional web application firewalls simply block malicious requests, which immediately alerts attackers they've been detected. Eris takes a deceptive approach:

  • Wastes attacker time and resources on fake responses
  • Collects data about attack patterns and techniques
  • Reduces server load by handling malicious traffic efficiently
  • Provides valuable metrics and insights about attack traffic

Key Features

The design I had in mind was minimal, but more features crept in while I was fixing things on to go. More features to come as I see fit.

  • Low-overhead tarpit: Delays responses to suspicious requests byte-by-byte with random delays
  • Markov chain response generation: Creates realistic-looking fake responses to deceive attackers (success my vary depending on how sophisticated the attackers are)
  • Firewall integration: Automatically blocks repeat offenders using nftables (iptables is legacy, and not supported)
  • Customizable response scripts: Using Lua scripting to generate deceptive responses
  • Prometheus metrics: Tracks and exposes honeypot activity

Installation

From Source

# Clone the repository
git clone https://github.com/notashelf/eris
cd eris

# Build the binary
cargo build --release

# Create necessary directories
mkdir -p ~/.local/share/eris/data
mkdir -p ~/.local/share/eris/corpora
mkdir -p ~/.local/share/eris/scripts

Pre-built Binaries

Pre-built binaries are not yet available.

Deployment Architecture

Static Sites

For static sites served by Nginx, the proper setup is to place Eris in front of Nginx. Here is a graph of how it's meant to be configured:

Internet → [Eris (port 80)] → [Nginx (local port)]

You will want to configure Eris to listen on port 80 (or 443 for SSL) and forward legitimate traffic to Nginx running on a local port:

# Run Eris on port 80, forwarding legitimate requests to Nginx on port 8080
eris --listen-addr 0.0.0.0:80 --backend-addr 127.0.0.1:8080

Then, configure Nginx to serve your static site on the local port:

server {
    # XXX: Nginx listens on local port only and it is
    # not exposed to internet
    listen 127.0.0.1:8080;
    server_name example.com;

    root /var/www/example.com; # your site's source
    index index.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

With the setup above, several things will happen (in this order):

  1. All traffic hits Eris first (on port 80)
  2. Eris inspects each request against its trap patterns
  3. Malicious requests get tarpitted by Eris
  4. Legitimate requests get proxied to Nginx on port 8080
  5. Nginx serves your static content as usual

HTTPS Support

For HTTPS, you have two options:

Option 1: Terminate SSL at Eris

# SSL termination at Eris (requires cert files)
eris --listen-addr 0.0.0.0:443 --backend-addr 127.0.0.1:8080 --ssl-cert /path/to/cert.pem --ssl-key /path/to/key.pem

Option 2: Use a separate SSL terminator

Internet → [SSL Terminator (port 443)] → [Eris (local port)] → [Nginx (local port)]

You can use Nginx, HAProxy, or Caddy as the SSL terminator, forwarding decrypted traffic to Eris.

Configuration

Command Line Options

USAGE:
    eris [OPTIONS]

OPTIONS:
    --listen-addr <ADDR>         Address to listen on [default: 0.0.0.0:8888]
    --metrics-port <PORT>        Port for Prometheus metrics [default: 9100]
    --backend-addr <ADDR>        Address of backend server [default: 127.0.0.1:80]
    --min-delay <MS>             Minimum delay between tarpit bytes in ms [default: 1000]
    --max-delay <MS>             Maximum delay between tarpit bytes in ms [default: 15000]
    --max-tarpit-time <SEC>      Maximum time to hold a tarpit connection in seconds [default: 600]
    --block-threshold <COUNT>    Block IPs after this many hits [default: 3]
    --base-dir <PATH>            Base directory for all files (optional)
    --config-file <FILE>         JSON configuration file (optional)
    --log-level <LEVEL>          Log level (debug, info, warn, error) [default: info]

JSON Configuration File

For more complex configurations, use a JSON configuration file:

{
  "listen_addr": "0.0.0.0:8888",
  "metrics_port": 9100,
  "backend_addr": "127.0.0.1:80",
  "min_delay": 1000,
  "max_delay": 15000,
  "max_tarpit_time": 600,
  "block_threshold": 3,
  "trap_patterns": [
    "/vendor/phpunit",
    "eval-stdin.php",
    "/wp-admin",
    "/wp-login.php",
    "/xmlrpc.php",
    "/phpMyAdmin",
    "/solr/",
    "/.env",
    "/config",
    "/api/",
    "/actuator/"
  ],
  "whitelist_networks": [
    "192.168.0.0/16",
    "10.0.0.0/8",
    "172.16.0.0/12",
    "127.0.0.0/8"
  ],
  "markov_corpora_dir": "./corpora",
  "lua_scripts_dir": "./scripts",
  "data_dir": "./data"
}

Extending and Customizing

Adding Trap Patterns

Edit your configuration file to add additional trap patterns:

"trap_patterns": [
  "/vendor/phpunit",
  "eval-stdin.php",
  "/wp-admin",
  "/wp-login.php",
  "/xmlrpc.php",
  "/phpMyAdmin",
  "/solr/",
  "/.env",
  "/config",
  "/api/",
  "/actuator/",
  "/wp-content/debug.log",
  "/cgi-bin/",
  "/admin/"
]

Custom Response Generation with Lua

Warning

The Lua API is experimental, and might be subject to change. Breaking changes will be

Create Lua scripts in your lua_scripts_dir to customize response generation:

-- honeypot.lua
function generate_honeytoken(token)
    local token_types = {"API_KEY", "AUTH_TOKEN", "SESSION_ID", "SECRET_KEY"}
    local prefix = token_types[math.random(#token_types)]
    local suffix = string.format("%08x", math.random(0xffffff))
    return prefix .. "_" .. token .. "_" .. suffix
end

function enhance_response(text, response_type, path, token)
    local result = text
    local honeytoken = generate_honeytoken(token)

    if response_type == "php_exploit" then
        result = result .. "\n<?php /* Debug mode enabled */ ?>"
        result = result .. "\n<!-- DEBUG TOKEN: " .. honeytoken .. " -->"
    elseif response_type == "wordpress" then
        result = result .. "\n<!-- WordPress debug: DB_PASSWORD='" .. honeytoken .. "' -->"
    elseif response_type == "api" then
        result = '{"error":"Unauthorized","message":"Invalid credentials",'
        result = result .. '"debug_token":"' .. honeytoken .. '"}'
    else
        result = result .. "\n<!-- Server: Apache/2.4.41 PHP/7.4.3 -->"
        result = result .. "\n<!-- Debug: " .. honeytoken .. " -->"
    end

    return result
end

Custom Markov Response Corpus

Create text files in your markov_corpora_dir to provide custom text for response generation:

  • generic.txt - Default responses
  • php_exploit.txt - PHP-specific error messages
  • wordpress.txt - WordPress-style responses
  • api.txt - API error messages

Metrics and Monitoring

Eris exposes Prometheus metrics on the configured metrics port (default: 9100):

  • eris_hits_total - Total number of hits to honeypot paths
  • eris_blocked_ips - Number of IPs permanently blocked
  • eris_active_connections - Number of currently active connections in tarpit
  • eris_path_hits_total - Hits by path
  • eris_ua_hits_total - Hits by user agent

View current status at: http://your-server:9100/status

Additional Security Considerations

Internally, Eris is designed with security and maximum performance in mind. Additionally you might want to consider:

  • Running Eris as a non-privileged user
  • Placing Eris behind a CDN or DDoS protection service for high-traffic sites
  • Regularly reviewing logs to identify new attack patterns (and keeping verbose NGINX logs)
  • Hiding the metrics endpoint from public access

License

This project is licensed under the MIT License - see the LICENSE file for details.