From c2ea22bcab6d814688ae75e13ec8cc57596ba59c Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Tue, 13 Jan 2026 11:16:58 +0100 Subject: [PATCH] fix: CAPI registration with stale credentials cleanup - repair_lapi() now removes stale online_api_credentials.yaml and retries - New repair_capi() function for dedicated CAPI repair - console_enroll() handles CAPI credential cleanup before retry - Added repairCapi API method in frontend - Bump luci-app-crowdsec-dashboard to 0.7.0-r20 - Add openwrt-luci-bf.yaml scenario for LuCI brute force detection - Add secubox-auth-acquis.yaml acquisition config Co-Authored-By: Claude Opus 4.5 --- .../luci-app-crowdsec-dashboard/Makefile | 2 +- .../resources/crowdsec-dashboard/api.js | 7 + .../usr/libexec/rpcd/luci.crowdsec-dashboard | 141 ++++++++++++++++-- package/secubox/secubox-auth-logger/Makefile | 4 + .../files/99-secubox-auth-logger | 23 +-- .../secubox-auth-logger/files/auth-monitor.sh | 14 +- .../files/openwrt-luci-bf.yaml | 18 +++ .../files/secubox-auth-acquis.yaml | 7 + 8 files changed, 186 insertions(+), 30 deletions(-) create mode 100644 package/secubox/secubox-auth-logger/files/openwrt-luci-bf.yaml create mode 100644 package/secubox/secubox-auth-logger/files/secubox-auth-acquis.yaml diff --git a/package/secubox/luci-app-crowdsec-dashboard/Makefile b/package/secubox/luci-app-crowdsec-dashboard/Makefile index 733355a1..d15656ef 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/Makefile +++ b/package/secubox/luci-app-crowdsec-dashboard/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=luci-app-crowdsec-dashboard PKG_VERSION:=0.7.0 -PKG_RELEASE:=19 +PKG_RELEASE:=20 PKG_ARCH:=all PKG_LICENSE:=Apache-2.0 diff --git a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/api.js b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/api.js index d76236f5..66725014 100644 --- a/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/api.js +++ b/package/secubox/luci-app-crowdsec-dashboard/htdocs/luci-static/resources/crowdsec-dashboard/api.js @@ -197,6 +197,12 @@ var callRepairLapi = rpc.declare({ expect: { } }); +var callRepairCapi = rpc.declare({ + object: 'luci.crowdsec-dashboard', + method: 'repair_capi', + expect: { } +}); + var callResetWizard = rpc.declare({ object: 'luci.crowdsec-dashboard', method: 'reset_wizard', @@ -403,6 +409,7 @@ return baseclass.extend({ checkWizardNeeded: callCheckWizardNeeded, getWizardState: callWizardState, repairLapi: callRepairLapi, + repairCapi: callRepairCapi, resetWizard: callResetWizard, // Console Methods diff --git a/package/secubox/luci-app-crowdsec-dashboard/root/usr/libexec/rpcd/luci.crowdsec-dashboard b/package/secubox/luci-app-crowdsec-dashboard/root/usr/libexec/rpcd/luci.crowdsec-dashboard index 4fcce05d..c0ba33d0 100755 --- a/package/secubox/luci-app-crowdsec-dashboard/root/usr/libexec/rpcd/luci.crowdsec-dashboard +++ b/package/secubox/luci-app-crowdsec-dashboard/root/usr/libexec/rpcd/luci.crowdsec-dashboard @@ -1120,18 +1120,41 @@ repair_lapi() { # Step 13: Register with CAPI (required for console enrollment) if [ "$lapi_ok" = "1" ] && [ -x "$CSCLI" ]; then + local capi_creds="/etc/crowdsec/online_api_credentials.yaml" + local capi_registered=0 + + # First attempt: try to register with existing credentials if run_with_timeout 15 "$CSCLI" capi register >/dev/null 2>&1; then + capi_registered=1 steps_done="${steps_done}CAPI registered; " else - # CAPI registration may fail if already registered, which is OK + # Check if CAPI is already working local capi_status="" capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1) - if echo "$capi_status" | grep -qi "registered\|online"; then + if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then + capi_registered=1 steps_done="${steps_done}CAPI OK; " - else - errors="${errors}CAPI not registered; " fi fi + + # If CAPI still not working, try with fresh credentials + if [ "$capi_registered" = "0" ] && [ -f "$capi_creds" ]; then + secubox_log "CAPI registration failed, removing stale credentials and retrying..." + rm -f "$capi_creds" + steps_done="${steps_done}CAPI creds reset; " + + # Retry registration with clean slate + if run_with_timeout 15 "$CSCLI" capi register >/dev/null 2>&1; then + capi_registered=1 + steps_done="${steps_done}CAPI re-registered; " + else + local capi_err="" + capi_err=$(run_with_timeout 10 "$CSCLI" capi register 2>&1) + errors="${errors}CAPI: ${capi_err}; " + fi + elif [ "$capi_registered" = "0" ]; then + errors="${errors}CAPI not registered; " + fi fi if [ "$lapi_ok" = "1" ]; then @@ -1150,6 +1173,84 @@ repair_lapi() { json_dump } +# Repair CAPI - fix Central API registration issues +repair_capi() { + json_init + local steps_done="" + local errors="" + local capi_creds="/etc/crowdsec/online_api_credentials.yaml" + + secubox_log "Starting CAPI repair..." + + # Check if CrowdSec and LAPI are running + if ! pgrep crowdsec >/dev/null 2>&1; then + json_add_boolean "success" 0 + json_add_string "error" "CrowdSec is not running. Start CrowdSec first." + json_dump + return + fi + + if ! run_with_timeout 5 "$CSCLI" lapi status >/dev/null 2>&1; then + json_add_boolean "success" 0 + json_add_string "error" "LAPI is not available. Run LAPI repair first." + json_dump + return + fi + + # Check current CAPI status + local capi_status="" + capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1) + if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then + steps_done="${steps_done}CAPI already working; " + json_add_boolean "success" 1 + json_add_string "message" "CAPI is already connected" + json_add_string "steps" "$steps_done" + json_dump + return + fi + + # Step 1: Backup and remove existing credentials + if [ -f "$capi_creds" ]; then + cp "$capi_creds" "${capi_creds}.bak" 2>/dev/null + rm -f "$capi_creds" + steps_done="${steps_done}Removed stale credentials; " + fi + + # Step 2: Register with CAPI + local reg_output="" + reg_output=$(run_with_timeout 20 "$CSCLI" capi register 2>&1) + if [ $? -eq 0 ]; then + steps_done="${steps_done}CAPI registered; " + else + # Check if error is about already registered + if echo "$reg_output" | grep -qi "already registered"; then + steps_done="${steps_done}Already registered; " + else + errors="${errors}Registration failed: ${reg_output}; " + fi + fi + + # Step 3: Verify CAPI connection + sleep 2 + capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1) + if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then + steps_done="${steps_done}CAPI connected; " + json_add_boolean "success" 1 + json_add_string "message" "CAPI repaired successfully" + json_add_string "steps" "$steps_done" + secubox_log "CAPI repair successful: $steps_done" + else + json_add_boolean "success" 0 + json_add_string "error" "CAPI repair incomplete" + json_add_string "steps" "$steps_done" + json_add_string "errors" "$errors" + json_add_string "capi_output" "$capi_status" + secubox_log "CAPI repair failed: $errors" + fi + + json_dump +} + # Reset wizard - clean up for fresh start reset_wizard() { json_init @@ -1261,23 +1362,38 @@ console_enroll() { # Step 0: Ensure CAPI is registered (prerequisite for console enrollment) local capi_ok=0 local capi_status="" + local capi_creds="/etc/crowdsec/online_api_credentials.yaml" + capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1) - if echo "$capi_status" | grep -qi "registered\|online"; then + if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then capi_ok=1 + secubox_log "CAPI already connected" else # Try to register with CAPI - secubox_log "CAPI not registered, attempting registration..." + secubox_log "CAPI not connected, attempting registration..." if run_with_timeout 15 "$CSCLI" capi register >/dev/null 2>&1; then capi_ok=1 secubox_log "CAPI registration successful" else - json_add_boolean "success" 0 - json_add_string "error" "CAPI registration failed. Please run LAPI repair first." - json_dump - return + # If registration fails and credentials exist, try with fresh credentials + if [ -f "$capi_creds" ]; then + secubox_log "CAPI registration failed, removing stale credentials..." + rm -f "$capi_creds" + if run_with_timeout 15 "$CSCLI" capi register >/dev/null 2>&1; then + capi_ok=1 + secubox_log "CAPI re-registration successful" + fi + fi fi fi + if [ "$capi_ok" = "0" ]; then + json_add_boolean "success" 0 + json_add_string "error" "CAPI registration failed. Please run LAPI repair first." + json_dump + return + fi + # Build enroll command local enroll_cmd="run_cscli console enroll $key" if [ -n "$name" ]; then @@ -1954,7 +2070,7 @@ remove_hub_item() { # Main dispatcher case "$1" in list) - echo '{"decisions":{},"alerts":{"limit":"number"},"metrics":{},"bouncers":{},"machines":{},"hub":{},"status":{},"ban":{"ip":"string","duration":"string","reason":"string"},"unban":{"ip":"string"},"stats":{},"seccubox_logs":{},"collect_debug":{},"waf_status":{},"metrics_config":{},"configure_metrics":{"enable":"string"},"collections":{},"install_collection":{"collection":"string"},"remove_collection":{"collection":"string"},"update_hub":{},"register_bouncer":{"bouncer_name":"string"},"delete_bouncer":{"bouncer_name":"string"},"firewall_bouncer_status":{},"control_firewall_bouncer":{"action":"string"},"firewall_bouncer_config":{},"update_firewall_bouncer_config":{"key":"string","value":"string"},"nftables_stats":{},"check_wizard_needed":{},"wizard_state":{},"repair_lapi":{},"reset_wizard":{},"console_status":{},"console_enroll":{"key":"string","name":"string"},"console_disable":{},"service_control":{"action":"string"},"configure_acquisition":{"syslog_enabled":"string","firewall_enabled":"string","ssh_enabled":"string","http_enabled":"string","syslog_path":"string"},"acquisition_config":{},"acquisition_metrics":{},"health_check":{},"capi_metrics":{},"hub_available":{},"install_hub_item":{"item_type":"string","item_name":"string"},"remove_hub_item":{"item_type":"string","item_name":"string"}}' + echo '{"decisions":{},"alerts":{"limit":"number"},"metrics":{},"bouncers":{},"machines":{},"hub":{},"status":{},"ban":{"ip":"string","duration":"string","reason":"string"},"unban":{"ip":"string"},"stats":{},"seccubox_logs":{},"collect_debug":{},"waf_status":{},"metrics_config":{},"configure_metrics":{"enable":"string"},"collections":{},"install_collection":{"collection":"string"},"remove_collection":{"collection":"string"},"update_hub":{},"register_bouncer":{"bouncer_name":"string"},"delete_bouncer":{"bouncer_name":"string"},"firewall_bouncer_status":{},"control_firewall_bouncer":{"action":"string"},"firewall_bouncer_config":{},"update_firewall_bouncer_config":{"key":"string","value":"string"},"nftables_stats":{},"check_wizard_needed":{},"wizard_state":{},"repair_lapi":{},"repair_capi":{},"reset_wizard":{},"console_status":{},"console_enroll":{"key":"string","name":"string"},"console_disable":{},"service_control":{"action":"string"},"configure_acquisition":{"syslog_enabled":"string","firewall_enabled":"string","ssh_enabled":"string","http_enabled":"string","syslog_path":"string"},"acquisition_config":{},"acquisition_metrics":{},"health_check":{},"capi_metrics":{},"hub_available":{},"install_hub_item":{"item_type":"string","item_name":"string"},"remove_hub_item":{"item_type":"string","item_name":"string"}}' ;; call) case "$2" in @@ -2068,6 +2184,9 @@ case "$1" in repair_lapi) repair_lapi ;; + repair_capi) + repair_capi + ;; reset_wizard) reset_wizard ;; diff --git a/package/secubox/secubox-auth-logger/Makefile b/package/secubox/secubox-auth-logger/Makefile index 5b0c87d9..8a01d23c 100644 --- a/package/secubox/secubox-auth-logger/Makefile +++ b/package/secubox/secubox-auth-logger/Makefile @@ -36,6 +36,10 @@ define Package/secubox-auth-logger/install $(INSTALL_BIN) ./files/secubox-auth-logger.init $(1)/etc/init.d/secubox-auth-logger $(INSTALL_DIR) $(1)/etc/crowdsec/parsers/s01-parse $(INSTALL_DATA) ./files/openwrt-luci-auth.yaml $(1)/etc/crowdsec/parsers/s01-parse/ + $(INSTALL_DIR) $(1)/etc/crowdsec/scenarios + $(INSTALL_DATA) ./files/openwrt-luci-bf.yaml $(1)/etc/crowdsec/scenarios/ + $(INSTALL_DIR) $(1)/etc/crowdsec/acquis.d + $(INSTALL_DATA) ./files/secubox-auth-acquis.yaml $(1)/etc/crowdsec/acquis.d/ $(INSTALL_DIR) $(1)/etc/uci-defaults $(INSTALL_BIN) ./files/99-secubox-auth-logger $(1)/etc/uci-defaults/ endef diff --git a/package/secubox/secubox-auth-logger/files/99-secubox-auth-logger b/package/secubox/secubox-auth-logger/files/99-secubox-auth-logger index 90e72f71..c8b8af42 100644 --- a/package/secubox/secubox-auth-logger/files/99-secubox-auth-logger +++ b/package/secubox/secubox-auth-logger/files/99-secubox-auth-logger @@ -1,33 +1,24 @@ #!/bin/sh # SecuBox Auth Logger - Post-install configuration -# Enables verbose logging for Dropbear and uhttpd +# Enables verbose logging for uhttpd and configures CrowdSec # Note: Dropbear 2024.86 does NOT support -v flag # Auth monitoring relies on parsing existing syslog messages # The auth-monitor.sh script watches logread for auth failures -# Enable uhttpd syslog +# Enable uhttpd syslog for LuCI login monitoring if [ -f /etc/config/uhttpd ]; then uci set uhttpd.main.syslog='1' uci commit uhttpd /etc/init.d/uhttpd restart 2>/dev/null fi -# Create auth failures log file -touch /var/log/auth-failures.log -chmod 644 /var/log/auth-failures.log +# Create auth log file for secubox-auth-logger +touch /var/log/secubox-auth.log +chmod 644 /var/log/secubox-auth.log -# Add acquisition for CrowdSec if installed -if [ -d /etc/crowdsec/acquis.d ]; then - cat > /etc/crowdsec/acquis.d/secubox-auth.yaml << 'EOF' -# SecuBox Auth Failure Acquisition -# Reads from /var/log/messages for secubox-auth tagged messages -filenames: - - /var/log/messages -labels: - type: syslog -EOF - # Restart CrowdSec to pick up new acquisition +# Restart CrowdSec to pick up new acquisition/parser/scenario +if [ -x /etc/init.d/crowdsec ]; then /etc/init.d/crowdsec restart 2>/dev/null fi diff --git a/package/secubox/secubox-auth-logger/files/auth-monitor.sh b/package/secubox/secubox-auth-logger/files/auth-monitor.sh index f6a30caa..e67f4b22 100644 --- a/package/secubox/secubox-auth-logger/files/auth-monitor.sh +++ b/package/secubox/secubox-auth-logger/files/auth-monitor.sh @@ -1,10 +1,15 @@ #!/bin/sh # SecuBox Auth Monitor - Lightweight auth failure detection -# Monitors SSH and LuCI login failures, logs to syslog for CrowdSec +# Monitors SSH and LuCI login failures for CrowdSec # Copyright (C) 2024 CyberMind.fr +LOG_FILE="/var/log/secubox-auth.log" LOG_TAG="secubox-auth" +# Ensure log file exists +touch "$LOG_FILE" +chmod 644 "$LOG_FILE" + # Track recent IPs to avoid duplicate logging TRACK_FILE="/tmp/auth-monitor-track" touch "$TRACK_FILE" @@ -27,7 +32,12 @@ log_failure() { fi echo "${key}:${now}" >> "$TRACK_FILE" - # Log to syslog - CrowdSec will parse this + # Log to dedicated file in syslog format for CrowdSec + local ts=$(date "+%b %d %H:%M:%S") + local hostname=$(cat /proc/sys/kernel/hostname 2>/dev/null || echo "OpenWrt") + echo "$ts $hostname $LOG_TAG[$$]: authentication failure for $user from $ip via $service" >> "$LOG_FILE" + + # Also log to syslog for local visibility logger -t "$LOG_TAG" -p auth.warning "authentication failure for $user from $ip via $service" } diff --git a/package/secubox/secubox-auth-logger/files/openwrt-luci-bf.yaml b/package/secubox/secubox-auth-logger/files/openwrt-luci-bf.yaml new file mode 100644 index 00000000..bd607394 --- /dev/null +++ b/package/secubox/secubox-auth-logger/files/openwrt-luci-bf.yaml @@ -0,0 +1,18 @@ +# CrowdSec Scenario for SecuBox LuCI Brute Force Detection +# Triggers when multiple authentication failures are detected from the same IP +# Works with secubox/openwrt-luci-auth parser + +type: leaky +name: secubox/openwrt-luci-bf +description: "Detect LuCI/OpenWrt web interface brute force attempts" +filter: "evt.Meta.log_type == 'auth_failure'" +leakspeed: "10s" +capacity: 5 +groupby: evt.Meta.source_ip +blackhole: 1m +reprocess: true +labels: + service: http + remediation: true + type: bruteforce + confidence: 3 diff --git a/package/secubox/secubox-auth-logger/files/secubox-auth-acquis.yaml b/package/secubox/secubox-auth-logger/files/secubox-auth-acquis.yaml new file mode 100644 index 00000000..29458611 --- /dev/null +++ b/package/secubox/secubox-auth-logger/files/secubox-auth-acquis.yaml @@ -0,0 +1,7 @@ +# SecuBox Auth Logger Acquisition +# Reads authentication failure logs from secubox-auth-logger +# Used by secubox/openwrt-luci-auth parser and secubox/openwrt-luci-bf scenario +filenames: + - /var/log/secubox-auth.log +labels: + type: syslog