feat(mitmproxy): Integrate threat detection with CrowdSec for auto-banning
- Change analytics addon to write threats to /data/threats.log (bind-mounted to host) - Add CrowdSec acquisition config to read from /srv/mitmproxy/threats.log - Add parser for mitmproxy JSON threat logs with source_ip in Meta - Add scenarios for web attacks, scanners, SSRF, and CVE exploits - Update RPCD to read alerts from host-visible path without lxc-attach This enables automatic IP banning when mitmproxy detects: - SQL injection, XSS, command injection (capacity: 3, ban: 15m) - Path traversal, XXE, LDAP injection, Log4Shell - Aggressive web scanning (capacity: 10, ban: 10m) - SSRF attempts from external IPs (capacity: 5, ban: 10m) - Known CVE exploits (immediate trigger, ban: 30m) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
88e6d04f4e
commit
7b67b0329a
@ -339,16 +339,16 @@ do_stop() { [ -x /etc/init.d/mitmproxy ] && /etc/init.d/mitmproxy stop >/dev/nul
|
|||||||
do_restart() { [ -x /etc/init.d/mitmproxy ] && /etc/init.d/mitmproxy restart >/dev/null 2>&1; echo '{"success":true}'; }
|
do_restart() { [ -x /etc/init.d/mitmproxy ] && /etc/init.d/mitmproxy restart >/dev/null 2>&1; echo '{"success":true}'; }
|
||||||
|
|
||||||
get_alerts() {
|
get_alerts() {
|
||||||
# Read alerts from container's JSONL log file
|
# Read alerts from host-visible JSONL log file
|
||||||
# The analytics addon writes one JSON object per line to /var/log/crowdsec/secubox-mitm.log
|
# The analytics addon writes to /data/threats.log inside container
|
||||||
local log_file="/var/log/crowdsec/secubox-mitm.log"
|
# which is bind-mounted to /srv/mitmproxy/threats.log on host
|
||||||
|
local log_file="/srv/mitmproxy/threats.log"
|
||||||
local max_alerts=50
|
local max_alerts=50
|
||||||
local alerts_json="[]"
|
local alerts_json="[]"
|
||||||
|
|
||||||
# Try to get last N alerts from LXC container and convert JSONL to JSON array
|
# Read last N lines from the host-accessible log file
|
||||||
if command -v lxc-attach >/dev/null 2>&1; then
|
if [ -f "$log_file" ]; then
|
||||||
# Read last N lines, wrap in JSON array
|
local lines=$(tail -n "$max_alerts" "$log_file" 2>/dev/null)
|
||||||
local lines=$(lxc-attach -n "$LXC_NAME" -- tail -n "$max_alerts" "$log_file" 2>/dev/null)
|
|
||||||
if [ -n "$lines" ]; then
|
if [ -n "$lines" ]; then
|
||||||
# Convert JSONL to JSON array: join lines with commas, wrap in brackets
|
# Convert JSONL to JSON array: join lines with commas, wrap in brackets
|
||||||
alerts_json=$(echo "$lines" | awk '
|
alerts_json=$(echo "$lines" | awk '
|
||||||
@ -401,12 +401,11 @@ EOFJ
|
|||||||
}
|
}
|
||||||
|
|
||||||
clear_alerts() {
|
clear_alerts() {
|
||||||
# Clear alerts in container
|
# Clear the host-visible threats log file
|
||||||
if command -v lxc-attach >/dev/null 2>&1; then
|
local log_file="/srv/mitmproxy/threats.log"
|
||||||
lxc-attach -n "$LXC_NAME" -- sh -c 'echo "[]" > /tmp/secubox-mitm-alerts.json' 2>/dev/null
|
> "$log_file" 2>/dev/null
|
||||||
fi
|
|
||||||
|
|
||||||
# Also clear on host
|
# Also clear the legacy alerts file
|
||||||
echo "[]" > /tmp/secubox-mitm-alerts.json 2>/dev/null
|
echo "[]" > /tmp/secubox-mitm-alerts.json 2>/dev/null
|
||||||
|
|
||||||
echo '{"success":true,"message":"Alerts cleared"}'
|
echo '{"success":true,"message":"Alerts cleared"}'
|
||||||
|
|||||||
@ -0,0 +1,10 @@
|
|||||||
|
# CrowdSec acquisition for mitmproxy threat logs
|
||||||
|
# Monitors threats detected by SecuBox mitmproxy analytics addon
|
||||||
|
# The analytics addon runs inside LXC container and writes to /data/threats.log
|
||||||
|
# which is bind-mounted to /srv/mitmproxy/threats.log on the host
|
||||||
|
|
||||||
|
source: file
|
||||||
|
filenames:
|
||||||
|
- /srv/mitmproxy/threats.log
|
||||||
|
labels:
|
||||||
|
type: mitmproxy
|
||||||
@ -0,0 +1,53 @@
|
|||||||
|
# CrowdSec parser for SecuBox mitmproxy threat logs
|
||||||
|
# Parses JSON threat events from mitmproxy analytics addon
|
||||||
|
|
||||||
|
onsuccess: next_stage
|
||||||
|
name: secubox/mitmproxy-threats
|
||||||
|
description: "Parse SecuBox mitmproxy threat detection logs (JSON)"
|
||||||
|
filter: "evt.Line.Labels.type == 'mitmproxy'"
|
||||||
|
statics:
|
||||||
|
- parsed: source_ip
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "source_ip")
|
||||||
|
- parsed: timestamp
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "timestamp")
|
||||||
|
- parsed: request
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "request")
|
||||||
|
- parsed: host
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "host")
|
||||||
|
- parsed: user_agent
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "user_agent")
|
||||||
|
- parsed: threat_type
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "type")
|
||||||
|
- parsed: pattern
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "pattern")
|
||||||
|
- parsed: category
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "category")
|
||||||
|
- parsed: severity
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "severity")
|
||||||
|
- parsed: cve
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "cve")
|
||||||
|
- parsed: response_code
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "response_code")
|
||||||
|
- parsed: is_bot
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "is_bot")
|
||||||
|
- parsed: country
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "country")
|
||||||
|
- meta: log_type
|
||||||
|
value: mitmproxy_threat
|
||||||
|
- meta: service
|
||||||
|
value: mitmproxy
|
||||||
|
- meta: source_ip
|
||||||
|
expression: JsonExtract(evt.Line.Raw, "source_ip")
|
||||||
|
---
|
||||||
|
# Filter for critical/high severity threats only (to avoid noise)
|
||||||
|
onsuccess: next_stage
|
||||||
|
name: secubox/mitmproxy-high-severity
|
||||||
|
description: "Filter high severity mitmproxy threats for banning"
|
||||||
|
filter: "evt.Meta.log_type == 'mitmproxy_threat' && evt.Parsed.severity in ['critical', 'high']"
|
||||||
|
statics:
|
||||||
|
- meta: threat_severity
|
||||||
|
expression: evt.Parsed.severity
|
||||||
|
- meta: threat_type
|
||||||
|
expression: evt.Parsed.threat_type
|
||||||
|
- meta: attack_pattern
|
||||||
|
expression: evt.Parsed.pattern
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
# CrowdSec scenario for SecuBox mitmproxy threat detection
|
||||||
|
# Triggers bans for detected attacks (SQLi, XSS, command injection, etc.)
|
||||||
|
|
||||||
|
type: leaky
|
||||||
|
name: secubox/mitmproxy-attack
|
||||||
|
description: "Detect web attacks via mitmproxy (SQLi, XSS, command injection, SSRF)"
|
||||||
|
filter: |
|
||||||
|
evt.Meta.log_type == 'mitmproxy_threat' &&
|
||||||
|
evt.Parsed.severity in ['critical', 'high'] &&
|
||||||
|
evt.Parsed.pattern in ['sql_injection', 'xss', 'command_injection', 'path_traversal', 'xxe', 'ldap_injection', 'log4shell']
|
||||||
|
groupby: evt.Meta.source_ip
|
||||||
|
capacity: 3
|
||||||
|
leakspeed: 60s
|
||||||
|
blackhole: 15m
|
||||||
|
labels:
|
||||||
|
service: mitmproxy
|
||||||
|
type: web_attack
|
||||||
|
remediation: true
|
||||||
|
---
|
||||||
|
# Detect aggressive scanning/probing
|
||||||
|
type: leaky
|
||||||
|
name: secubox/mitmproxy-scanner
|
||||||
|
description: "Detect aggressive web scanning via mitmproxy"
|
||||||
|
filter: |
|
||||||
|
evt.Meta.log_type == 'mitmproxy_threat' &&
|
||||||
|
evt.Parsed.pattern in ['admin_scanner', 'config_scan', 'backup_scan', 'env_scan']
|
||||||
|
groupby: evt.Meta.source_ip
|
||||||
|
capacity: 10
|
||||||
|
leakspeed: 30s
|
||||||
|
blackhole: 10m
|
||||||
|
labels:
|
||||||
|
service: mitmproxy
|
||||||
|
type: web_scan
|
||||||
|
remediation: true
|
||||||
|
---
|
||||||
|
# Detect SSRF attempts (more lenient - internal IPs might be legitimate)
|
||||||
|
type: leaky
|
||||||
|
name: secubox/mitmproxy-ssrf
|
||||||
|
description: "Detect SSRF attempts via mitmproxy"
|
||||||
|
filter: |
|
||||||
|
evt.Meta.log_type == 'mitmproxy_threat' &&
|
||||||
|
evt.Parsed.pattern == 'ssrf' &&
|
||||||
|
evt.Parsed.country != 'LOCAL'
|
||||||
|
groupby: evt.Meta.source_ip
|
||||||
|
capacity: 5
|
||||||
|
leakspeed: 60s
|
||||||
|
blackhole: 10m
|
||||||
|
labels:
|
||||||
|
service: mitmproxy
|
||||||
|
type: ssrf
|
||||||
|
remediation: true
|
||||||
|
---
|
||||||
|
# Detect known CVE exploitation attempts (immediate ban)
|
||||||
|
type: trigger
|
||||||
|
name: secubox/mitmproxy-cve
|
||||||
|
description: "Detect CVE exploitation attempts via mitmproxy"
|
||||||
|
filter: |
|
||||||
|
evt.Meta.log_type == 'mitmproxy_threat' &&
|
||||||
|
evt.Parsed.cve != '' &&
|
||||||
|
evt.Parsed.severity == 'critical'
|
||||||
|
blackhole: 30m
|
||||||
|
labels:
|
||||||
|
service: mitmproxy
|
||||||
|
type: cve_exploit
|
||||||
|
remediation: true
|
||||||
@ -19,7 +19,9 @@ from pathlib import Path
|
|||||||
# GeoIP database path (MaxMind GeoLite2)
|
# GeoIP database path (MaxMind GeoLite2)
|
||||||
GEOIP_DB = "/srv/mitmproxy/GeoLite2-Country.mmdb"
|
GEOIP_DB = "/srv/mitmproxy/GeoLite2-Country.mmdb"
|
||||||
LOG_FILE = "/var/log/secubox-access.log"
|
LOG_FILE = "/var/log/secubox-access.log"
|
||||||
CROWDSEC_LOG = "/var/log/crowdsec/secubox-mitm.log"
|
# CrowdSec log - uses /data which is bind-mounted to /srv/mitmproxy on host
|
||||||
|
# This allows CrowdSec on the host to read threat logs from the container
|
||||||
|
CROWDSEC_LOG = "/data/threats.log"
|
||||||
ALERTS_FILE = "/tmp/secubox-mitm-alerts.json"
|
ALERTS_FILE = "/tmp/secubox-mitm-alerts.json"
|
||||||
STATS_FILE = "/tmp/secubox-mitm-stats.json"
|
STATS_FILE = "/tmp/secubox-mitm-stats.json"
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user