diff --git a/package/secubox/luci-app-secubox-security-threats/root/usr/libexec/rpcd/luci.secubox-security-threats b/package/secubox/luci-app-secubox-security-threats/root/usr/libexec/rpcd/luci.secubox-security-threats index b9e53df0..d23ffb67 100755 --- a/package/secubox/luci-app-secubox-security-threats/root/usr/libexec/rpcd/luci.secubox-security-threats +++ b/package/secubox/luci-app-secubox-security-threats/root/usr/libexec/rpcd/luci.secubox-security-threats @@ -57,6 +57,28 @@ get_crowdsec_alerts() { $CSCLI alerts list -o json --limit 100 2>/dev/null || echo '[]' } +# Get mitmproxy threats (last 50 from threats.log) +get_mitmproxy_threats() { + local log_file="/srv/mitmproxy/threats.log" + [ ! -f "$log_file" ] && return + + # Get last 50 unique threats by IP and convert to unified format + tail -50 "$log_file" 2>/dev/null | jq -sc ' + map({ + ip: .source_ip, + mac: "N/A", + timestamp: .timestamp, + risk_score: (if .severity == "critical" then 90 elif .severity == "high" then 70 elif .severity == "medium" then 50 else 30 end), + severity: .severity, + category: (if .type == "path_scan" then "anomaly" else "web_attack" end), + source: "mitmproxy", + netifyd: {application: "HTTP", protocol: "TCP", risks: [.type], risk_count: 1, bytes: 0, packets: 0}, + crowdsec: {has_decision: false, decision: null, has_alert: false, alert_count: 0, scenarios: ""}, + mitmproxy: {request: .request, host: .host, pattern: .pattern, country: .country, is_bot: .is_bot, bot_type: .bot_type, response_code: .response_code} + }) | unique_by(.ip) | .[] + ' 2>/dev/null +} + # ============================================================================== # CLASSIFICATION # ============================================================================== @@ -493,39 +515,28 @@ case "$1" in ;; get_active_threats) - # Main correlation workflow - local netifyd_data=$(get_netifyd_flows) - local risky_flows=$(filter_risky_flows "$netifyd_data") + # Get mitmproxy threats from threats.log (primary source for WAN protection) + _log_file="/srv/mitmproxy/threats.log" + _threats_json="[]" - # Only fetch CrowdSec data if available - local decisions='[]' - local alerts='[]' - if [ -x "$CSCLI" ]; then - decisions=$(get_crowdsec_decisions) - alerts=$(get_crowdsec_alerts) + if [ -f "$_log_file" ]; then + _threats_json=$(tail -50 "$_log_file" 2>/dev/null | jq -sc ' + map({ + ip: .source_ip, + mac: "N/A", + timestamp: .timestamp, + risk_score: (if .severity == "critical" then 90 elif .severity == "high" then 70 elif .severity == "medium" then 50 else 30 end), + severity: .severity, + category: (if .type == "path_scan" then "anomaly" else "web_attack" end), + source: "mitmproxy", + netifyd: {application: "HTTP", protocol: "TCP", risks: [.type], risk_count: 1, bytes: 0, packets: 0}, + crowdsec: {has_decision: false, decision: null, has_alert: false, alert_count: 0, scenarios: ""}, + mitmproxy: {request: .request, host: .host, pattern: .pattern, country: .country, is_bot: .is_bot, bot_type: .bot_type, cve: .cve, response_code: .response_code} + }) | unique_by(.ip) | sort_by(.risk_score) | reverse + ' 2>/dev/null || echo "[]") fi - # Correlate threats - local threats=$(correlate_threats "$risky_flows" "$decisions" "$alerts") - - # Check auto-block rules for each threat - if [ -n "$threats" ]; then - echo "$threats" | while read -r threat; do - [ -z "$threat" ] && continue - check_block_rules "$threat" >/dev/null 2>&1 || true - done - fi - - # Output as JSON array - json_init - json_add_array "threats" - if [ -n "$threats" ]; then - echo "$threats" | jq -s 'sort_by(.risk_score) | reverse' | jq -c '.[]' | while read -r threat; do - echo "$threat" - done - fi - json_close_array - json_dump + printf '{"threats":%s}\n' "$_threats_json" ;; get_threat_history) 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 faa3e727..d930a484 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 @@ -308,8 +308,25 @@ CVE_PATTERNS = { 'screenconnect': [r'/SetupWizard\.aspx'], # CVE-2024-27198 (TeamCity) 'teamcity': [r'/app/rest/users/id:', r'/app/rest/server'], + # CVE-2025-15467 (OpenSSL CMS AuthEnvelopedData stack overflow) + # Targets S/MIME, CMS endpoints with potentially malicious payloads + 'CVE-2025-15467': [ + r'/smime', r'/s-mime', r'/cms/', r'/pkcs7', + r'/api/mail', r'/mail/send', r'/email/compose', + r'/decrypt', r'/verify-signature', r'/enveloped', + ], } +# Content-Type patterns for CVE-2025-15467 (CMS/S/MIME attacks) +CMS_CONTENT_TYPES = [ + 'application/pkcs7-mime', + 'application/pkcs7-signature', + 'application/x-pkcs7-mime', + 'application/x-pkcs7-signature', + 'application/cms', + 'multipart/signed', +] + class SecuBoxAnalytics: def __init__(self): self.geoip = None @@ -543,6 +560,18 @@ class SecuBoxAnalytics: 'severity': 'critical', 'category': 'xml_attack' } + # Check CVE-2025-15467 (OpenSSL CMS AuthEnvelopedData stack overflow) + # Detect potential exploitation attempts via S/MIME/CMS content + if any(ct in content_type for ct in CMS_CONTENT_TYPES): + # Flag all CMS/S/MIME content as potential CVE-2025-15467 target + # Especially suspicious if body is large (oversized IV attack) + severity = 'critical' if len(body) > 1024 else 'high' + return { + 'is_scan': True, 'pattern': 'CVE-2025-15467', 'type': 'cve_exploit', + 'severity': severity, 'category': 'cms_attack', + 'cve': 'CVE-2025-15467' + } + # Check LDAP Injection for pattern in LDAP_INJECTION_PATTERNS: if re.search(pattern, combined, re.IGNORECASE):