.github/workflows | ||
contrib | ||
nix | ||
resources | ||
src | ||
.envrc | ||
.gitignore | ||
Cargo.lock | ||
Cargo.toml | ||
flake.lock | ||
flake.nix | ||
README.md |
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
- Eris receives all incoming HTTP requests
- It analyzes each request against its list of trap patterns
- Legitimate requests are proxied directly to your backend server
- 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
- 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):
- All traffic hits Eris first (on port 80)
- Eris inspects each request against its trap patterns
- Malicious requests get tarpitted by Eris
- Legitimate requests get proxied to Nginx on port 8080
- 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 responsesphp_exploit.txt
- PHP-specific error messageswordpress.txt
- WordPress-style responsesapi.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 pathseris_blocked_ips
- Number of IPs permanently blockederis_active_connections
- Number of currently active connections in tarpiteris_path_hits_total
- Hits by patheris_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.