300 lines
8.7 KiB
Markdown
300 lines
8.7 KiB
Markdown
# 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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```nginx
|
|
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
|
|
|
|
```bash
|
|
# 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:
|
|
|
|
```json
|
|
{
|
|
"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:
|
|
|
|
```json
|
|
"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:
|
|
|
|
```lua
|
|
-- 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.
|