diff --git a/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy b/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy index a55e46f0..49aa1824 100755 --- a/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy +++ b/package/secubox/luci-app-mitmproxy/root/usr/libexec/rpcd/luci.mitmproxy @@ -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}'; } get_alerts() { - # Read alerts from container's JSONL log file - # The analytics addon writes one JSON object per line to /var/log/crowdsec/secubox-mitm.log - local log_file="/var/log/crowdsec/secubox-mitm.log" + # Read alerts from host-visible JSONL log file + # The analytics addon writes to /data/threats.log inside container + # which is bind-mounted to /srv/mitmproxy/threats.log on host + local log_file="/srv/mitmproxy/threats.log" local max_alerts=50 local alerts_json="[]" - # Try to get last N alerts from LXC container and convert JSONL to JSON array - if command -v lxc-attach >/dev/null 2>&1; then - # Read last N lines, wrap in JSON array - local lines=$(lxc-attach -n "$LXC_NAME" -- tail -n "$max_alerts" "$log_file" 2>/dev/null) + # Read last N lines from the host-accessible log file + if [ -f "$log_file" ]; then + local lines=$(tail -n "$max_alerts" "$log_file" 2>/dev/null) if [ -n "$lines" ]; then # Convert JSONL to JSON array: join lines with commas, wrap in brackets alerts_json=$(echo "$lines" | awk ' @@ -401,12 +401,11 @@ EOFJ } clear_alerts() { - # Clear alerts in container - if command -v lxc-attach >/dev/null 2>&1; then - lxc-attach -n "$LXC_NAME" -- sh -c 'echo "[]" > /tmp/secubox-mitm-alerts.json' 2>/dev/null - fi + # Clear the host-visible threats log file + local log_file="/srv/mitmproxy/threats.log" + > "$log_file" 2>/dev/null - # Also clear on host + # Also clear the legacy alerts file echo "[]" > /tmp/secubox-mitm-alerts.json 2>/dev/null echo '{"success":true,"message":"Alerts cleared"}' diff --git a/package/secubox/secubox-app-crowdsec-custom/files/acquis.d/secubox-mitmproxy.yaml b/package/secubox/secubox-app-crowdsec-custom/files/acquis.d/secubox-mitmproxy.yaml new file mode 100644 index 00000000..b85d87d0 --- /dev/null +++ b/package/secubox/secubox-app-crowdsec-custom/files/acquis.d/secubox-mitmproxy.yaml @@ -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 diff --git a/package/secubox/secubox-app-crowdsec-custom/files/parsers/s01-parse/secubox-mitmproxy.yaml b/package/secubox/secubox-app-crowdsec-custom/files/parsers/s01-parse/secubox-mitmproxy.yaml new file mode 100644 index 00000000..54fd117f --- /dev/null +++ b/package/secubox/secubox-app-crowdsec-custom/files/parsers/s01-parse/secubox-mitmproxy.yaml @@ -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 diff --git a/package/secubox/secubox-app-crowdsec-custom/files/scenarios/secubox-mitmproxy-threats.yaml b/package/secubox/secubox-app-crowdsec-custom/files/scenarios/secubox-mitmproxy-threats.yaml new file mode 100644 index 00000000..454697a8 --- /dev/null +++ b/package/secubox/secubox-app-crowdsec-custom/files/scenarios/secubox-mitmproxy-threats.yaml @@ -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 diff --git a/package/secubox/secubox-app-mitmproxy/root/srv/mitmproxy/addons/secubox_analytics.py b/package/secubox/secubox-app-mitmproxy/root/srv/mitmproxy/addons/secubox_analytics.py index c83d6f93..893ee832 100644 --- a/package/secubox/secubox-app-mitmproxy/root/srv/mitmproxy/addons/secubox_analytics.py +++ b/package/secubox/secubox-app-mitmproxy/root/srv/mitmproxy/addons/secubox_analytics.py @@ -19,7 +19,9 @@ from pathlib import Path # GeoIP database path (MaxMind GeoLite2) GEOIP_DB = "/srv/mitmproxy/GeoLite2-Country.mmdb" 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" STATS_FILE = "/tmp/secubox-mitm-stats.json"