feat(secubox-auth-logger): Add auth failure monitoring for CrowdSec

- Create secubox-auth-logger package to monitor SSH/LuCI auth failures
- auth-monitor.sh watches logread for failed password attempts
- Supports OpenSSH, Dropbear, and uhttpd/LuCI authentication
- Logs failures to syslog with secubox-auth tag for CrowdSec parsing
- Fix wizard.js syntax error with computed property names
- Remove broken Dropbear verbose config (2024.86 doesn't support -v)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-01-13 09:35:20 +01:00
parent f917b5412c
commit 3b84c8a047
7 changed files with 248 additions and 15 deletions

View File

@ -644,10 +644,10 @@ return view.extend({
];
var renderCheckboxItem = function(item, type) {
return E('div', {
var attrs = {
'class': 'collection-item',
'data-' + type: item.name,
'data-type': type,
'data-name': item.name,
'data-checked': item.preselected ? '1' : '0',
'style': 'display: flex; align-items: center; cursor: pointer;',
'click': function(ev) {
@ -661,7 +661,8 @@ return view.extend({
checkbox.style.color = newState ? '#22c55e' : '#94a3b8';
}
}
}, [
};
return E('div', attrs, [
E('span', {
'class': 'checkbox-indicator',
'style': 'display: inline-block; font-size: 28px; margin-right: 16px; user-select: none; color: ' + (item.preselected ? '#22c55e' : '#94a3b8') + '; line-height: 1; min-width: 28px;'
@ -1143,16 +1144,16 @@ return view.extend({
handleInstallCollections: function() {
// Read collections from data-checked attributes
var collectionItems = document.querySelectorAll('.collection-item[data-collection]');
var collectionItems = document.querySelectorAll('.collection-item[data-type="collection"]');
var selectedCollections = Array.from(collectionItems)
.filter(function(item) { return item.getAttribute('data-checked') === '1'; })
.map(function(item) { return item.getAttribute('data-collection'); });
.map(function(item) { return item.getAttribute('data-name'); });
// Read parsers from data-checked attributes
var parserItems = document.querySelectorAll('.collection-item[data-parser]');
var parserItems = document.querySelectorAll('.collection-item[data-type="parser"]');
var selectedParsers = Array.from(parserItems)
.filter(function(item) { return item.getAttribute('data-checked') === '1'; })
.map(function(item) { return item.getAttribute('data-parser'); });
.map(function(item) { return item.getAttribute('data-name'); });
console.log('[Wizard] Selected collections:', selectedCollections);
console.log('[Wizard] Selected parsers:', selectedParsers);

View File

@ -1364,15 +1364,11 @@ configure_acquisition() {
uci commit crowdsec
steps_done="${steps_done}Updated UCI settings; "
# Step 3: Enable verbose logging for services that need it
# Dropbear SSH needs verbose mode to log authentication failures
# Step 3: Note on Dropbear SSH logging
# Dropbear 2024.86 does NOT support -v flag or verbose UCI option
# Auth failures are detected via auth-monitor.sh parsing syslog messages
if [ "$ssh_enabled" = "1" ]; then
if uci -q get dropbear.@dropbear[0] >/dev/null 2>&1; then
uci set dropbear.@dropbear[0].verbose='1'
uci commit dropbear
/etc/init.d/dropbear restart >/dev/null 2>&1
steps_done="${steps_done}Enabled Dropbear verbose logging; "
fi
steps_done="${steps_done}SSH detection enabled via syslog monitoring; "
fi
# Enable uhttpd syslog for HTTP auth logging

View File

@ -0,0 +1,52 @@
# Copyright (C) 2024 CyberMind.fr
# Licensed under Apache-2.0
include $(TOPDIR)/rules.mk
PKG_NAME:=secubox-auth-logger
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_ARCH:=all
PKG_LICENSE:=Apache-2.0
PKG_MAINTAINER:=CyberMind <contact@cybermind.fr>
include $(INCLUDE_DIR)/package.mk
define Package/secubox-auth-logger
SECTION:=secubox
CATEGORY:=SecuBox
TITLE:=Authentication Failure Logger for CrowdSec
DEPENDS:=+rpcd +uhttpd
PKGARCH:=all
endef
define Package/secubox-auth-logger/description
Logs authentication failures from LuCI/rpcd and Dropbear SSH
for CrowdSec detection. Patches rpcd to emit auth failure logs
to syslog in a format CrowdSec can parse.
endef
define Build/Compile
endef
define Package/secubox-auth-logger/install
$(INSTALL_DIR) $(1)/usr/lib/secubox
$(INSTALL_BIN) ./files/auth-monitor.sh $(1)/usr/lib/secubox/
$(INSTALL_DIR) $(1)/etc/init.d
$(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/uci-defaults
$(INSTALL_BIN) ./files/99-secubox-auth-logger $(1)/etc/uci-defaults/
endef
define Package/secubox-auth-logger/postinst
#!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] || {
/etc/init.d/secubox-auth-logger enable
/etc/init.d/secubox-auth-logger start
}
exit 0
endef
$(eval $(call BuildPackage,secubox-auth-logger))

View File

@ -0,0 +1,34 @@
#!/bin/sh
# SecuBox Auth Logger - Post-install configuration
# Enables verbose logging for Dropbear and uhttpd
# 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
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
# 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
/etc/init.d/crowdsec restart 2>/dev/null
fi
exit 0

View File

@ -0,0 +1,107 @@
#!/bin/sh
# SecuBox Auth Monitor - Lightweight auth failure detection
# Monitors SSH and LuCI login failures, logs to syslog for CrowdSec
# Copyright (C) 2024 CyberMind.fr
LOG_TAG="secubox-auth"
# Track recent IPs to avoid duplicate logging
TRACK_FILE="/tmp/auth-monitor-track"
touch "$TRACK_FILE"
log_failure() {
local service="$1"
local ip="$2"
local user="${3:-root}"
# Avoid duplicate logs within 60 seconds
local key="${service}:${ip}"
local now=$(date +%s)
if grep -q "^${key}:" "$TRACK_FILE" 2>/dev/null; then
local last=$(grep "^${key}:" "$TRACK_FILE" | cut -d: -f3)
if [ $((now - last)) -lt 60 ]; then
return
fi
sed -i "/^${key}:/d" "$TRACK_FILE"
fi
echo "${key}:${now}" >> "$TRACK_FILE"
# Log to syslog - CrowdSec will parse this
logger -t "$LOG_TAG" -p auth.warning "authentication failure for $user from $ip via $service"
}
# Monitor logread for auth failures
monitor_logs() {
logread -f 2>/dev/null | while read line; do
# OpenSSH failures
# Format: sshd[xxx]: Failed password for root from 1.2.3.4 port xxx
if echo "$line" | grep -qi "sshd.*failed.*password"; then
ip=$(echo "$line" | grep -oE 'from [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | awk '{print $2}')
user=$(echo "$line" | grep -oE 'for [^ ]+' | awk '{print $2}')
[ -n "$ip" ] && log_failure "ssh" "$ip" "$user"
fi
# OpenSSH invalid user
# Format: sshd[xxx]: Invalid user xxx from 1.2.3.4
if echo "$line" | grep -qi "sshd.*invalid.user"; then
ip=$(echo "$line" | grep -oE 'from [0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | awk '{print $2}')
user=$(echo "$line" | grep -oE 'user [^ ]+' | awk '{print $2}')
[ -n "$ip" ] && log_failure "ssh" "$ip" "${user:-unknown}"
fi
# Dropbear failures (if ever enabled)
# Format: dropbear[xxx]: Bad password attempt for 'root' from x.x.x.x:port
if echo "$line" | grep -qi "dropbear.*bad.password"; then
ip=$(echo "$line" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
user=$(echo "$line" | grep -oE "for '[^']+'" | tr -d "'" | awk '{print $2}')
[ -n "$ip" ] && log_failure "ssh" "$ip" "$user"
fi
# uhttpd/LuCI - Look for failed POST to login
# When uhttpd syslog is enabled, failed logins redirect with 302/403
if echo "$line" | grep -qi "uhttpd.*POST.*/cgi-bin/luci"; then
ip=$(echo "$line" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
# Check if this is followed by a failure indicator
if echo "$line" | grep -qE "403|401"; then
[ -n "$ip" ] && log_failure "luci" "$ip"
fi
fi
# rpcd session errors
if echo "$line" | grep -qi "rpcd.*access.denied\|ubus.*error"; then
ip=$(echo "$line" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)
[ -n "$ip" ] && log_failure "luci" "$ip"
fi
done
}
# Cleanup old tracking entries (older than 5 minutes)
cleanup_tracking() {
while true; do
sleep 300
local now=$(date +%s)
local tmp=$(mktemp)
while read line; do
local ts=$(echo "$line" | cut -d: -f3)
if [ $((now - ts)) -lt 300 ]; then
echo "$line"
fi
done < "$TRACK_FILE" > "$tmp"
mv "$tmp" "$TRACK_FILE"
done
}
case "$1" in
start)
cleanup_tracking &
monitor_logs
;;
*)
echo "Usage: $0 start"
echo "Monitors auth failures and logs to syslog for CrowdSec"
exit 1
;;
esac

View File

@ -0,0 +1,20 @@
# CrowdSec Parser for SecuBox Auth Logger
# Parses authentication failures from LuCI/uhttpd and Dropbear
# Format: secubox-auth: Authentication failure for <user> from <ip> via <service>
name: secubox/openwrt-luci-auth
description: "Parse SecuBox auth failure logs for LuCI and SSH"
filter: "evt.Parsed.program == 'secubox-auth'"
onsuccess: next_stage
nodes:
- grok:
pattern: "Authentication failure for %{USERNAME:user} from %{IP:source_ip} via %{WORD:service}"
apply_on: message
statics:
- meta: log_type
value: auth_failure
- meta: service
expression: evt.Parsed.service
- meta: source_ip
expression: evt.Parsed.source_ip

View File

@ -0,0 +1,23 @@
#!/bin/sh /etc/rc.common
# SecuBox Authentication Logger
# Monitors SSH and LuCI auth failures for CrowdSec
# Copyright (C) 2024 CyberMind.fr
START=99
STOP=10
USE_PROCD=1
PROG=/usr/lib/secubox/auth-monitor.sh
start_service() {
procd_open_instance
procd_set_param command "$PROG" start
procd_set_param respawn
procd_set_param stdout 0
procd_set_param stderr 1
procd_close_instance
}
service_triggers() {
procd_add_reload_trigger "secubox-auth-logger"
}